Andriy Shyrokoryadov

.Net developer, data scientist

Краткий обзор услуг (сервисов) WCF Windows Communication Foundation

Текст к видео "Краткий обзор услуг (сервисов) WCF" на канале YouTube

Всем привет. Сегодня нестандартное видео. По нескольким причинам. Речь идет об услугах, даже можно сказать о микроуслуге или о микроуслугах. Но с использованием относительно старой технологии. Не знаю, как вы себе представляли работу в сфере IT, но я до того, как начал профессионально программировать представлял себе работу программиста следующим образом. Получаешь задание и начинаешь писать код, то есть, по сути, делаешь то, что мы все любим – кодишь. И этот цикл продолжается до бесконечности: задание – код - релиз, задание – код – релиз. Как вы уже поняли – я ошибался. Когда я пришел на свою первую работу, то оказалось, что всё уже было написано и запрограммировано до меня. Моей задачей было, собственно, поддержание этого относительно старого приложения, если быть более точным – приложения, основанном на архитектуре микроуслуг. То есть я писал новые функциональности редко. В основном я должен был исправлять ошибки других программистов, а если что-то не работало, то сваливать вину на предшественников. Шутка. Мне кажется, что большинство программистов сталкивается с этой проблемой – проекты старые, написанные криво, тяжело исправлять. Напишите в комментариях о вашей первой работе? Какие были ощущение? Оправдались ли ваши ожидания и была ли конфронтация ваших ожиданий с суровой реальностью? Мне будет интересно почитать. Да, я думаю не только мне, зрителям канала также будет интересно узнать, что можно ожидать от работы в IT.

Что следует из данной ситуации? Из этой ситуации следует, что пока из каждого утюга нам гласят, какой продуктивный и классный фреймворк Asp.Net Core, большинство приложений, которыми мы пользуемся, например в банках, написаны с использованием уже относительно старых технологий. Таких приложений очень много, и никто не будет переписывать их на .Net Core. Такие приложения необходимо дальше обслуживать. Если вам очень не повезло, то вы можете попасть на проект, где еще используются услуги ASMX. Я работал с этими услугами на моей первой работе в IT, но не могу сказать, что я их знаю хорошо. Из того что я помню, это определенный вид услуг, написанный с использованием фреймворка .Net Framework. Сама услуга использует в качестве хоста сервер IIS, то есть услугу можно разместить на серверах с операционной системой Windows. С услугой можно взаимодействовать, отправляя запросы и получая ответы по протоколу SOAPsimple object access protocol, то есть протокол доступа простых объектов. Или как-то так. Достаточно часто можно встретить микросервисные приложения, которые основаны на услугах WCF. И это главная тема сегодняшнего видео.

Как правило если в компании, куда вы пришли на собеседование на позицию программист, используют услуги на основании технологии WCF, то на собеседовании вам могут задать пару вопросов на эту тему. Нет смысла искать в интернете список вопросов по WCF, потому что даже если такой список и существует, то никто не проводит собеседования только и исключительно на программиста услуг WCF. Однако быть готовым к паре вопросов на эту тему все-таки стоит и необходимо иметь общее понимание, как работают данные услуги. Тематика услуг достаточно широка – моя книга на эту тему насчитывает около 600 страниц. Сложно ожидать, что во время такого короткого видео на эту тему, вы сразу сможете сесть и написать услугу с использованием этой технологии. Однако я уверен, что после просмотра данного видео у вас будет понимание, какие преимущества имеют услуги WCF по сравнению с услугами ASMX, а также в чем услуги WCF уступают услугам .Net Core. Также мы познакомимся с практическими примером услуги WCF и 2 клиентами: один клиент будет на основании автоматически сгенерированного кода и второй клиент будет создан с использованием синтаксиса языка C#.

Что послужило причиной появления услуг WCF? Если мы посмотрим на предшественника этой технологии, то есть на услуги ASMX, то мы увидим, что услуги ASMX можно было размещать только на сервере IIS, что не всегда было удобно. В этом контексте услуги WCF можно назвать услугами ASMX на стероидах. Хостом приложения услуги WCF может быть любое приложение, написанное с использованием .Net Framework. Например, это может быть обычное консольное приложение, которое получает и обрабатывает запросы или приложение услуг Windows. То есть вы не ограничены сервером IIS.

