Windows Communication Foundation

Работа с подтипом приложений, доступных для создания в Visual Studio 2010 - Приложение службы Windows Communication Foundation. Создание и изменение приложения WCF: приложение-клиент для WCF-службы. Разработка Windows Forms: сервер и клиент чата на WCF.

Рубрика Программирование, компьютеры и кибернетика
Вид лабораторная работа
Язык русский
Дата добавления 11.04.2017
Размер файла 2,2 M

Отправить свою хорошую работу в базу знаний просто. Используйте форму, расположенную ниже

Студенты, аспиранты, молодые ученые, использующие базу знаний в своей учебе и работе, будут вам очень благодарны.

Размещено на http://www.allbest.ru/

Лабораторная работа

на тему: Windows Communication Foundation

Содержание

1. Вводная часть

2. Создание приложения WCF

3. Модификация приложения WCF: приложение-клиент для WCF-службы

4. Создание приложения Windows Forms: сервер чата на WCF

5. Создание приложения Windows Forms: клиент чата на WCF

6. Завершающая часть

7. О приложении к Лабораторной работе № 16

1. Вводная часть

В этой работе будет рассмотрена работа с подтипом приложений доступных для создания в Visual Studio 2010, а именно Приложение службы WCF. Что такое WCF?

Windows Communication Foundation (WCF) -- программный «фреймворк», используемый для обмена данными между приложениями входящими в состав .NET Framework. До своего выпуска в декабре 2006 года в составе .NET Framework 3.0, WCF был известен под кодовым именем Indigo.

WCF делает возможным построение безопасных и надёжных транзакционных систем через упрощённую унифицированную программную модель межплатформенного взаимодействия. Или проще: приложений для удалённого межплатформенного обмена данными. Комбинируя функциональность существующих технологий .NET по разработке распределённых приложений (ASP.NET XML Web Services -- ASMX, WSE 3.0, .NET Remoting, .NET Enterprise Services и System.Messaging), WCF предоставляет единую инфраструктуру разработки, при умелом применении повышающую производительность и снижающую затраты на создание безопасных, надёжных и транзакционных Web-служб. Заложенные в неё принципы интероперабельности (способность к взаимодействию) позволяют организовать работу с другими платформами, для чего используются технологии взаимодействия платформ, например WSIT (Web Services Interoperability Technology) разрабатываемые на базе открытого исходного кода.

«Хостинг» (расположение) приложений WCF:

Класс службы WCF не может существовать самостоятельно. Каждая служба WCF должна находиться под управлением некоторого процесса Windows, называемого хостовым (серверным) процессом. Существуют несколько вариантов хостинга:

· Автохостинг (то есть хост-процессом является, к примеру, консольное приложение или графическое приложение Windows Forms)

· Хостинг в одной из служб Windows.

· Хостинг с использованием IIS (Internet Information Server) или WAS (Windows Activation Services).

В данной работе будет рассмотрен простейший случай работы с WCF, а также будет написан клиент и сервер для реализации возможностей чата на основе WCF (оба приложения будут в виде Windows Forms).

2. Создание приложения WCF

Запускаем Visual Studio 2010, откроется Начальная страница:

Для начала, надо создать проект, для этого выполним последовательно: Файл -> Создать -> Проект… (также можно просто нажать сочетание клавиш Ctrl+Shift+N или пункт «Создать проект…» на Начальной странице):

Рис. 2.1 Создание нового проекта

Выберем слева в пункте Установленные шаблоны язык Visual C#, далее найдём в списке Приложение службы WCF. Также здесь можно выбрать какой использовать «фреймворк» (набора компонентов для написания программ). В нашем случае выберем .NET Framework 4.

Рис. 2.2 Окно создания нового проекта

В поле Имя вводим LWP16WCF -- это название программы (выбрано по названию лабораторного практикума, номеру и названию работы). В поле Расположение указана конечная директория, где будет находиться весь проект. Выберем расположение удобное для быстрого поиска. В поле Имя решения вводится либо название программы «по умолчанию» из поля Имя автоматически, либо можно ввести своё собственное. Под этим именем будет создана конечная папка проекта (если Имя и Имя решения разные).

Рис. 2.3 Вводим данные нового проекта приложения Windows Forms

После нажатия клавиши ОК мы увидим сформированный проект и исходный код приложения Windows Forms (не пустого изначально).

Рис. 2.4 Обозреватель решений: состав проекта приложения Windows Forms сформированного средой разработки

