Windows Communication Foundation (WCF) — программный фреймворк, используемый для обмена данными между приложениями, входящий в состав .NET Framework. Другим словами, WCF – это программная платформа от Microsoft для создания, настройки и развертывания распределенных сетевых сервисов.

Давайте рассмотрим процесс создания и вызова службы WCF.

Подпишись на группу Вконтакте и Телеграм-канал. Там еще больше полезного контента для программистов.

А на  YouTube-канале ты найдешь обучающие видео по программированию. Подписывайся!

Создание службы WCF

Для начала необходимо создать новый проект WCF. Пусть наша Windows Communication Foundation служба будет возвращать количество оставшихся дней до нового года.

Visual studio создаст интерфейс и класс службы по умолчанию с именем IService1.cs и Service1.svc.

Нам необходимо переименовать их в соответствии с нашей предметной областью.

Давайте рассмотрим интерфейс INewYearService. Для начала нам необходимо в теле интерфейса объявить метод, который будет предоставлять служба для вызова. Для этого его необходимо пометить атрибутом [OperationContract].

using System;
using System.ServiceModel;
 
namespace NewYearService
{
    /// <summary>
    /// Интерфейс, определяющий методы, которые предоставляет служба.
    /// </summary>
    [ServiceContract]
    public interface INewYearService
    {
        /// <summary>
        /// Получить  количество времени до нового года от указанной даты.
        /// </summary>
        /// <param name="start">Дата от которой ведется отсчет до нового года.</param>
        /// <returns>Временные промежутки до нового года.</returns>
        [OperationContract]
        TimeToNewYear GetDaysToNewYear(DateTime start);
    }
}

Как вы видите данный метод возвращает экземпляр класса TimeToNewYear. Это вспомогательный класс, содержащий значения времени до нового года. Ниже приведена его структура. Для того, чтобы данный класс можно было использовать в качестве возвращаемого аргумента, его необходимо пометить атрибутом [DataContract], а свойства, доступные для чтения клиенту в возвращаемом значении помечаются атрибутом [DataMember].

using System;
using System.Runtime.Serialization;
 
namespace NewYearService
{
    /// <summary>
    /// Класс, содержащий временные промежутки до нового года.
    /// </summary>
    [DataContract]
    public class TimeToNewYear
    {
        /// <summary>
        /// Момент времени, от которого отсчитывается время.
        /// </summary>
        private DateTime _start;
 
        /// <summary>
        /// Дата нового года.
        /// </summary>
        private DateTime _newYear;
 
        /// <summary>
        /// Количество дней до нового года.
        /// </summary>
        [DataMember]
        public int Days { get; private set; }
 
        /// <summary>
        /// Количество часов до нового года.
        /// </summary>
        [DataMember]
        public int Hours { get; private set; }
 
        /// <summary>
        /// Количество минут до нового года.
        /// </summary>
        [DataMember]
        public int Minutes { get; private set; }
 
        /// <summary>
        /// Количество секунд до нового года.
        /// </summary>
        [DataMember]
        public int Seconds { get; private set; }
 
        /// <summary>
        /// Создать новый экземпляр отсчета времени до нового года.
        /// </summary>
        /// <param name="point">Момент времени, от которого ведется отсчет.</param>
        public TimeToNewYear(DateTime point)
        {
            _start = point;
            _newYear = DateTime.Parse($"{point.Year}-12-31 23:59:59.999");
            SetPeriods();
        }
 
        /// <summary>
        /// Метод устанавливающий временные промежутки до нового года.
        /// </summary>
        private void SetPeriods()
        {
            var interval = _newYear - _start;
            Days = (int)interval.TotalDays;
            Hours = (int)interval.TotalHours;
            Minutes = (int)interval.TotalMinutes;
            Seconds = (int)interval.TotalSeconds;
        }
    }
}

Теперь нам остается реализовать интерфейс Windows Communication Foundation службы в классе NewYearService.svc.cs следующим образом:

using System;
 
