Добавил:
Преподаватель Колледжа информационных технологий Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Лабораторные работы / Методические указания к ЛР по ОАИП (09.02.07)

.pdf
Скачиваний:
60
Добавлен:
08.05.2022
Размер:
3.68 Mб
Скачать

Рисунок 15.5 – Добавление ссылки на библиотеку в основной проект

Далее нам откроется окно для добавления библиотек. В этом окне выберем пункт Проекты, который позволяет увидеть все библиотеки классов из проектов текущего решения, поставим отметку рядом с нашей библиотекой и нажмем на кнопку OK:

Рисунок 15.6

Если наша библиотека вдруг представляет файл dll, который не связан ни с каким проектом в нашем решении, то с помощью кнопки Обзор мы можем найти местоположение файла dll и также его подключить.

251

После успешного подключения библиотеки в главном проекте изменим

класс формы регистрации FormReg, чтобы он использовал класс User из библиотеки классов:

Листинг 15.2

1

using MyLib;

2

using System;

3

using System.IO;

4

using System.Net.Sockets;

5

using System.Windows.Forms;

6

namespace LAB_5_OAIP

7

{

8

public partial class FormReg : Form

9

{

10

11

}

12

}

В строке 1 происходит подключение пространства имен MyLib из библиотеки классов.

Для дальнейшей работы информационной системы с клиент-серверной архитектурой требуется в библиотеку классов приложения MyLib добавить следующие классы:

1. Класс Thesis, описывающий сущность «Дипломный проект» со свойствами:

«Тема дипломного проекта» (Name);

«Аннотация к дипломному проекту» (Annotation);

«Преподаватель, добавивший тему дипломного проекта»

(Professor).

Листинг 15.3 – Класс «Дипломный проект»

1namespace MyLib

2{

3[Serializable]

4public partial class Thesis

5{

6public int Id { get; set; }

7public string Name { get; set; }

252

8

public string Annotation

{ get; set; }

9

public virtual Professor

Professor { get; set; }

10

}

 

11

}

 

2. Класс Student, описывающий сущность «Студент» со свойствами:

«ФИО студента» (Name);

«Номер группа» (NumberGroup);

«Дополнительная информация о студенте» (PersonalData);

«Фотография студента» (Photo);

«Специальность» (Specialty);

«Учетная запись студента» (User);

«Преподаватель, являющийся руководителем дипломного проекта студента» (Professor).

Листинг 15.4 – Класс «Студент»

1

namespace MyLib

2

{

3

[Serializable]

4

public partial class Student

5

{

6

public int Id { get; set; }

7

public string Name { get; set; }

8

public long NumberGroup { get; set; }

9

public string PersonalData { get; set; }

10

public byte[] Photo { get; set; }

11

public string Specialty { get; set; }

12

public virtual User User { get; set; }

13

public virtual Professor Professor { get; set; }

14}

15}

253

3. Класс Professor, описывающий сущность «Преподаватель» со

свойствами:

«ФИО преподавателя» (Name);

«Должность» (Position);

«Дополнительная информация о преподавателе»

(PersonalData);

«Фотография преподавателя» (Photo);

«Учетная запись преподавателя» (User);

«Коллекция тем дипломных проектов, предлагаемая преподавателем» (Thesis)

«Коллекция студентов, закрепленная за преподавателем»

(Student).

 

Листинг 15.5 – Класс «Преподаватель»

 

 

 

1

namespace MyLib

 

2

{

 

3

[Serializable]

 

4

public partial class Professor

 

5

{

 

6

public int Id { get; set; }

 

7

public string Name { get; set; }

 

8

public string Position { get; set; }

 

9

public string PersonalData { get; set; }

 

10

public byte[] Photo { get; set; }

 

11

public virtual User User { get; set; }

 

12

public virtual ICollection<Thesis> Thesis { get; set; }

 

13

public virtual ICollection<Student> Student { get; set; }

 

14

public Professor()

 

15

{

 

16

this.Student = new List<Student>();

 

17

this.Thesis = new List<Thesis>();

 

18

}

 

19

}

 

20

}

 

 

 

 

254

4. Класс CustomBinder, применяемый для десериализации объектов в другом проекте.

Класс BinaryFormatter, который используется для сериализации и десериализации в файл, сохраняет полное имя типа вместе с полным именем сборки (full qualified name). Соответственно если при десериализации форматтер не обнаруживает эту сборку, то генерируется исключение