Также, если сравнивать услугу ASMX с услугой WCF, WCF имеет больше возможностей передачи информации различными протоколами. Услуги ASMX работают только с протоколом HTTP. В свою очередь услуга WCF может работать с протоколами HTTP, TCP, MSMQ, а также с именованными каналами.

Я думаю, такой информации о преимуществах услуг WCF над услугами ASMX будет достаточно на данном этапе. С другой стороны, услуги WCF нельзя назвать современной технологией, и они постепенно уступают место услугам .Net Core. Я вижу здесь несколько причин.

  1. Первая причина – это кросс платформенность .Net Core. Мы как и прежде можем размещать нашу услугу .Net Core в консольном приложении либо на сервере IIS, а дополнительно эта же услуга может работать в системах Linux и MacOS.
  2. Вторая причина – это сложность конфигурации услуг WCF. Когда мы будем рассматривать пример вы увидите сколько настроек необходимо определить, чтобы запустить столь небольшую услугу.
  3. Третья причина – это взаимодействие между услугами. Для того чтобы объект можно было передать в услугу WCF или получить из услуги WCF, он должен иметь определенный тип в определенном пространстве имён. Иногда из-за этого возникают сильные зависимости между кодом услуги и кодом клиента, а как мы знаем из видео на тему паттернов проектирования, мы не любим сильные зависимости в коде. В случае услуг .Net Core мы по факту отправляем текстовые данные в формате JSON и получаем обратно данные в этом формате. Нет привязки к конкретным типам.

Теперь к самой услуге WCF. Обычно на моих собеседованиях я задаю вопрос какие существует 3 необходимых элемента, чтобы задекларировать или создать услугу WCF? Я объясню почему именно этот вопрос. Дело в том, что если человек работал с услугами WCF, неважно как долго или на сколько тесно, то скорей всего он будет знать ответ на этот вопрос. А даже если не работал на практике, то в каждой книге на тему WCF эти 3 элемента всегда описываются. Если человек хотя бы читал книгу на данную тему, то это уже хорошо. Лучше, чем ничего. То есть это своего рода дополнительная проверка если кандидат ранее ответил «Да, да, я работал с услугами WCF». Если во время развития дискуссии на тему его работы с услугами WCF кандидат не в состоянии назвать эти 3 элемента, то есть повод сомневаться в правдивости его слов об опыте работы с WCF. Так что же это за элементы? Это так называемое ABC услуги WCF. Сокращение, которое состоит из первых букв трёх английский слов: Address, Binding, Contract. То есть на русском: адрес, второе слово переводится как «связывание», и третье слово в переводе не нуждается – это контракт.

Остановимся на каждом из этих элементах. С адресом всё понятно – хочешь воспользоваться услугой, адрес — это первое, о чем необходимо спросить. Binding или связывание – это по сути способ, каким образом данные передаются в услугу и возвращаются из услуги. В документации Microsoft датированной сентябрём 2021 года определяется 5 видов связывания: каждый из видов имеет преимущества или недостатки, является более сложным или менее сложным. В нашем примере, который вы увидите через несколько минут, мы будем использовать самый простой тип связывания, то есть BasicHttpBinding. То есть связывание по протоколу HTTP. Что касается контракта, то с программной точки зрения, то есть с перспективы кода, контракт – это определённый интерфейс C#, который определяет функциональность услуги WCF. Проще говоря это интерфейс, который описывает, что услуга умеет делать и какие методы можно выполнить на сервере при помощи данной услуги. Возможно, сейчас эти 3 понятия звучат абстрактно, но давайте посмотрим наконец то на пример кода с использованием услуги WCF и всё станет более понятным.

Я подготовил 4 проекта для примера. 3 проекта находятся в одном решении и 1 проект находится в отдельном решеном. Я объясню позже в процессе работы приложения почему я так сделал. Итак, рассмотрим первое решение, в котором у нас 3 проекта.