namespace NewYearService
{
    /// <summary>
    /// Класс службы реализующий интерфейс взаимодействия со службой.
    /// </summary>
    public class NewYearService : INewYearService
    {
        /// <summary>
        /// Получить  количество времени до нового года от указанной даты.
        /// </summary>
        /// <param name="start">Дата от которой ведется отсчет до нового года.</param>
        /// <returns>Временные промежутки до нового года.</returns>
        public TimeToNewYear GetDaysToNewYear(DateTime start)
        {
            var timeToNewYear = new TimeToNewYear(start);
            return timeToNewYear;
        }
    }
}

Давайте проверим работу нашей службы wcf. Для этого нажмем кнопку Начать отладку. Обратите внимание, что возможные два варианта поведения системы. Если мы начнем отладку находясь в NewYearService.svc, от откроется отладчик службы. Во всех остальных случаях откроется окно браузера. Давайте рассмотрим каждый из вариантов подробнее.

Браузер

После запуска отладки отобразится браузер с файловой структурой нашей службы wcf.

Нам необходимо нажать на ссылку с именем нашей службы NewYearService.svc. Если все работает корректно, то мы увидим следующее окно, иначе будет показано сообщение с ошибкой.

Просмотр wcf службы в браузере

Тестовый клиент WCF

В левой верхней части отладчика можно увидеть структура нашей службы wcf. Для проверки нашего метода выполним двойной щелчок левой кнопкой мыши по его имени. В правой части отладчика откроется форма запроса. Мы можем указать значение, которое будет передано в метод.

После установки передаваемых значений необходимо нажать кнопку Вызвать. Появится предупредительное сообщение. Можно смело ставить галочку Не выводить это сообщение в дальнейшем и нажимать кнопку ОК.

После этого в нижней правой части отладчика будет отображены значения возвращаемые нашей службой wcf.

обзор службы wcf

Консольный клиент для WCF

Теперь нам необходимо создать клиент, который будет обращаться к нашей службе wcf. Для этого для начала создадим новое консольное приложение.

В созданном консольном приложении нам необходимо добавить ссылку на службу wcf.

В открывшимся окне службы необходимо указать имя службы wcf и ввести ее адрес.

Для простоты можно нажать кнопку Найти, тогда адрес службы wcf будет определен автоматически.

После этого необходимо развернуть дерево Windows Communication Foundation службы, чтобы удостоверится что выбран правильность выбора. В правой части должен быть отображен вызываемый метод.

Если настройка прошла корректно, то в обозревателе решения в консольном приложении отобразится ссылка на нашу службу wcf.

Теперь нам остается только обратиться к нашей службе, чтобы взывать метод и вывести результат на экран.

using NewYearServiceCmdClient.NewYearService;
using System;
 
namespace NewYearServiceCmdClient
{
    class Program
    {
        static void Main(string[] args)
        {
            // Создадим клиент для обращения к службе.
            var client = new NewYearServiceClient();
 
            // Вызовем метод службы и сохраним результат.
            var result = client.GetDaysToNewYear(DateTime.Now);
 
            // Выводим результат на консоль.
            Console.WriteLine($"До нового года осталось {result.Days} дней, или {result.Hours} часов, или {result.Minutes} минут, или {result.Seconds} секунд.");
            Console.ReadKey();
        }
    }
}

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

Web клиент для WCF

Теперь рассмотрим, как нам обратиться к службе wcf из веб-приложения. Процесс подключения службы не отличается от подключения в консольном приложении. Давайте рассмотрим как можно настроить авторизацию с помощью Windows. Это потребует дополнительной настройки приложения. Для начала создадим проект нового MVC приложения.

Нажимаем кнопку ОК, и попадаем в меню настройки создания веб-приложения. Выберем MVC шаблон и изменим способ авторизации. Для этого нажмем на кнопку Изменить способ проверки подлинности.

Выбираем авторизацию с помощью Windows и нажимаем ОК в обоих окнах.

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

Для того, чтобы IISExpres перестала ругаться на нас за попытку создания windows-аутентификации нужно сделать ряд действий в наше службе.

Нужно дополнить наш web.config

Добавляем в любую точку раздела <configuration>, если отсутствует раздел webServer или дополняем уже существующий.

<system.webServer>
    <security>
      <authentication>
        <windowsAuthentication enabled="true" />
      </authentication>
    </security>
</system.webServer>