SerializationException. Для того, чтобы десериализовать данные во втором проекте, необходимо подключить именно ту сборку, типы которой сериализовались ранее в первом проекте. Если таковой возможности нет, и вы сами гарантируете наличие аналогичных определений типов сериализованных объектов в другом проекте, то можно создать биндер, который переопределит имя сборки и типа во время десериализации и передаст нужную информацию форматтеру. Для этого достаточно определить наследника абстрактного класса System.Runtime.Serialization.SerializationBinder:

 

Листинг 15.6 – Класс CustomBinder

 

 

 

1

namespace MyLib

 

2

{

 

3

class CustomBinder : SerializationBinder

 

4

{

 

5

public override Type BindToType

 

(string assemblyName, string typeName)

 

 

 

6

{

 

7

Assembly currentasm = Assembly.GetExecutingAssembly();

 

8

return Type.GetType($"{currentasm.GetName().

 

Name}.{typeName.Split('.')[1]}");

 

 

 

9

}

 

10

}

 

11

}

 

 

Метод BindToType при переопределении в производном классе

управляет привязкой сериализованного объекта к типу. Параметр assemblyName – это имя сборки сериализованного объекта, typename – имя типа сериализованного объекта. Данный метод возвращает тип объекта,

экземпляр которого создается модулем форматирования.

255

5. Класс EntityModelContainer, представляющий контекст данных,

используемый для взаимодействия с базой данных.

 

Листинг 15.7 – Класс контекста данных

 

 

 

1

namespace MyLib

 

2

{

 

3

public partial class EntityModelContainer : DbContext

 

4

{

 

5

public EntityModelContainer() :

 

base("name=EntityModelContainer")

 

 

 

6

{}

 

7

public virtual DbSet<User> UserSet { get; set; }

 

8

public virtual DbSet<Student> StudentSet { get; set;

 

}

 

 

 

9

public virtual DbSet<Professor> ProfessorSet { get;

 

set; }

 

 

 

10

public virtual DbSet<Thesis> ThesisSet { get; set; }

 

11

}

 

12

}

 

 

6. Класс SerializeAndDeserialize, хранящий методы для

сериализации (Serialize) и десериализации (Deserialize) объектов.

 

Листинг 15.8 – Класс сериализации и десериализации

 

 

 

1

namespace MyLib

 

2

{

 

3

public class SerializeAndDeserialize

 

4

{

 

5

public static Message Serialize(object

 

anySerializableObject)

 

 

 

6

{

 

7

IFormatter formatter = new BinaryFormatter();

 

8

formatter.Binder = new CustomBinder();

 

9

using (var memoryStream = new MemoryStream())

 

10

{

 

11

formatter.Serialize(memoryStream,

 

anySerializableObject);

 

12

return new Message { Data = memoryStream.ToArray() };

 

13

}

 

14

}

 

15

public static object Deserialize(Message message)

 

16

{

 

17

IFormatter formatter = new BinaryFormatter();

 

256

18

formatter.Binder = new CustomBinder();

 

 

19

using

(var

memoryStream

=

new

MemoryStream(message.Data))

 

 

20

{

 

 

 

 

21

return formatter.Deserialize(memoryStream);

 

22

}

 

 

 

 

23

}

 

 

 

 

24

}

 

 

 

 

25

}

 

 

 

 

Для корректной сериализации и десериализации в строке 8 и 18 свойству объекта formatter присваивается экземпляр биндера CustomBinder,

созданного классе 4.

7. Класс Message, представляющий в качестве объекта пакет данных,

передаваемый посредством TCP-протокола через компьютерную сеть от клиента к серверу и наоборот, от сервера к клиенту.

Листинг 15.9 – Класс пакетов данных

1

namespace MyLib

2

{

3

[Serializable]

4

public class Message

5

{

6

public byte[] Data { get; set; }

7

}

8

[Serializable]

9

public class ComplexMessage

10

{

11

public Message First { get; set; }

12

public Message Second { get; set; }

13

public int NumberStatus { get; set; }

14}

15}

Класс Message представляет собой пакет с данными об одном сериализованном объекте, а класс ComplexMessage – о двух сериализованных объектах (First и Second). Сериализованные данные об объекте хранятся в массиве байтов Data.

Свойство NumberStatus позволяет при отправке пакета от одной машины к другой отследить тип запроса, который необходимо выполнить

257