Первый проект, на который стоит обратить внимание это проект CalculatorService.Model. Хотя в названии этот проект имеет слово Service в нём нет ничего, что связано с услугой WCF. В этом проекте определены несколько интерфейсов и дана имплементация двух из этих интерфейсов. Обратим внимание на 2 интерфейса IСalculator и ILoggingCalculator. Оба интерфейса декларируют 2 метода: добавить и вычесть. Разница между интерфейсами сводится к тому, что в интерфейсе IСalculator мы используем простой тип decimal, а в интерфейсе ILoggingCalculator используются 2 сложных типа, которые реализуют интерфейсы IСalulatorRequest и ICalulatorResponse для аргументов и возвращаемых значений методов соответственно. Реализации этих двух интерфейсов для аргументов и возвращаемых значений уже определены классами CalculatorRequest и CalculatorResponse. По сравнению со стандартной декларацией интерфейса наши интерфейсы IСalculator и ILoggingCalculator имеют дополнительные атрибуты:

  • Атрибут ServiceContract означает что данный интерфейс будет использоваться в качестве контракта услуги, то есть это элемент C сокращения ABC, о котором мы говорили ранее.
  • Атрибут OperationContract определяет, что данный метод будет доступен в услуге. Не все методы, которые мы задекларируем в интерфейсе – контракте, должны обязательно быть доступны в услуге. То есть методы, которые не будут обозначены данным атрибутом, не будет доступны в услуге WCF, хотя они и указаны в контракте.
  • Атрибут ServiceKnownType – этот атрибут используется только в интерфейсе ILoggingCalculator. В этом интерфейсе мы используем сложные типы, которые реализуют определенные интерфейсы. Услуга WCF при обработке запроса по контракту ILoggingCalculator будет пытаться создать объекты, которые реализуют интерфейсы IСalulatorRequest и ICalulatorResponse. Без нашей помощи услуга не сможет их создать. Потому что она не знает, как создать объект, который бы имплементировал, например, интерфейс IСalulatorRequest. Поэтому при помощи атрибута ServiceKnownType мы информируем услугу WCF о типах, которые иплементируют соответствующие интерфейсы. Класс СalulatorRequest имплементирует IСalulatorRequest, а класс CalculatorResponse, в свою очередь, имплементирует ICalulatorResponse.

Давайте сейчас посмотрим на эти классы. Оба класса в своих декларациях имеют специфические атрибуты:

  • Атрибут DataContract определяет, что данный класс может быть сериализован стерилизатором DataContractSerializer. Не помню, было ли у меня на канале видео на тему сериализации и десериализации, но скажу только, что сериализация — это процесс перевода структуры данных в последовательность байтов. Обратной к операции сериализации является операция десериализации то есть создание структуры данных из байтовой последовательности. По сети к услуге и от услуги WCF нам передается последовательность байтов. Чтобы передать объект в услугу его надо преобразовать в последовательность байтов, то есть сериализовать. Чтобы получить объект из байтов, которые содержатся в ответе услуги, данные байты информации необходимо десериализовать. В случае услуг WCF этим процессом занимается сериализатор DataContractSerializer.
  • Атрибут DataMember определяет что данное свойство класса подлежит сериализации и десериализации. Из этого можно сделать вывод, что не все свойства класса могут быть сериализованы, а только те, которые отмечены атрибутом DataMember.

Подведем итог: в проекте CalculatorService.Model содержаться несколько интерфейсов и классов, которые определяют контракт услуги WCF, а также данные, которые мы можем передавать в услугу и получать из услуги. Этот проект — это библиотека, которая будут использоваться как сервером услуги, так и её клиентами.