Находим раздел <system.web> и в нем вставляем следующее.

<authentication mode="Windows"></authentication>
<authorization>
      <allow users="domen\"/> //каких пользователей пускать
     <!--<deny users="*"/>--> //запрет пользователей
</authorization>

Далее нужно указать разделы биндинг и сервис

<bindings>
      <basicHttpBinding>
        <binding name="BasicHttpEndpoinBinding">
          <security mode="TransportCredentialOnly">
            <transport clientCredentialType="Windows" />
          </security>
        </binding>
      </basicHttpBinding>
</bindings>
<services>     
      <service name="Имя сервиса">       
        <endpoint address=""
                  binding="basicHttpBinding"
                  bindingConfiguration="BasicHttpEndpoinBinding"
                  name="BasicHttpEndpoint"
                  contract="Интерфейс в сервисе (выпадет само)">
          <identity>
            <dns value="localhost"/>
          </identity>       
        </endpoint>
        <endpoint address="mex"
                  binding="mexHttpBinding"
                  contract="IMetadataExchange"/>
      </service>
</services>

Раздел <serviceBehavior><behavior> дополняем такой вот строчкой. В ней мы говорим, что именно такая схема аутентификации будет использоваться у нас.

<serviceAuthenticationManager authenticationSchemes="Negotiate"/>

На этом настройка web.config заканчивается. В итоге у нас должен получиться файл примерно следующего содержания.

<?xml version="1.0" encoding="utf-8"?>
<configuration>
 
  <appSettings>
    <add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
  </appSettings>
  <system.web>
    <compilation debug="true" targetFramework="4.6.1" />
    <httpRuntime targetFramework="4.6.1"/>
    <authentication mode="Windows"></authentication>
    <authorization>
      <allow users="*"/> <!-- Каких пользователей пускать (при необходимости можно указать домен в формате domen\*) -->
      <!--<deny users="*"/>--> <!-- Запрет пользователей -->
    </authorization>
  </system.web>
  <system.serviceModel>
    <bindings>
      <basicHttpBinding>
        <binding name="BasicHttpEndpoinBinding">
          <security mode="TransportCredentialOnly">
            <transport clientCredentialType="Windows" />
          </security>
        </binding>
      </basicHttpBinding>
    </bindings>
    <services>      
      <service name="NewYearService.NewYearService">        <!-- Имя сервиса -->
        <endpoint address=""
                  binding="basicHttpBinding"
                  bindingConfiguration="BasicHttpEndpoinBinding"
                  name="BasicHttpEndpoint"
                  contract="NewYearService.INewYearService"> <!-- Интерфейс в сервисе (выпадет само) -->
          <identity>
            <dns value="localhost"/>
          </identity>        
        </endpoint>
        <endpoint address="mex"
                  binding="mexHttpBinding"
                  contract="IMetadataExchange"/>
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior>
          <!--Чтобы избежать раскрытия метаданных, до развертывания задайте следующим параметрам значение "false". -->
          <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
          <!-- Чтобы при сбое получать подробные сведения об исключении для целей отладки, установите для нижеприведенного параметра значение true.  Перед развертыванием установите значение false, чтобы избежать раскрытия информации об исключении -->
          <serviceDebug includeExceptionDetailInFaults="false"/>
          <!-- Говорим, что именно такая схема аутентификации будет использоваться у нас. -->
          <serviceAuthenticationManager authenticationSchemes="Negotiate"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <protocolMapping>
        <add binding="basicHttpsBinding" scheme="https" />
    </protocolMapping>    
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
  </system.serviceModel>
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>
    <directoryBrowse enabled="true"/>
    <security>
      <authentication>
        <windowsAuthentication enabled="true" />
      </authentication>
    </security>
  </system.webServer>
</configuration>

Настройка applicationhost.config

Далее идем в папку vs нашего проекта (она скрыта по умолчанию). В ней ищем папку config, а уже в ней находим файл applicationhost.config, его то нам нужно будет поправить.

Находим вот такой раздел. Все Deny меняем на Allow, разрешая изменение установленного по умолчанию режима аутентификации.

