×
Вы действительно хотите открыть доступ к тестированию по курсу WCF Базовый на 40 дней?
ВИДЕОУРОК №2. Хостинг сервисов.
Видео курс WCF Essential
Урок 2. Хостинг сервисов
Здравствуйте, меня зовут Александр Шевчук. Я сертифицированный тренер Microsoft, работаю в компании CyberBionic Systematics. Я рад вас приветствовать на информационном видео ресурсе для разработчиков программного обеспечения ITVDN. Тема данного урока «Конфигурирование и хостинг сервисов WCF».
И давайте перейдем к первому слайду и вспомним, что же такое конечная точка. Мы помним, что конечная точка – представляет собой совокупность адреса, контракта и привязки. Конечная точка – это сетевой ресурс, которому можно посылать сообщения. Клиент посылает сообщение конечным точкам в формате, который описывается контрактом между клиентом и службой.
И давайте перейдем к рассмотрению первого элемента конечной точки – адреса. Мы знаем, что в WCF каждая служба связывается с неким уникальным адресом. Адрес содержит два элемента. То есть, размещение службы и транспортный протокол, или, как мы еще будем называть транспортный протокол, транспортной схемой. Адрес определяет, куда следует отправлять сообщения, что бы конечная точка их получила. Давайте посмотрим на формат адреса. У нас имеется базовый адрес, как мы говорили URL, и URN. URN в адресе не всегда обязательный. Если по определенному адресу, по определенному порту располагается только один сервис и, в нашем случае, не может быть неоднозначности, то URN можно не указывать. Давайте посмотрим более детально формат базового адреса. Мы указываем транспорт, вот например http, далее указываем IP или домен, в данном случае мы указываем IP локал хостом, здесь вы можете указать IP сайта своей организации или домен сайта своей организации, например Microsoft.com. Далее, мы можем указать необязательный порт, умолчанию если будет использоваться http, то у нас будет 80 порт, либо вы можете выделить какой-то свой любой порт. И вот имеются примеры адресов. Допустим, имеется транспортная схема http, IP 127.0.0.1, и 8001 порт. Далее, допустим, мы можем указать и имя сервиса, который находится по этому адресу. Допустим, можем использовать транспорт net.tcp, если мы работаем с локальными сетями, net.pipe, если мы используем interprocess communication (межпроцесные взаимодействия). Можем использовать транспортные префиксы msmq (Microsoft Message Queuing), если хотим организовать некий аналог электронной почты для приложений, есть у людей электронная почта и для программ тоже имеются такие механизмы, которые позволяют им построить некий аналог такой электронной почти, и это позволяет сделать технология MSMQ.
И давайте теперь рассмотрим каждый адрес по отдельности.
И первая разновидность адреса, которую мы рассмотрим это адреса TCP (Transmission Control Protocol), то есть протокол управления передачей. Мы видим, что адреса TCP содержат транспортный префикс «net.tcp». Адреса TCP есть смысл при работе с локальными сетями, потому что для работы с интернетом TCP не совсем подходит. Мы в адрес можем включить номер порта, видите, IP, норме порта и сервис. Если порт не указан, то по умолчанию будет использоваться порт 808. И два адреса TCP могу совместно использовать один порт, вот мы это видим.
Следующие адреса это адреса HTTP. Мы видим, что адреса HTTP содержат транспортный префикс http или префикс безопасного транспорта https. Адреса HTTP обычно используются службами, размещёнными в интернет. HTTPS расшифровывается как HyperText Transfer Protocol Secure, то есть расширение протокола http которое поддерживает шифрование. И данные передаваемые по протоколу http упаковываются в криптографический протокол ssl или tls, и тем самым обеспечивается защита этих данных. И в отличие от http, https по умолчанию используется tcp порт 443. Вот, мы это видим.
Следующий адрес это адреса IPC, или как мы их называем адреса для межпроцессных взаимодействий, или inter-process communication. IPC, по сути, представляет собой набор способов для обмена данными между множеством потоков в одном или более процессов. Процессы могут быть запущенны на одном компьютере. Раньше ipc выражались в виде множества техник, туда же входили и Remoting, и различные LPC, и работа с буфером обмена, с OLE, с DDE, и многие, многие другие. Так вот, сегодня Microsoft объединила все эти возможности в WCF и теперь, если нам следует налаживать межпроцессные взаимодействия, то мы будем использовать адреса с использованием транспортной схемы net.pipe. И вот давайте посмотрим правила. Адрес должен содержать явно заданное имя локального компьютера или localhost, за которым следует строка с именем канала. И два адреса IPC не могут использовать одно имя канала на одном компьютере, так как net.pipe, именованный канал, может быть открыт только в одном экземпляре.
И мы перейдем к следующим адресам. Это адреса MSMQ, то есть Microsoft Message Queuing. Мы видим транспортный префикс net.msmq. MSMQ это технология очереди сообщений Microsoft, она позволяет, или предоставляет, такие возможности приложениям, которые выполняются в разное время обмениваться информацией. То есть мы уже говори, что это некий аналог электронной почты для приложений. При этом не принимается во внимание гетерогенные системы операционных систем, которые могут быть временно недоступны, и msmq обеспечивает гарантированную доставку сообщений, эффективную маршрутизацию, безопасность и передачу сообщений на основе приоритета.
И последняя разновидность адресов это адреса P2P (Peer-to-Peer). Так сказать адреса, которые используются при работе с одно-ранговыми, децентрализованными, или как мы их называем пиринговыми сетями. Peer-to-Peer переводится равный к равному. То есть получается, что это некая компьютерная сеть, которая строится на равноправии участников. И в такой сети отсутствуют выделенные серверы, а каждый узел, как его называют пиром, является как клиентом, так и сервером. И в отличие от архитектуры клиент-сервера, такая организация позволяет сохранять работоспособность сети при любом количестве и любом сочетании доступных узлов пирам. И участниками такой сети, повторюсь, являются пиры. То есть пир – равноправный участник, пользователь сети, предоставляющий сервисы другим участникам такой одно ранговой сети, и сам пользующийся их сервисами. Часто так называется клиент, который участвует в раздаче в файл обменных сетях. И так же, по протоколу P2P обмен, например, файлами в том же скайпе, в live messenger и других чатах. Зачем? За тем, что бы ни нагружать основной сервер. То есть, если я хочу Вам передать, например, свою фотографию то получается, что между нами вот такое пиринговое соединение и именно по такой схеме происходит передача этого файла.
А мы с Вами переходим к рассмотрению следующего элемента конечно точки – это привязки. И обратите внимание на определение, которое мы даем привязке. Привязка представляет собой набор настроек, относящихся к транспортному протоколу, обратите внимание, вот у нас в имени привязки указывается тот транспортный протокол, который должен использоваться в связке с данной привязкой. Далее, кодированию сообщений, сообщение тоже, должно быть либо закодированным, либо не закодированным, вот мы смотрим, что если мы используем привязку BasicHttpBinding, то мы можем использовать вот такую либо текстовую кодировку, либо кодировку MTOM (Message Transmission Optimization Mechanism). И если текстовая кодировка отправляет чистый текст, то MTOM позволяет отправлять бинарные данные и вот такая кодировка MTOM используется для коммуникации, например, между Windows и Linux сервисами, с кроссплатформенными сервисами. А если мы видим в имени привязки такой префикс Net, это говорит о том, что эта привязка предназначена для организации коммуникации только на платформах Windows и здесь будет использоваться бинарная кодировка, она считается более оптимальной. Ну и так далее, коммуникационная схема, надежность сообщений, безопасность, распространение транзакций и совместимость. Мы эти понятия рассматривали на прошлом уроке. И в дальнейшем мы уже будем поочередно рассматривать все эти привязки уже применимо к какому-то конкретному случаю. Вот уже с базовой привязкой мы познакомились, с привязкой TCP дальше познакомимся, привязка для работы в одноранговой сети, IPC привязки, которые используются для организации inter-process communication, WS это привязка, которая поддерживает стандарты Web Service star, федеративная привязка, например для организации работы с различными single sign-on, дуплексная привязка, так же мы будем рассматривать такую дуплексную коммуникацию, привязка для работы с msmq ну и интеграционная привязка msmq.
И следующий элемент конечной точки это контракт. Мы уже понимаем, что технически контракт представляет собой интерфейс. Как мы видим здесь в определении, контракт – это стандартный, платформенно-независимый способ описания того, что делает данная служба. Контракты у нас бывают 4 видов. Это контракты служб, контракты данных, контракты ошибок и контракты сообщений. Мы уже видели, что контракты служб описывают операции, которые могут вызываться клиентом, сервисом consumer, на сервисе провайдере. Контракты данных обычно определяют, какие типы данных принимаются и передаются сервисам. Ну, например, если мы вызываем удаленный метод и в качестве аргумента метода мы хотим передать экземпляр класса MyClass, то есть экземпляр какого-то сложного класса был передан на сторону сервера, то нам здесь нужно воспользоваться так же специальными атрибутами, которые будут говорить нам о том, что тот или иной класс будет, так сказать, придерживаться контракта передачи данных, и WCF определяет еще косвенные данных, для встроенных типов, таких как int, float, string. Вы помните, мы рассматривали простейшие сервисы и нам не надо было для аргумента метода, допустим Say, создавать свой собственный контракт. Почему? Потому, что там использовался аргумент типа string, а вот этот тип, уже для этого типа WCF определяет так называемый косвенный, то есть невидимый контракт. Он как бы встроен по умолчанию. Но если вы будите создавать свои типы и экземпляры передавать на сторону сервера, то Вам потребуется создавать контракт данных. Как создаются такие контракты данных мы будем уже смотреть дальше. Далее, контракты ошибок. Контракты ошибок определяют, какие ошибки инициируются службой и как служба будет обрабатывать эти ошибки, и как она передает информацию об этих ошибках своим клиентам. Либо на error сервер, либо что нам делать с возможными, или с происшедшими исключениями на стороне сервиса, и поэтому вот имеется такая разновидность контракта. И контракты сообщений. Эти контракты позволяют сервисам напрямую работать с сообщениями. Что это значит? Это значит, что мы создаем экземпляр класса message, наполняем его нужной информацией и уже отправляет сообщение физически, практически уже отходя от идей RPC, хотя там есть такие обертки, которые помогают с этим работать, но при работе с сообщениями мы работает непосредственно с экземпляром класса message, который позволяет нам представить, который даже представляет собой объектно-ориентированное представление сообщения, которым обмениваются сервисы в сети друг с другом.
И следующий важный элемент сервиса это, собственно, сам хостинг, который включает в себе и конечную точку, и включает в себя, по сути, тело сервиса. И мы понимаем, что каждая служба WCF должна находиться под управлением некоторого такого процесса, процесса Windows, который будет называться хостовым процессом. И, важно понимать, что один хостовый процесс может управлять несколькими экземплярами служб одного типа.
И мы можем посмотреть на следующий слайд, и посмотреть, как же выглядит вот эта техника схематически, когда один хостовый процесс управляет экземплярами служб одного типа. Представьте себе, у нас имеется несколько сервисов consumer, которые отправляют сообщения на сторону сервиса, конечная точка их принимает, и обратите внимание, что вот для этого сервиса consumer у нас создается вот этот экземпляр сервиса, для этого создается вот этот, а для этого создается вот этот. Видите, то есть для каждого сервиса consumer на стороне сервера создается отдельный экземпляр сервиса, например. А может быть и наоборот, может быть только один сервис. У нас имеется 3 уровня, так сказать, 3 уровня работы с экземплярами сервиса. То есть экземпляры бывают, так сказать, трех уровней. Уровень сеанса, или уровень сессии, когда для каждого отдельного сервиса создается, для каждого consumer, создается отдельный сервис, и он живет указанное количество времени, стандартно это примерно 10 минут. Далее, уровень вызова. То есть на каждый вызов создается экземпляр и потом уничтожается, сразу же уничтожается, даже если Вы в цикле будите вызывать несколько раз методы, например у себя на consumer, один и тот же метод будите вызывать, здесь на стороне сервера у Вас будет создаваться только один экземпляр на каждый Ваш вызов, то есть конечно вы понимаете, что это не оптимально. И синглетный уровень, когда создается один singleton, экземпляр, так сказать, синглетный, единственная его копия. Когда вы отправляете сообщение на строну сервиса, они выстраиваются здесь в очередь и этот singleton по очереди обрабатывает сообщения разных consumer-ов. Но об уровнях экземпляров, а точнее уровни экземпляров, мы будем рассматривать дальше по курсу, а сейчас мы просто познакомились.
И теперь, нам важно рассмотреть варианты хостинга, которые могут использоваться нами, при размещении сервисов. У нас имеется автохостинг, хостинг в службах Windows, то есть так называемых NT service, хостинг WAS (Windows Activation Services), и хостинг IIS (Internet Information Services), то есть в IIS у нас будет происходить хостинг.
И теперь мы с Вами перейдем как к рассмотрению примера, но прежде чем перейти в Visual Studio мы будем на слайде смотреть с Вами диаграммно, что же представляет собой та или иная разновидность хостинга.
Давайте перейдем на слайд и посмотрим автохостинг. Автохостинга у нас имеется несколько разновидностей. Мы понимаем, что мы можем хостить, размещать, сервис провайдер в консольных приложениях, в Windows приложениях, в WPF приложениях. Так вот, такое размещение сервиса и называется авторазмещением, или Self-Hosting. И разновидность размещения в консоли мы уже видели, но мы все равно сейчас перейдем к примерам и посмотрим, как мы можешь размещать сервисы в консоль, и как мы можем размещать в WPF формах. Так же мы посмотрим размещение сервисов непосредственно в коде или с использование конфигурационных файлов, точнее описание конечных точек сервисов.
И давайте теперь перейдем в Visual Studio и посмотрим первый пример. Заходим на серверную часть. И смотрим, на 8 строке мы создаем интерфейс с именем IContractService, помечаем его атрибутом ServiceContract, тем самым делаем этот интерфейс сервисным контрактом. В теле интерфейса, на 11 строке, мы создаем абстрактный метод Method, который принимает один строковой аргумент и возвращает значение типа double, и помечаем его атрибутом OperationContract. Далее, на 16 строке мы создаем собственно сам класс сервиса, реализуем в нем контракт IContractService. И на 18 строке вот мы видим реализацию метода с именем Method, который принимает строковой аргумент и возвращает значение типа double, и в теле метода мы выводим на экран, что обработан запрос, выводим на экран то значение, которое передал пользователь. Далее мы проверяем в условной конструкции if, что если пользователь передал слово “double”, то мы возвращаем 777.77, а иначе, если пользователь передал что-то другое в качестве аргумента при вызове метода, то мы возвращаем пользователю 0. Далее нам требуется организовать хост, создать хост. И вот на 35 строке мы выводим в title консоли, что это сервер. Создаем экземпляр сервис хоста, обратите внимание, передаем аргументы, передаем экземпляр класса type, содержащий в себе информацию о сервисе, и передаем адрес. Далее на 39 строке мы добавляем конечную точку, передаем, снова же, контракт, указываем требуемую привязку, ну адрес у нас уже имеется. И открываем хост.
Далее мы можем зайти на клиентскую часть и посмотреть, какой код имеется у клиента. На 8 строке имеется тот же самый контракт, мы с Вами помним, что контракты, которыми пользуются клиенты, то есть сервис consumer, называется требуемый контракт, а контракты стороны сервиса провайдера называется предоставляемые контракты. И мы знаем, что как предоставляемый контракт, так и требуемый контракт они технически совпадают. Далее, в теле метода main мы создаем ChannelFactory, и на 24 строке мы говорим фабрика, создай нам объектно-ориентированное представление канала. В данном случае мы его ассоциируем с сервисом. И на 26 строке мы на канале вызываем метод, используя технику RPC (Remote procedure call), мы понимаем, что этот метод в итоге каким-то хитрым образом обращается к серверной стороне, передает сообщение, в которое упаковывает вот эту строку “double”. Там мы видели, в теле сервиса, как происходит обработка этого аргумента. И в итоге на 26 строек мы переменной digit типа double мы присваиваем возвращаемое значение метода Method, который обратится к сервис провайдеру и получит от него сообщение, и отдаст его нам, и мы его поместим в переменную digit. И дальше выводим это значение на экран.
И давайте перейдем к следующему примеру. И в этом на серверной стороне мы снова же видим, что у нас на 10 строке имеется контракт, видите мы создаем контракт, помечаем атрибутом ServiceContract, тот же самый метод, что и в предыдущем примере, на 18 строке мы создаем класс сервиса, реализуем в нем контракт, ничего не поменялось. И вот интересно теперь посмотреть в тело метода main. На 37 строке мы создаем экземпляр класса сервис хост и открываем хост. Вы скажите Подождите, подождите, подождите, а где же конечная точка?, как сервис consumer узнает куда, в какой форме слать сообщения, что вообще может этот сервис. А вот давайте мы зайдем сейчас в конфигурационный файл и посмотрим, что мы все тоже самое, что раньше хард кодили, то есть писали, жестко кодировали, записывали в коде, мы теперь можем вынести в конфигурационный файл. Обратите внимание, этот файл представлен в xml формате. Вот у нас как раз идет описание конечной точки, указание адреса, привязки, контракта. И здесь даже на 9 строке указываем, что мы для хоста указываем базовый адрес, и вот задаем базовый адрес, где будет находится сервис. И далее, в теге endpoint мы в атрибуте binding и contract присваиваем соответствующие значения. Байндингу присваиваем basicHttpBinding, пожалуйста не ошибайтесь, он должен быть с маленькой буквы, потому что если поставить с большой буквы, то уже возникнет ошибка, и Вам будет казаться, что вроде я все правильно написал, но будет ошибка из-за этого. Так же мы указываем полное квалифицированное имя контракта, включая пространство имен, где находится этот контракт.
И далее заходим в program клиента, смотрим, имеется, снова же, версия контракта, только это уже требуемый контракт. Здесь мы создаем уже стандартный ChannelFactory, создаем канал, и вызываем метод, используя метод RPC. И мы передаем методу строку “double”, этот метод обращается к сервису провайдеру, сервис провайдер ему отвечает, и возвращаемое значение метода, то есть то, что он получил в конверте, мы присваиваем переменной digit и выводим на экран. Значит, мы видим, два способа задания конечных точек. Либо непосредственно в коде, как в предыдущем примере, либо в конфигурационном файле. Какой способ предпочтительней? Ну конечно же предпочтительней в конфигурационном файле. Почему? Потому, что у нас здесь живет просто голинький сервис, который мы можем уже в дальнейшем конфигурировать так, как нужно. Мы можем включать, отключать шифрование, можем его переносить с одного домена на другой, а так как было в предыдущем примере, то если мы хотели перенести нас сервис с одного домена на другой, или с одного IP адреса на другой, то получается, что нам пришлось бы перебилживать программу. А так, просто администраторы возьмут и здесь укажут, допустим, сайт Microsoft.com и, допустим, с нашего сайта перенесут его сразу на сайт Microsoft, к примеру. И администраторы уже не будут обращаться к программистам, что бы те перебилдили им сервисное решение.
А мы идем дальше. И посмотрим теперь хостинг в… Можно хостить в Windows Form приложениях, можно хостить в WPF (Windows Presentation Foundation), без разницы. Давайте посмотрим. Вот, серверная сторона. Можем сразу выполнится и посмотреть, что у нас происходит. Вот у нас имеется клиент и вот у нас имеется сервер. Берем, стартуем сервер. Сервер запущен. И отправляем сообщение на сторону сервера «Hello Server», например. Нажимаем Enter. И вот видите, сообщение от меня «Hello Server», сообщение от сервера «Вы сказали Hello Server». То есть сервер получил сообщение, обработал и прислал нам ответ. Вот это From me, это From Server. И давайте посмотрим, как мы можем организовать работу такой программы.
Заходим в контракт, видим, что здесь у нас имеется простейший контракт. Не забываем атрибуты ServiceContract и OperationContract, 11 строка метод Say, который принимает один строковой аргумент и возвращает строковое значение. Заходим в Service. Имеется сам сервис, класс Service, который реализует указанный ранее контракт. На 9 строке мы реализуем абстрактный метод Say из контракта. И вот, обратите внимание, мы принимаем и возвращаем пользователю значение «From Server: Вы сказали – » то-та то-та.
И давайте перейдем в code behind и посмотрим. Теперь смотрим, в теле класса Window1 мы создаем адрес, простейший binding, BasecHttpBinding, создаем поле service типа ServiceHost. Стандартный конструктор. И вот пожалуйста, у нас имеются обработчики событий нажатий на кнопку. Мы видим, что это обработчик событий на кнопку старт сервиса, мы проверим, сервис не пустой, если сервис еще не создан, то мы на 31 строке создаем этот сервис, передаем экземпляр класса type, который содержит о сервисе, потому что мы понимаем, что он через активатор create instance будет создавать экземпляр этого сервиса, если вы забыли, как это происходит, то посмотрите урок по рефлексии, здесь сервис создается при помощи рефлексии. На 34 строке добавляем конечную точку, которая определяет границу сервиса, и открываем конечную точку. Это – метод обработчик события нажатия на кнопку остановить сервис. Мы видим, что мы тут просто останавливаем сервис и на всякий случай зануляем его, что бы уже действительно быстрее потерять ссылку, в каких-то случаях это бывает полезно.
Давайте теперь зайдем на сторону клиента. Мы видим, имеется тот же контракт. Только этот контракт называется требуемый, а контракт на стороне сервера – предоставляемый. И заходим в code behind. Смотрим, создаем тот же address, тот же banding. Адрес, бандинг и контракты должны совпадать. Создаем поля factory и channel, пока пустые. И далее вот у нас метод обработчик нажатия на кнопку Отправить сообщение, к примеру. У нас здесь создается фабрика каналов, создаем непосредственно канал. Проверяем, что бы они были не пустые. И, собственно, отправляем сообщение. Видите, вот channel.Say говорит «отправь пожалуйста сообщение, которое находится в textBox2», который был ниже, куда мы вводили сообщение. И соответственно в верхний textbox мы выводим его. Здесь уже не стали делать каких-то красивых имен, потому что все равно 3 элемента управление, думаю и так достаточно понятно.
Давайте посмотрим тот же самый пример, с использованием конфигурационных файлов. И зайдем, сторона клиента не изменилась, относительно предыдущего примера. Смотрим, контракт, Service так же остались прежними. Давайте зайдем в code behind и посмотрим. Обратите внимание, 25 строка мы создаем экземпляр сервис хоста, но не указываем конечную точку. Мы помним, что конечная точка теперь описывается в конфигурационном файле. И по сути выполнение будет такое же. Хотелось бы обратить внимание на вот этот файл app.manifest. Мы его, собственно, добавляем сами. Зачем? За тем, что бы мы могли, сейчас закомментируем эту строку. Зачем мы это делаем? Для того, что бы определить уровень требуемой безопасности, так сказать, требуемой безопасности для выполнения данной программы. Что это значит? Дело в том, что для того, что бы нам получить доступ к портам нам требуется находится под, иметь определенные привилегии для этого. И вот мы здесь, в этом файле, app.manifest, можем указать, что вот мы хотим иметь наивысший доступный приоритет. Либо в другом случае, Вы должны, для того что бы выполнялись Ваши примеры, запускать проект и запускать Visual Studio от имени администратора. Иначе у Вас будет ошибка. Или использовать этот файл. И снова же, вроде бы он в режиме debug не должен сработать, сейчас посмотрим. Работает. Раньше возникали по debug’ам проблемы. Хотя у кого-то могут возникнуть проблемы.
А мы идем дальше. И сейчас мы рассмотрим еще одну разновидность автохостинга – это хостинг службы в user interface потоке. Такой хостинг дает нам возможность обновления пользовательского интерфейса, или вообще всей формы именно службой, сервисом. И вот часто возникает вопрос как службе получить ссылку на форму. Обратите внимание, раньше была проблематично, что бы служба обратилась к форме. У нас есть два способа решения такой проблемы. Первый способ – мы должны форму сделать службой. Мы сейчас посмотрим, как это делается.
Обратите внимание, на 10 строке у нас имеется класс Window1 и мы реализуем в нем контракт. Давайте посмотрим. Вот у нас имеется контракт. Видите, стандартный сервисный контракт. И мы, по сути, непосредственно в Window1, в самой форме, реализуем этот контракт. Здесь же мы указываем и адрес, и binding. Смотрим далее, здесь же мы создаем и сервис, видите, создаем ServiceHost, настраиваем конечную точку, открываем конечную точку. Здесь идет код завершения. А вот пожалуйста, сама реализация сервиса. Вот имеется контракт, а вот идет его реализация. Мы видим, что эта реализация идет непосредственно в самом классе Window1. Интересно, да? То есть, вроде бы и форма, и служба одновременно. Но здесь есть еще маленькое ограничение. У нас имеется такой атрибут, ServiceBehavior, и мы в таком случае, что бы все правильно сработало, должны взять и пометить этот класс, класс формы, именно вот этим атрибутом ServiceBehavior, и указать именованный параметр атрибута InstanceContextMode как Single. То есть, что значит Single? Это значит, что экземпляр этого класса будет являться синглетным. То есть, по сути, экземпляр вот этого класса-сервиса, потому что Window1, он же по сути становится сервисом, должен быть синглетным. Мы с Вами рассматривали в презентации уровни экземпляров. Обратите внимание, мы с Вами говорили, что вот у нас бывают 3 уровня экземпляров. Уровень сессии, когда в соответствие к каждому сервису consumer создается экземпляр сервиса, и вот 10 минут он живет с момента последнего обращения. Либо каждый раз на каждое обращение создается новый, это второй уровень – уровень вызова, per call называется. Есть еще синглетный уровень, когда создается только один экземпляр, выглядит он вот так, и когда у нас несколько сервисов consumer обращаются к такому сервису, то их обращения, их вот эти конвертики, ложатся здесь в стопочку, и он по мере прочтению и ответов снимает с стопочки конвертики. Это очередь, не стек, а очередь. Вот, мы возвращаемся в код. Ну и, собственно, клиент, у нас остается без изменений, относительно других примеров. Поэтому вот, мы можем теперь обращаться. Давайте выполнимся и посмотрим, как работает эта программа. Стартуем сервер, сервер запущен. Пишем Hello From User. Видите, на стороне сервера у нас вывелось сообщение Hello From User. Потому что в предыдущем примере мы не могли так сделать, мы не могли обратиться напрямую к форме и вывести сообщение. Здесь теперь мы видим, получается практически как чат. Я вот пишу привет от меня, а мне отвечают. Мы сказали Hello From User, здесь на стороне сервера тоже видно. Но это только один способ. Давайте посмотрим еще один способ.
И мы сейчас напрямую, из сервиса, будем обращаться к форме через один интересный механизм. Давайте откроем Visual Studio и посмотрим следующий пример.
Заходим в контракт, контракт у нас не изменился. Заходим в code behind. И смотрим, в данном случае наша форма, наше окно, уже не является сервисом, но, тем не менее, мы создаем в нем адрес, binding. Далее, создаем сервис хост. Добавляем конечную точку, открываем. И смотрим дальше. А вот у нас ниже имеется реализация сервиса, мы просто реализовали его в одном модуле, что бы не разносить по разным файлам. И вот на 72 строке мы создаем класс Service, реализуем в нем контракт. Обратите внимание, у нас имеется вспомогательный класс, который называется UiConnection, и смотрите, что мы в нем делаем. Мы в этом классе, получаем ссылку на текущую форму. Обратите внимание как, мы обращаемся к Application.Current, колекция Windows, ну мы знаем, что в этом коллекции имеется только одно окно, поэтому мы не делаем сложной логики, ну и дальше FirstOrDefault и передаем сюда то, что мы хотим получить. И в итоге мы получаем ссылку на текущее окно. И далее у нас имеется метод UpdateText, мы здесь обращаемся теперь к нашей форме, к textBox1, к его свойству Text и в него что-то записываем. И уже в методе Say, на классе UiConnection обращаемся к методу UpdateText, и практически происходит полноценное обращение к элементу требуемой формы. Клиент не изменился. Давайте выполнимся и посмотрим, действительно ли работает этот пример. Запускаем сервер, запускаем ему сообщение Hello. Вот, пожалуйста. Видим, что вторым способом мы тоже получили доступ к форме.
И давайте еще посмотрим следующий пример. Следующий пример тоже показывает, как у нас работает сервис с использованием конфигурационного файла. Просто что бы повторить. Я думаю, он будет очевиден и очень прост.
Снова же смотрим, имеется знакомый код. Мы создаем, так сказать, окно и службу одновременно, мы пример назад смотрели это. И смотрим, что мы на 28 строке создаем экземпляр сервис хоста, передаем ссылку на себя, открываемся. Но мы понимаем, что настройка конечной точки происходит автоматически через файл app.config. Здесь мы указали и адрес, и привязку, и контракт. Не забывайте, что все привязки в app.config мы пишем с маленькой буквы, поэтому если скопировать и вставить привязку из хард-кода, то нужно поменять первую букву на маленькую. Тот же самый пример, только с использованием конфигурационного файла.
А мы с Вами переходим к рассмотрению следующих разновидностей хостинга.
И посмотрим на еще один вид автохостинга – это хостинг в Windows Service, или как их называют NT Service, или NT службы. Если Вы не совсем хорошо знакомы с такой разновидностью приложений, то Вы можете на нашем курсе C# Professional познакомится с созданием Windows сервисов, а мы сейчас будет в контексте Windows сервиса создавать, так сказать, хостовую среду для того, что бы именно в Windows сервисе работал WCF сервис, WCF сервис провайдер. И давайте перейдем сперва к рассмотрению программного кода, перейдем в Visual Studio.
Зайдем в код NT сервиса. На 9 строке у нас стандартно создается ProjectInstaller, в ProjectInstallr в конструкторе мы описываем, как будет наш сервис называться, его описание, описать вот здесь, вот это description, здесь его называние, он будет называться вот таким именем, мы его специально так называли, что бы его здесь было проще найти. И description будет у него вот такой. Далее, устанавливаем стартовый режим автоматически, то есть когда мы будем перезапускать компьютер, то он у нас будет автоматически запускаться, не вручную, а он сам будет автоматически запускаться. Сейчас мы к этому подойдем, это такой служебный класс для NT сервисов, кто не знает. А вот, на 29 строке мы создаем сам класс NT сервиса. Снова же повторюсь, вот это идет набор NT сервисов, или Microsoft, или Windows сервисов. Вот мы создадим такую же программу. Она не имеет пользовательского интерфейса. И в нашем случае будет только хостить WCF сервис. И вот смотрим, у нас имеется два метода OnStart, OnStop. Снова же представьте, что у нас здесь наш сервис, если мы ПКМ нажмем вот если мы нажмем Start из контекстного меню, то как раз выполнится метод Start, если нажмем Stop, то выполнится метод Stop. Pause, Resume, Restart мы не стали реализовывать, потому что у нас задаче не рассмотреть устройство NT сервисов, а мы хотим просто в контексте такой NT сервиса запустить наш WCF сервис. И когда мы стартуем сервис, NT сервис, то у нас здесь как раз создается сервис хост для нашего WCF сервиса. Если нажимаем Stop, то он у нас останавливается. Мы понимаем, что у нас имеется app.config, в котором описывается конечная точка WCF сервиса. И рассмотрим наши основные составляющие. Вот у нас имеется контракт, знакомый метод Say. 68 строка создаем, собственно, сам сервис, который реализует этот контракт, реализуем метод Say, и когда пользователь удаленно вызовет наш метод, передаст нам какое-то сообщение, мы его конкатенируем с ответным сообщение и возвращаем в конверте ответ пользователя, а пользователь уже пусть делает с ним то, что хочет. И собственно посмотрим клиента. Вот у нас имеется клиентский контракт. Зайдем в code behind, стандартный код Windows приложения, которое будет обращаться к этому сервису. Оно никак не изменилось, относительно предыдущих версий. Теперь нам нужно нажать F6, build succeeded. И теперь посмотреть, на сам файл сервиса. Выбрать ПКМ, «open folder on file explorer», обратите внимание, вот в папочке bin, debug, у нас получилось версия этого сервиса. Ну мы знаем, что мы не можем запустить NT сервисы напрямую. Видите, говорит что не может запустить, он требует специальные утилиты, что бы его можно было правильно установить. Поэтому сейчас мы с вами и займемся тем, что установим этот сервис и в дальнейшем к нему обратимся. Для того, что бы установить мы сейчас должны скопировать все необходимые файлы по установке, сейчас я это расскажу, покажу как это делается, и установим его в сервисы. Но перед этим желательно настроить сервис для работы под любым процессором. Для этого мы зайдем в окно свойств, property, и нажмите Alt Enter, здесь выберите пожалуйста Configuration Manager, и там проследите, что бы у Вас WindowsService стоял в Platform пунктик Any CPU. Если у Вас здесь ничего нет, то Вы тогда возьмите Mixed Platform, выберите New, ну и здесь укажите то, что требуется, что бы у Вас вот здесь появилась следующая запись. И мы с Вами сейчас подготовили требуемые файлы для запуска, для того, что бы мог установиться наш сервис как служба NT. Для этого нам понадобится два командных файла, либо воспользоваться командной строкой, но по сути это тоже самое. И, собственно, нам нужен сам исполняемый файл и конфигурационный файл, вы их можете скопировать из папки bin, debug своего проекта. Давайте теперь посмотрим, мы понимаем, что здесь хранится код с нашим сервисом, здесь конфигурационный файл к которому будет обращаться сервис хост, он его будет искать, потому что здесь лежит конечная точка. А вот эти два командных файла, давайте зайдем в первый файл, возьмем, скажем, его редактировать. Сейчас посмотрим, что в нем имеется. Обратите внимание, в нем имеется строка, мы обращаемся по пути C:\Windows\Microsoft.NET\Framework\v4.0.30319\installutil.exe, это как раз и есть специальный утилита, которая позволяет нам зарегистрировать наш созданный сервис в службах, где и хранятся все эти сервисы, она нам поможет поместить его сюда, в Service Control Manager. И сейчас мы выполнимся, желательно от имени администратора. Обратите внимание, The transacted install has been completed, теперь вы нажимаем любую клавишу и завершаемся. Заходим в окно с сервисами, обновляем, и посмотрим. Вот, обратите внимание, наш сервис. Он установился. Мы его можем стартануть, сейчас сделаем старт, все, он запущен, видите, он у нас выполняется. Теперь нам было бы хорошо попробовать к нему обратится. Давайте так и сделаем. Возьмем запускаем клиент в папке bin debug проекта и обращаемся к нашему сервису, пишем Hello и отправляем сообщение. Видите, он нам ответил. Вот, достаточно просто. Завершаемся. И теперь, было бы хорошо его удалить. И мы сейчас вернемся в окно с нашими командными файлами, давайте посмотрим что у нас имеется в uninstall Service NT. Видите, мы обращаемся снова же к этой утилите C:\Windows\Microsoft.NET\Framework\v4.0.30319\installutil.exe, указываем вот такой атрибут /u (uninstall), ну и соответственно тут у нас путь к нашему сервису, снова же. Ну и давайте попробуем его удалить. Выполним от имени администратора. Ждем, видите, он останавливается. Вот пожалуйста, uninstall has completed. Наш сервис мы удалили. Вот он находится, сейчас мы обновимся. Видите, да, мы удалили этот сервис. Вот такая разновидность автохостинга, NT Service. В каком случае нужно пользоваться таким автохостингом? Ну, представьте, что Ваш сервис находится, естественно, на сервере, а сервер может перегружаться. Допустим, ночью администраторы могут его перегрузить и могут просто не зайти, так сказать, не аутентифицироваться, сервер перегрузился, и никто не аутентифицировал систему. И получается, что Ваша программа окажется незапущенной. Если Вы его поместите в автозагрузку, в реестр, в реестре разместитесь, она запустится только после аутентификации пользователя, то есть когда администратор зайдет в систему, а до этого момента ничего не запустится. Вы наверно замечали, когда Вы перегружали компьютер и, например, тот же скайп. Когда он запускается? Только когда Вы заходите в систему, когда Вы ввели свой пароль, зашли в систему и вот тогда у Вас запустился скайп. А до этого он почему то не запускается, даже если какое-то время компьютер будет стоять вроде бы работающим, но Вы в систему не зашли. А вот если бы здесь был некий сервис, который запускает скайп, если бы он не просто в автозагрузке стоял, а запускался такими сервисами, то тогда он бы запустился бы сразу. То есть вот такие преимущества автохостинга в NT Service.
И теперь мы с Вами переходим к следующей разновидности хостинга – это хостинг в IIS (Internet Information Services). Будем надеяться, что все знаю про IIS, что это за инструмент. А мы с Вами рассмотрим сам алгоритм размещения службы в IIS. Для этого нам, если мы будем создавать все с самого начала, нам потребуется создать, например, папку для сервиса, назовем ее Service IIS. В папке Service IIS создадим Project IIS, в папке Project IIS создадим папку bin. Сам алгоритм размещения службы прилагается к файлам примеров, поэтому мы откроем уже готовый и посмотрим, что в нем имеется. В результате, когда Вы выполните весь алгоритм, создадите все папочки, откроете эту папку как веб сайт, то в результате у Вас откроется проект и в solution explorer отобразятся и папка bin, вот мы видим, папка bin, дальше my service, и файл Web.config. И нам останется только создать новый проект с желаемым сервисом. Вот мы создаем новый проект. Указываем в нем сервис. Сначала создаем контракт, далее создаем сервис. Далее, мы можем отбилдить проект, нажмем F6, видим что построение прошло успешно. И в файле bin, в файл bin мы должны будем скопировать Service library.dll, вот например из папки debug вот этого проекта. То есть еще раз повторюсь, что весь алгоритм размещения вот такого ручного создания полного проекта Вы найдете в описании, в текстовом файле, описание к примеру. Далее откроем MyService.svc и сюда требуется вставить вот такую строку ServiceHost и указать полное квалифицированное имя сервиса. Далее требуется открыть Web.config и в Web.config, в файл конфигурации, вставить вот такой блок. Что здесь может нас заинтересовать? Далее, уже на протяжении курса будут подробно рассматриваться все составляющие, но здесь нам понадобится сейчас вставить конечную точку, видите, вот это идет наша конечная точка, а далее мы еще вставляем mex конечную точку, она расшифровывается metadata exchange. Зачем? За тем, что такое вообще mex? По mex вообще будет отдельный урок, но в двух словах я скажу. Вот представьте, что Вы предоставляете сервис по, допустим, который предоставляет, например, котировки валют, например. И если к Вам будут все обращаться и говорить «Скиньте мне пожалуйста файлик с контрактом, интерфейсом, а я уже от него наследуюсь и буду реализовывать сервис consumer». Конечно, Вам это надоест, потому что 1000 пользователей будет к Вам обращаться за этим файлом, где-то его выкладывать тоже не очень хорошо, поэтому WCF предоставляет такую возможность, что можно автоматически запросить контракт сервиса провайдера для того, что бы на стороне consumer, на стороне пользователя, сгенерировать правильный код сервиса consumer. Вот, поэтому мы вставляем вот такой код, Вы можете отсюда его первое время копировать и вставлять, единственное корректировать соответственно конечную точку, указывать здесь тот адрес, который Вам требуется, указывать привязку, указывать соответственно контракт. Ну mex можете оставить без изменений. И теперь нам требуется собственно запустить сам IIS сервер и желательно добавить в него виртуальный каталог. Вот давайте мы это сделаем. Вот заходим, смотрим, здесь у нас имеются сайты и откроем, выберем сайт по умолчанию, и вот выберем Add Virtual Directory. И назовем например его, к примеру, My. И укажем физический путь к виртуальной директории. Выберем, вот например, папку WCF, это у нас идет второй урок, и здесь выбираем сервис, Project IIS, вот выбираем папку с проектом. Проверяем соединение, ОК. И теперь нам нужно преобразовать виртуальный каталог в приложение. Вот мы возьмем теперь и Convert to Application. Нажмем ОК. Видите, мы преобразовали его в приложение. И теперь мы можем проверить, допустим, возьмем адрес нашего сервиса, откроем его в браузере. Вот, обратите внимание, мы обратились, по сути, к нашему сервису, ну и здесь мы уже можем посмотреть как wsdl, мы его будем рассматривать дальше, вот по сути, предлагаемый класс Test, то есть эта страница показывает то, что мы с Вами получили доступ к сервису. И теперь мы можем открыть полноценный клиент и уже из-под клиента обратится к этому сервису, что бы посмотреть. Вот пожалуйста, видите, мы обратились из клиента к данному сервису. Могли бы, допустим, обратится к нему по-другому. Есть специальные утилиты, вот, WCF Test Client, и мы сейчас зайдем, откроем сервис, обратите внимание, мы здесь можем вызвать метод, и сейчас мы попробуем обратится к нашему работающему сервису. Add Service, здесь возьмем, вставим сюда нашу строку, ОК. Вот у нас произошло добавление сервиса. И теперь мы можем указать какое-нибудь значение, допустим Hello, и вызвать. Видите. То есть это идет request для сервиса, а вот это идет response, то есть наш сервис нам ответил. Где находится эта утилита? Сейчас я Вам покажу путь. У нас имеются свойства, open file location. Посмотрите пожалуйста, если Вы захотите ею воспользоваться то вот по этому пути Вы найдете утилиту WCF Test Client. Вот она. И запустив, Вы можете обращаться, по сути, к любым сервисам, но здесь важно, что бы у Вас, для работы этой утилиты Вам понадобится, что бы у Вас был подключена возможность работы с mex конечными точками. Иначе она у Вас просто не сработает, потому что, что делает эта утилита? Она на своей стороне автоматически создает такое общее, такое общего клиента, который к Вам посылает запрос, но Вы понимаете, что вот здесь должен быть, должна быть клиентская реализация требуемого контракта. И вот этот контракт, как раз и будет предоставлен по, так сказать, и mex привязкой, вот он идет IMetadataExchange, вот этот контракт.
А мы с Вами переходим еще к одному рассмотрению хостинга в IIS. И давайте снова зайдем в Visual Studio и посмотрим еще одну разновидность проектов. Снова же, алгоритм размещения. Службы IIS и создание таких проектов Вы найдете в файлах read me к проектам. Вы там можете уже вручную создать папку, например Service IIS, в ней Project IIS, в ней папку bin, в ней файл MyService.svc, открываете все как веб сайт, в результате у Вас открывается студия, в ней отображается и папка bin, и MyService.svc, и Web.config. Обратите внимание, что у нас имеется в этом проекте. Мы берем и прямо в файл svc вставляем код ан C#, мы здесь указываем и namespace, и сразу же импортируем нужное пространство имен, здесь же указываем и контракт, здесь же создаем сервис. То есть получается, что когда мы будем хостить такой проект, то любой администратор сможет зайти и поправить этот исходный код. Насколько это хорошо? Снова же, судить Вам. Если Вам требуется, что бы код был закрыт, то его требуется скомпилировать в dll библиотеку. Если же в сервисе нет ничего страшного и секретного, то… Нет ничего страшного, имею ввиду, что если кто-то посмотрит в исходные коды. То пожалуйста, Вы можете держать исходные коды открытыми. Те же манипуляции нам нужно произвести с конфигурационным файлом, то есть добавить в него как свою конечную точку, так же и конечную точку mex. Все. Этот пример отличается от предыдущего тем, что мы прямо берем в svc и вписываем голый код и теперь этот код будет доступен всем. И администраторам, и по сути, он будет лежать вместе со страницами вашего сайте. И мы можем снова же что сделать? Зайти в IIS. Зайдем в IIS, то есть нам же надо его захостить. И теперь нам здесь нужно, снова же, добавить виртуальную директорию, мы ее традиционно назовем My, выберем физический путь к папке с проектом, проверим тест с этим… все отлично, ОК. ПКМ, конвертировать в приложение, конвертировали. И теперь снова же, мы можем зайти в Internet Explorer и проверить. Возьмем сразу же подготовим путь. Вот, обратите внимание, снова же, наш сервис работает. И мы можем зайти, снова же, воспользоваться утилитой WCF Test Client, что бы проверить работоспособность сервиса. Дважды кликаем, и попробуем связаться с нашим сервисом. Напишем ему Hello, нажимаем Invoke. Вот, обратите внимание, мы смогли отправить нашему сервису, который сейчас захощен в IIS, сообщение. Вот пожалуйста, он нам ответил. Вот собственно, как найти эту утилиту Вы знаете, я уже показал ранее. Вот имеются такие способы хостинга сервиса в IIS. Но, что мы здесь делаем? Мы здесь используем транспортную схему http. А если нам понадобится, если мы захотим захостить сервис в IIS, который использует транспортную схему TCP. Вот для этого мы должны воспользоваться таким инструментом, который входит в состав IIS, как Windows Activation Services. И давайте посмотрим, как мы можем захостится при помощи WAS.
Мы зайдем в Visual Studio и посмотрим на следующею разновидность проекта. Тот же самый сервис, что у нас был. Единственное, мы теперь хотим предоставлять доступ к нашему сервису по TCP протоколу. Все тоже самое. Тот же MyService.svc. Единственное, мы в Web.config, обратите внимание, добавляем еще одну конечную точку, которая уже использует net.tcp. Все, мы можем построить решение. У нас имеется проект, имеется библиотека с сервисом и вот мы будем к ней сейчас получать доступ вот по такому адресу, к примеру. У нас имеется клиента, давайте мы сразу посмотрим в клиентский код. Обратите внимание, вот когда мы создаем channel factory, мы сразу же указываем в клиенте адреса, что мы вот будем обращаться по протоколу net.tcp. Причем, по net.tcp мы будем работать, снова же повторюсь, через IIS. Заходим в IIS, нам нужно сделать все тоже самое, что мы делали. Add virtual directory, назовем ее My, укажем физический путь. Все, здесь у нас все сработало. Конвертируем в приложение. Теперь, нам нужно войти в управление приложением, дополнительные настройки, и добавить здесь следующею строчку. Заметьте, Вам нужно будет здесь добавить обязательно без пробела, ставим запятую, пишем «net.tcp». Еще раз замечу, без пробела. Далее, мы можем взять ПКМ, так же, и здесь нам нужно сделать Edit Bindings. Обратите внимание, в этом окне у нас появляются все порты, которые используются, IP адреса и информация о привязках. Нам, в нашем случае, понадобится вот эта информация о привязках, потому что мы будем использовать net.tcp, здесь используется http. Ну, у нас мы видим, что практически все настроено. И теперь, так как мы, по сути, WAS настроили, и теперь можно взять и проверить работоспособность. Мы зайдем в наш клиент, который будет обращаться именно по такому адресу, выполнимся и посмотрим. Обратите внимание, вот у нас как раз и произошло обращение к сервису и он нам ответил. То есть сейчас мы обратились через TCP протокол. Вот, таким образом, снова же, повторюсь, через Internet Information Services мы можем использовать как транспортные схемы http, так и транспортные схемы tcp.
Давайте еще раз повторим с Вами варианты автохостинга. Помним, автохостинг у нас может быть как в консоли, как в Windows Forms, как в WPF. Мы помним, что у нас автохостинг использует форму как синглетную службу, помните этот слайд, синглетная служба. Вот, представляете, что это наша форма. Далее, мы можем просто специально обращаться напрямую в форму, получая ссылку на форму. Далее мы рассмотрели с Вами хостинг в NT Service, в Windows службах, рассмотрели хостинг в чистом IIS с использованием транспортной схемы http, и так же рассмотрели хостинг WAS, то есть если мы хотим воспользоваться транспортной схемой TCP.
И на этом наш урок закончен. Спасибо за внимание! С Вами был Александр Шевчук. До новых встреч на ITVDN!