Теперь давайте посмотрим на сервер нашей услуги – проект CalculatorServiceWCF. Данный проект содержит ссылку на проект CalculatorService.Model. Два класса которые мы видим – это CalculatorService и LoggingCalculatorService. Вы, наверное, уже заметили, что данные классы – это имплементации интерфейсов – контрактов IСalculator и ILoggingCalculator. То есть эти классы, будут нашими рабочими лошадками, которые возьмут на себя груз обработки запроса, который был отправлен к нашей услуге. Касалось бы, в этом проекте всё просто – 2 класса – реализации контрактов и вперед. Можно запускать приложение. Но не тут было. Мы должны услугу WCF настроить. И тут, собственно, начинаются палки в колесах. Давайте посмотрим на файл App.config. Хорошо, что этот файл генерируется автоматически при создании приложения услуги WCF из шаблонов Visual Studio. Однако даже этот файл по умолчанию впечатляет. Давайте ознакомимся с ним более подробно:

  • Узел system.serviceModel – здесь сосредоточена конфигурациях наших услуг WCF. В нашем конкретном примере он содержит 2 узла – services и behaviors.
  • Узел services– здесь содержаться конфигурации отдельных услуг. Это означает, что в рамках одного приложения может быть определено несколько услуг.
  • Узел service имеет атрибут имя, то есть name, это название класса, который реализует контракт услуги WCF. Обратите внимание, что дано полное название класса, то есть с пространством имён.
  • Узел endpoint содержит 3 атрибута: адрес, связывание и контракт. Что-то мы об этом уже слышали в начале видео. В данном случае звездочка в атрибуте адрес означает, что будет использован адрес из узла host. Связывание определено, как basicHttpBinding – самое простое из доступных в услугах WCF. Контракт определен при помощи интерфейса с полным названием.
  • У нас определен еще один узел endpoint – этот узел служит для того, чтобы по адресу услуги можно было получить данные относительно услуги: какие методы она обслуживает и как создать клиента такой услуги. Для чего это надо мы узнаем при рассмотрении следующего проекта – автоматически сгенерированного клиента услуги.
  • Узел host – здесь настраиваются параметры нашего сервера. Как Вы видите мы определили здесь только адрес нашего сервера.
  • Следующий узел service содержит такие же настройки, как и первый, только для контракта ILoggingCalculator, который будет доступен по другому адресу.
  • В узле behaviors содержатся настройки «поведения» услуги. Конкретно у нас первая настройка определяет можем ли мы получить данные об услуге в нашем браузере, а вторая настройка позволяет нам получить либо скрыть более детальные данные об ошибке.

Третьим проектом, который мы рассмотрим сегодня, будет проект CalculatorService.Client задекларированный в отдельном решении. В этом проекте код клиента услуги WCF создан автоматически на основании данных, которые предоставляет услуга. Это легкий метод быстрого добавления клиента. В данный момент код клиента услуги уже готов к использованию. Далее я удалю ссылки на услуги, которые вы можете видеть в ссылках проекта в папке ConnectedServices – подключенные услуги – и добавлю эти услуги еще раз, чтобы вы увидели, как это происходит.

В самом коде клиента не происходит ничего не обычного – создаются 2 клиента: CalculatorClient и LoggingCalculatorClient. Обратите внимание как задекларированы эти два класса. Мы видим, что эти 2 класса действительно были созданы автоматически – об этом свидетельствует комментарий вверху файла. Далее на каждом из объектов клиентских классов мы выполняем операция суммы и вычитания. Результат операции выводится на экран консоли.

Второй клиентский проект называется CalculatorService.Client2. Он определен в том же решении, что и услуга. Также он отличается от первого клиентского проекта тем, что здесь мы не использовали автоматически сгенерированный код, а создали объекты клиентов самостоятельно. Давайте посмотрим на этот код поближе. Логика и схема создания для обоих клиентов одинакова. Первое что мы декларируем – это связывание или на английском binding. Мы создаем здесь программно связывание типа BasicHttpBinding. Далее мы создаем пункт доступа услуги с адресом. Эти 2 объекта буду использоваться для создания фабрики каналов. По каналу, созданному в данной фабрике, будут передаваться данные. Обратите внимание, что фабрика каналов реализует интерфейс IDisposable, а это значит можно, а даже нужно, использовать инструкцию using. Если присмотреться к коду и попытаться понять, что он делает, то можно увидеть, что фабрика каналов возвращает некоторый объект, который реализует интерфейс контракта услуги. При помощи этого объекта мы можем взаимодействовать с услугой. И как мы видим мы выполняем операции сложения и вычитания, а результат выводим на экран консоли. Для услуги с контрактом IloggingCalculator мы выполняем те же самые действия, только используем другой интерфейс.

Давайте подведём некоторые итоги. В начале видео я как бы намекал, что технология WCF может считаться старой. Однако в процессе данного видео я пришел к выводу, что данная технология всё еще актуальна, Microsoft обновляет документацию по WCF, существует еще большое количество приложений, которые основаны на услугах WCF. Просто Asp.Net Core сейчас более популярен и на слуху, но это абсолютно не значит, что WCF чем-то хуже. Просто у каждой из технологий есть своя область применения. Если это видео показалось вам интересным и полезным, дайте мне об этом знать в комментариях, ставьте лайк и подписывайтесь на канал, если вы еще не подписаны. Спасибо за внимание и до новых встреч.

Пример кода из видео на GitHub

Для открытия файла проекта необходимо Visual Studio 2019 или Visual Studio 2017. Visual Studio должно быть запущено с правами администратора.