<sectionGroup name="authentication">
    <section name="anonymousAuthentication" overrideModeDefault="Deny" />
    <section name="basicAuthentication" overrideModeDefault="Deny" />
    <section name="clientCertificateMappingAuthentication" overrideModeDefault="Deny" />
    <section name="digestAuthentication" overrideModeDefault="Deny" />
    <section name="iisClientCertificateMappingAuthentication" overrideModeDefault="Deny" />
    <section name="windowsAuthentication" overrideModeDefault="Deny" />
</sectionGroup>

Далее находим данную настройку. В ней false меняем на true, разрешая механизму работать.

<windowsAuthentication enabled="false">
    <providers>
        <add value="Negotiate" />
        <add value="NTLM" />
    </providers>
</windowsAuthentication>

И под конец находим вот эту настройку. Тут мы true меняем на false. Говоря нашему IISExpres, чтобы он не блокировал службу windows-аутентификации.

<add name="WindowsAuthenticationModule" lockItem="true" />

После этого сохраняем все конфигурационные файлы и пробуем сделать ссылку на службу wcf аналогично как при добавлении службы в консольное приложение.

Изменим контроллер главной страницы web-приложения, чтобы взывать нашу службу wcf.

using NewYearServiceWebClient.NewYearService;
using System;
using System.Web.Mvc;
 
namespace NewYearServiceWebClient.Controllers
{
    /// <summary>
    /// Контроллер домашних страниц.
    /// </summary>
    public class HomeController : Controller
    {
        /// <summary>
        /// Главная страница.
        /// </summary>
        /// <returns>Представление главная страница.</returns>
        public ActionResult Index()
        {
            // Создадим клиент для обращения к службе.
            var client = new NewYearServiceClient();
 
            // Вызовем метод службы и сохраним результат.
            var result = client.GetDaysToNewYear(DateTime.Now);
 
            // Помещаем результат в представление.
            ViewBag.DaysToNewYear = result;
 
            return View();
        }
 
        /// <summary>
        /// О программе.
        /// </summary>
        /// <returns>Представление о программе.</returns>
        public ActionResult About()
        {
            ViewBag.Message = "Тестовое приложение для работы с WCF в MVC.";
 
            return View();
        }
 
        /// <summary>
        /// Контактные данные.
        /// </summary>
        /// <returns>Представление контакты.</returns>
        public ActionResult Contact()
        {
            ViewBag.Message = "Your contact page.";
 
            return View();
        }
    }
}

Теперь нам осталось только изменить представление, чтобы вывести результат работы Windows Communication Foundation службы на экран пользователя.

@{
    ViewBag.Title = "Главная";
}
 
<div class="jumbotron">
    <h1>Использование WCF в MVC</h1>
    <p class="lead">Чтобы подробнее узнать о том, как создавать WCF службы и использовать их в MVC приложениях нажмите на кнопку.</p>
    <p><a href="https://shwanoff.ru/wcf/" class="btn btn-primary btn-lg">Узнать больше &raquo;</a></p>
</div>
 
<div class="row">
    <div class="col-md-3">
        <h2>Количество Дней до нового года</h2>
        <p>@ViewBag.DaysToNewYear.Days</p>
    </div>
    <div class="col-md-3">
        <h2>Количество Часов до нового года</h2>
        <p>@ViewBag.DaysToNewYear.Hours</p>
    </div>
    <div class="col-md-3">
        <h2>Количество Минут до нового года</h2>
        <p>@ViewBag.DaysToNewYear.Minutes</p>
    </div>
    <div class="col-md-3">
        <h2>Количество Секунд до нового года</h2>
        <p>@ViewBag.DaysToNewYear.Seconds</p>
    </div>
</div>

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

wcf mvc web app

Итоги WCF

Исходный код приложения можно скачать из репозитория https://github.com/shwanoff/wcf.

Мы подробно рассмотрели процесс создания и настройки Windows Communication Foundation службы, а также продемонстрировали как можно подключится к wcf через консольное и веб-приложение. Также рекомендую прочитать статью Принципы SOLID C#. И не забудьте подписывайтесь на группу ВКонтакте, Telegram и YouTube-канал. Там еще больше полезного и интересного для программистов.


shwan

Программист .NET