Теперь, можно откомпилировать созданную программу, нажав клавишу F5 (Отладка -> Начать отладку или нажав на иконку . Тем самым мы запускаем приложение в режиме отладки (и производим компиляцию debug-версии программы) (Debug выбрано изначально).

В данном типе проекта может быть два возможных вывода результата после компиляции. Если в обозревателе решений выбран любой файл кроме Service1.svc, будет открыто окно Internet Explorer с содержимым каталога проекта

Если выбрать вышеуказанный файл, то должен открыться Тестовый клиент WCF который служит для проверки работоспособности сервиса и выполняет функции простого клиента.

Тестовый клиент WCF (WcfTestClient.exe) представляет собой средство с графическим интерфейсом пользователя, позволяющее вводить тестовые параметры, отправлять их в службу и просматривать ответную реакцию службы. При совместном использовании с узлом службы WCF это обеспечивает удобную практику тестирования служб.

Тестовый клиент WCF (WcfTestClient.exe) находится в следующей папке (для Visual Studio 2010): C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\

Собственно тестирование происходит так: дважды нажмём на GetData(), затем в поле Запрос -> строка value введём любое число и нажмём Вызвать. В окне Предупреждение системы безопасности жмём ОК и наслаждается ответом службы в поле Ответ -> return:

Здесь также можно проверить работу и второго доступного параметра (контейнера с двумя разными типами переменных): GetDataUsingDataContract().

ПРИМЕЧАНИЕ № 1: Если по каким-либо причинам произошли ошибки при компиляции, можно проверить наличие всех необходимых компонентов. Если на ПК Visual Studio 2010 установлен правильно и со всеми необходимыми компонентами, добавлять ничего не нужно и ошибок не должно возникать. Если же были установлены не все компоненты (например, нет IIS), то можно воспользоваться специальным установщиком (ищем его в на одном из верхним меню Visual Studio 2010): Установщик веб-платформы 3.0:

После запуска установщика, выбираем неотступающие компоненты (при наличии подключения к сети Интернет). Выбор компонента происходит нажатием кнопки Добавить:

3. Модификация приложения WCF: приложение-клиент для WCF-службы

Для начала изменим имя сервиса. Выделим файл Service1.svc в обозревателе решений и перейдём к его коду (правая кнопка мыши -> Перейти к коду либо F7). Код файла содержит классы для работы с параметрами сервиса, теми самыми, что были доступны в клиенте WCF. Найдём в коде строку:

// ПРИМЕЧАНИЕ. Команду "Переименовать" в меню "Рефакторинг" можно использовать для одновременного изменения имени класса "Service1" в коде, SVC-файле и файле конфигурации.

public class Service1 : IService1

{

Выделим имя класса (слово) Service1 и далее ПКМ -> во всплывающем меню: Рефакторинг -> Переименовать (или F2):

Рис. 3.1 Переименование сервиса

Вводим в открывшемся окне имя LWP16Service, жмём ОК, в следующем окне Применить:

Рис. 3.2 Переименование сервиса: Переименовать

Рис. 3.2 Переименование сервиса: Просмотр изменений - Переименование

То же самое проделаем для имени интерфейса (IService1). Введём новое имя ILWP16Service. И переименуем имя файла сервиса в LWP16Service:

Слегка изменим сервис. Откроем код класса интерфейса сервиса (файл ILWP16Service.cs) и найдём:

[OperationContract]

string GetData(int value);

Изменим так:

[OperationContract]

string GetInt(int value);

[OperationContract]

string GetString(string value);

Обратим внимание на атрибуты [OperationContract] в приведенном выше коде. Эти атрибуты обязательны для любого метода, предоставляемого службой. Параметры которым обладает «контракт»:

IsInitiating - если true тогда связь с сервисом и сессия начинается, создается объект реализации на сервисе и запускается его конструктор. IsOneWay - если true данный метод ничего не возвращает и только в одну сторону. IsTerminating - значение true этого параметра приводит к тому, что по окончанию его обработки на сервисе связь с клиентом прерывается и сессия закрывается, т.е. последующие обращения к сервису приведут к ошибкам. Выглядит это так:

[OperationContract(IsInitiating = true, IsOneWay = false, IsTerminating = false)]

Для [ServiceContract]:

[ServiceContract(SessionMode = SessionMode.Required)]

Параметр SessionMode отвечатет за то, разрешены, запрещены или требуются ли сеансы.

В файле LWP16Service.svc.cs найдём:

public class LWP16Service : ILWP16Service

{

public string GetData(int value)

{

return string.Format("You entered: {0}", value);

}

Заменим на:

public string GetInt(int value)

{

return string.Format("Вы ввели число: {0}", value);

}

public string GetString(string value)

{

return string.Format("Вы ввели строку: {0}", value);

}

Сервис можно компилировать по конфигурации Release (Построение -> Построить решение, либо F6).

Осталось добавить клиентское приложение. Интегрируем такое приложение непосредственно в текущее решение. Для этого выполним следующие действия: Файл -> Создать -> Проект. В окне открывшемся окне «Создать проект», в поле Решение, выберем: Добавить в решение. В качестве проекта выберем Приложение Windows Forms. Имя будет: LWP16WCFClient. Жмём ОК. Получим следующее:

Рис. 3.3 Обозреватель решений: содержимое решения, состоящего из двух проектов windows communication foundation

Теперь интегрируем службу LWP16Service.svc в форму. Для этого в обозревателе решений выделим имя проекта (LWP16WCFClient), далее жмём правую кнопку мыши -> Добавить ссылку на службу...:

В открывшемся окне жмём на Найти, далее Службы решения. Наша служба автоматически добавится в список. В поле Пространство имён вводим: LWP16ServiceReference:

Рис. 3.4 Добавить ссылку на службу: добавление службы из нашего решения в другой проект этого же решения

Жмём ОК. И откроем конструктор формы клиентского проекта2.

ПРИМЕЧАНИЕ № 2: Для перехода на визуальное представление формы, необходимо двойным нажатием в обозревателе решений нажать на значок формы () или выбрать вкладку на панели вкладок с именем <имя формы>.cs [Конструктор].

На форме клиентского проекта Form1 расставим два текстовых поля, под ними одну кнопку и ещё ниже два статических поля Label. Все имена и свойства добавленных элементов оставим без изменений. Задаём следующие параметры самой формы на панели Свойства:

(Name)

изменим с Form1.cs3 на LWP16Main

^ Поменяем внутреннее имя формы

Text

изменим с Form1 на Клиент для службы WCF (C#)

^ Поменяем заголовок формы (то, что отображается в шапке приложения слева).

MaximizeBox

изменим с True на False

^ Уберём кнопку Развернуть.

Icon

изменим изображение (иконку) приложения

^ Необходим файл значка *.ico.

FormBorderStyle

> изменим с Sizable на FixedDialog

^ Сделаем окно «неизменяем» по размерам.

Size

изменим со значений 290; 290 на 350; 200

^ Поменяем размер формы.

ПРИМЕЧАНИЕ № 3: Для того, чтобы поменять имя файла нашей формы, необходимо выполнить следующее: выделить в обозревателе решений значок формы () и нажать правую кнопку мыши, затем выбрать Переименовать. Ввести необходимое новое имя СОХРАНЯЯ расширение *.cs. После смены имени, автоматически поменяются имена проассоциированных непосредственно с формой файлов:

Форма будет выглядеть примерно так:

Рис. 3.5 Модифицированная форма приложения и расстановка необходимых элементов управления

Кнопку и текстовые поля TextBox растянем до границ формы.

Дважды щёлкнем по кнопке на форме, тем самым создав событие Click. Впишем код:

private void button1_Click(object sender, EventArgs e)

{

if (textBox1.Text == "Ведите число") { textBox1.Text = "0"; }

LWP16ServiceReference.LWP16ServiceClient client = new LWP16ServiceReference.LWP16ServiceClient(); // Открываем сеанс связи со службой

returnString1 = client.GetInt(Convert.ToInt32(textBox1.Text));

label1.Text = returnString1;

returnString2 = client.GetString(textBox2.Text);

label2.Text = returnString2;

client.Close(); // Закрываем сеанс связи

}

В этом же файле найдём:

public partial class LWP16Main : Form

{

Вставим после:

String returnString1;

String returnString2;

Код метода LWP16Main() изменим так:

public LWP16Main()

{

InitializeComponent();

label1.Text = "";

label2.Text = "";

textBox1.Text = "Ведите число";

textBox2.Text = "Введите строку";

button1.Text = "Связать со службой";

}

И для первого (верхнего) TextBox объявим событие KeyPress, в котором запретим вводить все символы кроме цифр. Если этого не сделать, поймаем исключение. Служба на это поле будет передавать данные из метода GetInt(), который в качестве параметра принимает только int. Можно обойтись и без события для TextBox, тогда исключение можно обработать try-catch блоком. Код события:

private void textBox1_KeyPress(object sender, KeyPressEventArgs e)

{

// Введённые символы должны быть только цифрами, иначе ввода не будет (символ не введётся)

if (!Char.IsDigit(e.KeyChar))

{

e.Handled = true;

}

}

Сделаем нашу форму автоматически запускаемой при компиляции. Откроем свойства решения () и в поле Запускаемый проект выберем LWP16WCFClient:

Компилируем приложение (Release) и запускаем. Откроется форма клиента. Вводим в первое поле цифры, во второе какую-нибудь строку и жмём на кнопку Связаться со службой. Получаем ответ в виде двух статических строк внизу формы:

Рис. 3.6 Модифицированное приложение Windows Forms: работа клиента для службы WCF

4. Создание приложения Windows Forms: сервер чата на WCF

Чат. Наиболее простое и часто встречающее приложение на WCF для демонстрации возможности технологии удалённого «общения». Так как WCF требует нечто что должно выполнять функции «хоста», то самым простым решением станет создание приложение-сервера, которое будет запускать и останавливать сервис для работы множества (2 и более) приложений-клиентов. Каждое приложение-клиент будет реализовывать удалённый клиент чата -- попросту одного пользователя в чате. Средой для связи (сервер-клиент) выступит localhost (локальная машина), но можно использовать и адрес удалённого сервера, например в локальной сети. Ключевым адресом является адрес сервера.

Теперь о нашем приложении:

Приложение будет простой формой с двумя кнопками, одним GroupBox и одним статическим текстовым полем. Одна кнопка будет запускать сервер, вторая останавливать. В Label будет заноситься результат выполнения запуска или остановки.

Открываем снова Visual Studio и создаём пустое решение (Файл -> Создать -> Новый проект). Выбираем Другие типы проектов -> Решение Visual Studio -> Новое решение. Имя выбираем как LWP16:

Рис. 4.1 Вводим данные нового пустого решения

Жмём ОК. Было добавлено решение, но пока без проектов. Создаём новый проект в текущем решении. Для этого выполним следующие действия: Файл -> Создать -> Проект. В окне открывшемся окне «Создать проект», в поле Решение, выберем: Добавить в решение. В качестве проекта выберем Приложение Windows Forms. Имя будет: LWP16-ChatServer. Жмём ОК. Получим следующее:

Рис. 4.2 Обозреватель решений: состав проекта приложения Windows Forms сформированного средой разработки

Сразу же добавим необходимую библиотеку. Должен быть выбрать текущий проект в обозревателе решений (LWP16-ChatServer). Выполним Проект -> Добавить ссылку... -> в окне Добавить ссылку переходим на вкладку .NET и ищем System.ServiceModel:

Рис. 4.3 Добавить ссылку: добавляем новую ссылку на библиотеку System.ServiceModel

Переименуем форму в обозревателе решений (ПКМ на иконке формы -> Переименовать). Новое имя формы будет LWP16MainServer. После переименования, автоматически изменится свойство (Name) формы.

Теперь изменим свойства формы LWP16MainServer:

Text

изменим с Form1 на Чат на WCF (C#) :: Сервер

^ Поменяем заголовок формы (то, что отображается в шапке приложения слева).

MaximizeBox

изменим с True на False

^ Уберём кнопку Развернуть.

Icon

изменим изображение (иконку) приложения

^ Необходим файл значка *.ico.

FormBorderStyle

> изменим с Sizable на FixedDialog

^ Сделаем окно «неизменяем» по размерам.

Size

изменим со значений 290; 290 на 300; 125

^ Поменяем размер формы.

Расставим элементы с панели инструментов как показано на рисунке ниже:

Рис. 4.3. Расстановка элементов на форме приложения-сервера

Свойства элементов следующие:

Button:

(Name):

B_Start

Text:

Запуск

Button:

(Name):

B_Stop

Text:

Остановка

GroupBox:

(Name):

GB_1

Text:

Серверные операции

Label:

(Name):

StatusLabel

Text:

Состояние сервера

Событие Click кнопки Запуск:

private void B_Start_Click(object sender, EventArgs e)

{

try

{

cprs = new CustomPeerResolverService(); // Инициалазируем службу узлов

cprs.RefreshInterval = TimeSpan.FromSeconds(5); // Время в секундах обновления таблицы записей распознователя одноранговых узлов

host = new ServiceHost(cprs); // Передаём серверу службу узлов

cprs.ControlShape = true; // Инициализируем совместное использование ссылок

cprs.Open(); // Открываем службу

host.Open(TimeSpan.FromDays(1)); // Запускаем сервер на период одного дня

StatusLabel.Text = "Сервер WCF успешно запущен!";

}

catch (Exception ex)

{

MessageBox.Show(ex.ToString());

}

finally

{

B_Start.Enabled = false;

B_Stop.Enabled = true;

}

}

Событие Click кнопки Остановка:

private void B_Stop_Click(object sender, EventArgs e)

{

try

{

cprs.Close();

host.Close();

StatusLabel.Text = "Сервер WCF успешно остановлен!";

}

catch (Exception ex)

{

MessageBox.Show(ex.ToString());

}

finally

{

B_Start.Enabled = true;

B_Stop.Enabled = false;

}

}

Отредактируем код файла формы LWP16MainServer.cs. Подключим библиотеки в начале файла:

using System.ServiceModel;

using System.ServiceModel.Channels;

using System.ServiceModel.PeerResolvers;

Найдём:

public partial class LWP16MainServer : Form

{

Добавим после:

private CustomPeerResolverService cprs; // Объекта базовой реализации настраиваемой службы распознователя одноранговых узлов

private ServiceHost host; // Объект сервера для службы

Метод LWP16MainServer():

public LWP16MainServer()

{

InitializeComponent();

B_Stop.Enabled = false;

}

Теперь нужно сконфигурировать сервер, для этого воспользуемся стандартный App.Config. Так как при создании приложения Winfows Forms файл конфигурации не создаётся, то нужно создать его самостоятельно. Должен быть выбрать текущий проект в обозревателе решений (LWP16-ChatServer). Выполним Проект -> Добавить новый элемент... (Ctrl+Shift+A). В открывшемся окне выберем Файл конфигурации приложения. Имя оставим неизменным.

Откроем новый добавленный файл App.config и вставим в файл следующий XML-код:

<?xml version="1.0"?>

<configuration>

<system.serviceModel>

<services>

<service name="System.ServiceModel.PeerResolvers.CustomPeerResolverService">

<host>

<baseAddresses>

<add baseAddress="net.tcp://localhost:5433/LWP16_ChatServer"/>

</baseAddresses>

</host>

<endpoint address="net.tcp://localhost:5433/LWP16_ChatServer" binding="netTcpBinding" bindingConfiguration="TcpConfig" contract="System.ServiceModel.PeerResolvers.IPeerResolverContract">

</endpoint>

</service>

</services>

<bindings>

<netTcpBinding>

<binding name="TcpConfig">

<security mode="None"></security>

</binding>

</netTcpBinding>

</bindings>

</system.serviceModel>

</configuration>

Здесь основные значения содержатся в поле:

<add baseAddress="net.tcp://localhost:5433/LWP16-ChatServer"/>

Строчкой выше указывается локальный адрес и порт. Вместо localhost можно использовать реальный IP-адрес. Следующая строка:

<endpoint address="net.tcp://localhost:5433/LWP16-ChatServer" binding="netTcpBinding" bindingConfiguration="TcpConfig" contract="System.ServiceModel.PeerResolvers.IPeerResolverContract">

</endpoint>

Обратим внимание на привязку netTcpBinding.

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

Конфигурация по умолчанию для привязки netTcpBinding быстрее, чем конфигурация, предоставляемая привязкой wsHttpBinding, но она предназначена только для взаимодействия WCF с WCF. Режим безопасности настраивается с помощью дополнительного атрибута securityMode. Использование WS-ReliableMessaging настраивается с использованием дополнительного атрибута reliableSessionEnabled. Но по умолчанию надежный обмен сообщениями отключен. В общем случае системные привязки по протоколу HTTP, такие как wsHttpBinding и basicHttpBinding, настроены на включение основных возможностей по умолчанию, в то время как привязка netTcpBinding по умолчанию отключает возможности, так что для получения поддержки, например для спецификаций WS-*, необходимо специально их включить. Это означает, что используемая по умолчанию конфигурация для TCP быстрее при обмене сообщениями между конечными точками, чем конфигурация по умолчанию для привязок HTTP.

Привязка задается в файлах конфигурации клиента и службы (App.config). Тип привязки указывается в атрибуте binding элемента <endpoint>. Если необходимо настроить привязку netTcpBinding и изменить некоторые из ее параметров, необходимо определить конфигурацию привязки. Конечная точка должна ссылаться на конфигурацию привязки с атрибутом bindingConfiguration. Для нашего случая атрибут имеет привязку к имени TcpConfig:

<binding name="TcpConfig">

<security mode="None"></security>

</binding>

Компилируем приложение (Release) и запускаем. Запускаем и останавливаем сервер. Не должно быть никаких ошибок при нажатии кнопок:

Рис. 4.4 Модифицированное приложение Windows Forms: работа сервера чата после запуска

5. Создание приложения Windows Forms: клиент чата на WCF

Для создания клиентского приложения выполним аналогичные пункту № 4 данной лабораторной работы действия.

Создаём новый проект в текущем решении (LWP16). Для этого выполним следующие действия: Файл -> Создать -> Проект. В окне открывшемся окне «Создать проект», в поле Решение, выберем: Добавить в решение. В качестве проекта выберем Приложение Windows Forms. Имя будет: LWP16-ChatClient. Жмём ОК.

Сразу же добавим необходимые библиотеки. Должен быть выбрать текущий проект в обозревателе решений (LWP16-ChatClient). Выполним Проект -> Добавить ссылку... -> в окне Добавить ссылку переходим на вкладку .NET и ищем System.ServiceModel. Если ОС на которой запущена среда разработки Windows 7, добавим также ещё одну библиотеку: Microsoft Speech Object Library (вкладка COM):

Рис. 5.2 Добавить ссылку: добавляем новую ссылку на библиотеку Microsoft Speech Object Library

Переименуем форму проекта клиентского приложений в обозревателе решений (ПКМ на иконке формы -> Переименовать). Новое имя формы будет LWP16MainClient. После переименования, автоматически изменится свойство (Name) формы.

Теперь изменим свойства формы LWP16MainClient:

Text

изменим с Form1 на Чат на WCF (C#) :: Клиент

^ Поменяем заголовок формы (то, что отображается в шапке приложения слева).

MaximizeBox

изменим с True на False

^ Уберём кнопку Развернуть

Icon

изменим изображение (иконку) приложения

^ Необходим файл значка *.ico.

FormBorderStyle

> изменим с Sizable на FixedDialog

^ Сделаем окно «неизменяем» по размерам.

Size

изменим со значений 290; 290 на 300; 125

^ Поменяем размер формы.

Расставим элементы с панели инструментов как показано на рисунке ниже:

Рис. 5.1. Расстановка элементов на форме приложения-клиента

Здесь у нас в первой группе (GroupBox) «Пользовательские данные»: один Label, один TextBox и Button.

Свойства элементов следующие:

GroupBox:

(Name):

GB_UserDetails

Text:

Пользовательские данные

Label:

(Name):

L_LoginInfo

Text:

Введите имя для входа и нажмите на «Войти в чат»

TextBox:

(Name):

TB_UserName

Button:

(Name):

B_Login

Text:

Войти в чат

Во второй группе элементов один GroupBox и один ListBox:

GroupBox:

(Name):

GB_UserList

Text:

Пользователи в сети

ListBox:

(Name):

LB_Users

Последняя группа содержит один RichTextBox, TextBox и две кнопки.

GroupBox:

(Name):

GB_MessageWindow

Text:

Сообщения чата

RichTextBox:

(Name):

RTB_Messages

ReadOnly:

True

Multiline

True

TextBox:

(Name):

TB_SendMessage

Button:

(Name):

B_Send

Text:

Отправить

Button:

(Name):

B_WakeUp

Text:

!

Перейдём к редактированию кода формы. В начале файла с кодом для формы LWP16MainClient.cs объявим:

using System.ServiceModel;

using System.ServiceModel.Channels;

using System.Runtime.InteropServices;

using SpeechLib; // Для работы имитации голоса (в Windows XP не использовать)

Найдём:

namespace LWP16_ChatClient

{

Добавим после:

[ServiceContract(CallbackContract = typeof(ILWP16Service))]

public interface ILWP16Service // Интерфейс подключения к службе сервера

{

[OperationContract(IsOneWay = true)] // Операция не возвращает ответовное сообщение

void Join(string memberName); // Объявление метода присоединения к чату (по имени)

[OperationContract(IsOneWay = true)]

void SendMessage(string memberName, string message); // Объявление метода отсылки сообщения (по имени и тексту)

[OperationContract(IsOneWay = true)]

void WakeUp(string memberName, string wakeup); // Объявление метода отсылки сообщения (по имени и тексту)

[OperationContract(IsOneWay = true)]

void Leave(string memberName); // Объявление метода выхода из чата (по имени)

[OperationContract(IsOneWay = true)]

void ImageFF(string memberName, Bitmap image); // Объявление метода выхода из чата (по имени)

}

public interface ILWP16Channel : ILWP16Service, IClientChannel

{

}

Найдём:

public partial class LWP16MainClient : Form

{

Заменим на:

public partial class LWP16MainClient : Form, ILWP16Service

{

[DllImport("kernel32.dll")]

public static extern bool Beep(int BeepFreq, int BeepDuration);

private delegate void UserJoined(string name);

private delegate void UserSendMessage(string name, string message);

private delegate void UserWakeUp(string name, string wakeup);

private delegate void UserLeft(string name);

private static event UserJoined NewJoin; // Экземпляр события присоединения к чату через делегат

private static event UserSendMessage MessageSent; // Экземпляр события отсылки сообщения через делегат

private static event UserWakeUp NewWakeUp; // Экземпляр события сообщения типа: "разбудить чат"

private static event UserLeft RemoveUser; // Экземпляр события выхода из чата через делегат

private string userName; // Переменная имени пользователя в чате

private ILWP16Channel channel; // Экземпляр интерфейса чата для канала

// class ServiceModel.DuplexChannelFactory<TChannel>

private DuplexChannelFactory<ILWP16Channel> factory; // Объект средства приёма и передаче "дуплексных" сообщений по каналам в обе стороны

Метод LWP16MainClient() измени так:

public LWP16MainClient()

{

InitializeComponent();

this.AcceptButton = B_Login; // Привязываем событие Нажатия Enter с кнопкой "Войти в чат"

}

После добавим:

public LWP16MainClient(string userName)

{

this.userName = userName;

}

// Метод присоединения к чату (по имени)

void LWP16Client_NewJoin(string name)

{

RTB_Messages.AppendText("\r\n");

RTB_Messages.AppendText(name + " присоединился: [" + DateTime.Now.ToString() + "]"); // Добавляем в RichTextBox строчку c именем и датой входа пользователя

LB_Users.Items.Add(name); // Добавляем нового пользователя в ListBox

}

// Метод отсылки сообщения (по имени и тексту)

void LWP16Client_MessageSent(string name, string message)

{

if (!LB_Users.Items.Contains(name)) // Если имени нет в ListBox при получении сообщения в RichTextBox

{

LB_Users.Items.Add(name); // Добавляет нового пользователя в ListBox

}

RTB_Messages.AppendText("\r\n");

RTB_Messages.AppendText(name + " говорит: " + message + " [" + DateTime.Now.ToString() + "]"); // Добавляем в RichTextBox строчку с именем и сообщением

if (message == "WakeUp") { Beep(500, 100); }

}

// Метод присоединения к чату (по имени)

void LWP16Client_WakeUp(string name, string wakeup)

{

if (!LB_Users.Items.Contains(name)) // Если имени нет в ListBox при получении сообщения в RichTextBox

{

LB_Users.Items.Add(name); // Добавляет нового пользователя в ListBox

}

RTB_Messages.AppendText("\r\n");

RTB_Messages.AppendText(name + " попытался разбудить чат: [" + DateTime.Now.ToString() + "]"); // Добавляем в RichTextBox строчку c именем и датой входа пользователя

if (wakeup == "WakeUp")

{

Beep(500, 100);

Beep(500, 100);

SpVoice voice = new SpVoice();

voice.Speak("Wake Up Mate", SpeechVoiceSpeakFlags.SVSFDefault);

}

}

// Метод выхода из чата (по имени)

void LWP16Client_RemoveUser(string name)

{

try

{

RTB_Messages.AppendText("\r\n");

RTB_Messages.AppendText(name + " вышел: [" + DateTime.Now.ToString() + "]"); // Добавляем в RichTextbox строчку с именем и датой выхода пользователя

LB_Users.Items.Remove(name); // Удаляем по имени из ListBox

}

catch (Exception ex)

{

System.Diagnostics.Trace.WriteLine(ex.ToString());

}

}

void Online(object sender, EventArgs e)

{

RTB_Messages.AppendText("\r\nВ сети: " + this.userName);

}

void Offline(object sender, EventArgs e)

{

RTB_Messages.AppendText("\r\nНе в сети: " + this.userName);

}

#region ILWP16Service Основные методы

public void Join(string memberName)

{

if (NewJoin != null)

{

NewJoin(memberName);

}

}

public void SendMessage(string memberName, string message)

{

if (MessageSent != null)

{

MessageSent(memberName, message);

}

}

public void WakeUp(string memberName, string wakeup)

{

if (NewWakeUp != null)

{

NewWakeUp(memberName, wakeup);

}

}

public new void Leave(string memberName)

{

if (RemoveUser != null)

{

RemoveUser(memberName);

}

}

#endregion

Перейдём к событиям формы. Для кнопки «Войти в чат» событие Click будет содержать код:

private void B_Login_Click(object sender, EventArgs e)

{

if (!string.IsNullOrEmpty(TB_UserName.Text.Trim()))

{

try

{

NewJoin += new UserJoined(LWP16Client_NewJoin); // Переопределяем вызов метода подключения к чату через экзмепляр события

MessageSent += new UserSendMessage(LWP16Client_MessageSent); // Переопределяем вызов метода отсылки сообщения в чат через экзмепляр события

NewWakeUp += new UserWakeUp(LWP16Client_WakeUp); // Переопределяем вызов метода "разбудить чат" в чат через экзмепляр события

RemoveUser += new UserLeft(LWP16Client_RemoveUser); // Переопределяем вызов метода выхода из чата через экзмепляр события

channel = null;

this.userName = TB_UserName.Text.Trim(); // Удаляем пробелы из имени пользователя

// class ServiceModel.InstanceContext

InstanceContext context = new InstanceContext(new LWP16MainClient(TB_UserName.Text.Trim()));

factory = new DuplexChannelFactory<ILWP16Channel>(context, "ChatEndPoint"); // Получаем данные из app.config и передаём данные duplex-каналу

channel = factory.CreateChannel(); // Создаём канал и передаём его экземпляру интерфейса чата

// class ServiceModel.IOnlineStatus

IOnlineStatus status = channel.GetProperty<IOnlineStatus>(); // Определяем экземпляр для индикации доступности объекта по каналу

status.Offline += new EventHandler(Offline); // Вызов метода Offline (если в чате больше никого)

status.Online += new EventHandler(Online); // Вызов метода Online (если в чате больше одного пользователя)

channel.Open(); // Открываем канал

channel.Join(this.userName); // Вызываем метод Join() с текущим именем пользователя введённым в TB_Username

GB_MessageWindow.Enabled = true; // Включаем группу "Сообщения чата"

GB_UserList.Enabled = true; // Включаем группу "Список пользователей"

GB_UserDetails.Enabled = false; // Гасим группу "Данные для входа"

this.AcceptButton = B_Send; // Enter = "Отослать"

RTB_Messages.AppendText("*****************************ДОБРО ПОЖАЛОВАТЬ В ЧАТ*****************************\r\n");

TB_SendMessage.Select();

TB_SendMessage.Focus();

}

catch (Exception ex)

{

MessageBox.Show(ex.ToString());

}

}

}

События Click кнопок «Отправить» и «!»:

private void B_Send_Click(object sender, EventArgs e)

{

channel.SendMessage(this.userName, TB_SendMessage.Text.Trim()); // Вызываем метод SendMessage() и отсылаем имя пользователя и сообщение

TB_SendMessage.Clear(); // Очищаем TB_SendMessage и далее передаём фокус на элемент и делаем его активным

TB_SendMessage.Select();

TB_SendMessage.Focus();

}

private void B_WakeUp_Click(object sender, EventArgs e)

{

channel.WakeUp(this.userName, "WakeUp"); // Вызываем метод WakeUp() и отсылаем имя пользователя и текст "WakeUp"

TB_SendMessage.Clear(); // Очищаем TB_SendMessage и далее передаём фокус на элемент и делаем его активным

TB_SendMessage.Select();

TB_SendMessage.Focus();

}

Событие FormClosing формы LWP16MainClient:

private void LWP16MainClient_FormClosing(object sender, FormClosingEventArgs e)

{

try

{

if (channel != null)

{

channel.Leave(this.userName); // Если закрываем форму, вызваем метод Leave() и удаляем пользователя

channel.Close(); // Закрываем канал между сервером и клиентом

}

if (factory != null)

{

factory.Close(); // Закрываем duplex-канал

}

}

catch (Exception ex)

{

MessageBox.Show(ex.ToString());

}

}

Теперь разъясним принцип работы всего того что было тут наворочено. После запуска приложения-сервера, происходит инициализация канала по определённому адресу. Был выбран локальный адрес и порт 5433, а также абсолютное имя пространства имён LWP16_ChatServer для адресации по этому порту. Имя для адресации в строке конфигурации клиента:

<endpoint name="ChatEndPoint" address="net.p2p://LWP16-Сhat/LWP16_ChatServer"

И...

<custom address="net.tcp://localhost:5433/LWP16_ChatServer"

Может быть любым, но! Главное чтобы оно совпадало с серверной строкой адреса (в файле конфигурации приложения-сервера). То есть, запущенное приложение-клиент должно содержать в файле конфигурации этот абсолютный адрес.

После ввода имени, становится доступной кнопка «Войти в чат». После нажатия на кнопку, в приложении-клиенте происходит вызов (через делегат и событие) метода интерфейса: Join(string memberName), содержащее переданное из текстового поля строку с именем. И далее выполняется: LWP16Client_NewJoin(string name), где в RichTextBox добавляется запись о присоединении пользователя с таким-то именем к чату и временем присоединения. Имя также добавляется в ListBox. Если пользователь в уже не один, срабатывает метод Online(), которые сразу же оповещает и пользователя и другого пользователя о том, что они «в сети». Метод срабатывает в том случае, если в сети больше одного пользователя, после нажатия кнопки «Войти в чат» пользователя ещё не вошедшего в чат. Вызывает событие после получения по каналу «индикатора события доступности»:

IOnlineStatus status = channel.GetProperty<IOnlineStatus>();

Подключение третьего пользователя не вызывает срабатывание метода у двух предыдущих, но «в сети» отображается у нового пользователя, которому выдаётся оповещение о том что в канале он не один. Также любое подключение вызывает у всех клиентов срабатывание события NewJoin и следовательно Join(<имя подключившегося>).

Сообщение отсылается по такому же событийному механизму, но содержит также текст сообщения, которое пользователь набрал у себя в клиенте. Отправка идёт после нажатия кнопки «Отправить». В ListBox новый пользователи чата добавляются лишь по факту совершения события и появления записи с именем в RichTextBox, потом если в сети один клиент, то об имени уже находящегося в канале пользователя новый клиент узнает только после совершения тем пользователем действий.

Аналогичным образом работает событие WakeUp, которое передаёт чату имя пользователя нажавшего кнопку «!» и текст «WakeUp», который не отображается в чате. После получения такого сообщения, все клиенты издают системный звук (чтобы разбудить тех кто находится в чате). А также, если ОС на которой запущен клиент это Windows Vista или Windows 7, то приложение проговаривает заранее заготовленную фразу. Также системный звук раздаётся, если написать в чат непосредственно слово WakeUp.

Выход из чата (через закрытие формы и вызов события FormClosing) тоже выдаёт оповещения, а также происходит удаление имени вышедшего из ListBox всех клиентов.

Наше приложение-клиент готово. Можно компилировать и проверять работоспособность.

6. Завершающая часть

Компилируем приложения (Release) и запускаем. В качестве основного запускаемого объекта решения (Запускаемый проект) ставим приложение сервер. Стартуем сервер нажатием кнопки «Запуск». Запускаем копию приложения клиента. Вводим имя и жмём «Войти в чат»:

Рис. 6.1. Результат работы приложения клиента после запуска сервера: вход первого пользователя в чат и отсылка сообщения

Запускаем второй клиент, входим в чат и пишем сообщение:

Рис. 6.2 Результат работы приложения клиента после запуска сервера: вход второго пользователя в чат и его действия

Закрывает первый клиент, запускаем третий клиент и пишем со второго и третьего клиентов:

Рис. 6.3 Результат работы приложения клиента после запуска сервера: вход третьего пользователя в чат и его действия

7. О приложении к Лабораторной работе № 16

Получившиеся программы (LWP16WCF.exe, LWP16WCFClient.exe, LWP16-ChatServer.exe и LWP16-ChatClient.exe), собранные из кусков кода приведённых в данной лабораторной работе, можно загрузить по ссылке в конце этого материала.

Размещено на Allbest.ru

...

Подобные документы

Работы в архивах красиво оформлены согласно требованиям ВУЗов и содержат рисунки, диаграммы, формулы и т.д.
PPT, PPTX и PDF-файлы представлены только в архивах.
Рекомендуем скачать работу.