после приема данных. Например, если значение свойства равно 0, то выполняется запрос на регистрации, а если равно 1, то выполняется запрос на авторизацию пользователя и т.д.

3. Серверная часть приложения

Рассмотрим реализацию серверной части приложения.

Для начала создаем отдельный проект (в нашем случае LR8_SERVER).

В новый проект добавляем ссылку на раннее созданную библиотеку классов

MyLib.

Сервер будет принимать от клиента пакеты данных, которые будут содержать сериализованные объекты и тип запроса. После приема данных необходимо организовать взаимодействие с базой данных – или для добавления, или для извлечения данных. Для этого необходимо создать базу данной с аналогичной структурой, как она была реализована в десктопной версии приложения (в лабораторной работе 14).

Добавляем в проект следующие классы:

1. Класс ServerObject – класс, описывающий свойства и метода,

требуемые для обеспечения работоспособности TCP-сервера, который будет осуществлять прием и отправку данных посредством TCP-протокола через компьютерную сеть.

Реализация класса сервера представлена в листинге 15.10.

 

 

 

 

Листинг 15.10 – Класс сервера

 

 

 

1

public class ServerObject

 

2

{

 

 

 

3

static public TcpListener

tcpListener; // сервер для

прослушивания

 

 

 

 

 

4

List<ClientObject> clients = new List<ClientObject>();

5

ClientObject clientObject = null;

6

protected

internal

void

AddConnection(ClientObject

clientObject)

 

 

 

 

 

7

{

 

 

 

8

clients.Add(clientObject);

 

9

}

 

 

 

10

protected internal void Listen()

11

{

 

 

 

258

12

tcpListener = new TcpListener(IPAddress.Any, 8888);

13

tcpListener.Start();

 

 

 

14

while (true)

 

 

 

 

15

{

 

 

 

 

16

TcpClient tcpClient = tcpListener.AcceptTcpClient();

17

clientObject = new ClientObject(tcpClient, this);

18

Thread

clientThread

=

new

Thread(new

ThreadStart(clientObject.Process));

 

 

19

clientThread.Start();

 

 

 

20

}

 

 

 

 

21

}

 

 

 

 

22

}

 

 

 

 

Все подключенные клиенты будут храниться в коллекции clients. С

помощью метода AddConnection мы можем добавлять объекты в эту коллекцию.

Основной метод - Listen(), в котором будет осуществляться прослушивание всех входящих подключений. При получении подключения будет запускаться новый поток, в котором будет выполняться метод Process

объекта ClientObject.

2. Класс ClientObject - класс, описывающий свойства и метода,

требуемые для обеспечения работоспособности TCP-клиента, который будет осуществлять отправку данных посредством TCP-протокола через компьютерную сеть и прием данных, отправленных сервером.

Реализация класса клиента представлена в листинге 15.11.

259

Листинг 15.11 – Класс клиента

 

1

public class ClientObject

 

 

2

{

 

 

3

protected internal string Id { get; private set; }

Идентификатор подключаемого к серверу

 

клиента

 

 

 

 

4

protected internal NetworkStream Stream { get;

Поток, используемый для взаимодействия с

 

private set; }

клиентом

 

 

 

5

TcpClient client;

Объект TCP-клиента

 

6

ServerObject server;

Объект сервера

 

7

MyLib.Message m, m1, m2;

Экземпляры класса Message из библиотеки

 

8

MyLib.ComplexMessage cm = new ComplexMessage();

MyLib, созданной на предыдущем этапе

 

9

public ClientObject(TcpClient tcpClient,

Конструктор класса клиента

 

ServerObject serverObject)

 

 

 

 

 

10

{

 

 

 

 

Инициализация свойства Id (метод NewGuid

 

11

Id = Guid.NewGuid().ToString();

генерирует случайный уникальный

 

 

 

идентификатор)

 

12

client = tcpClient;

Инициализация свойства tcpClient

 

13

server = serverObject;

Инициализация свойства serverObject

 

14

serverObject.AddConnection(this);

Добавление в коллекцию подключений класса

 

ServerObject нового подключения

 

 

 

 

15

Stream = client.GetStream();

Связывание потока Stream с TCP-клиентом

 

client

 

 

 

 

16

}

 

 

17

public void Process()

Метод, реализующий протокол обмена

 

сообщениями с клиентом

 

 

 

 

18

{

 

260

Соседние файлы в папке Лабораторные работы