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

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

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

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

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;
        }
    }
}

Теперь нам остается реализовать интерфейс службы в классе 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;
        }
    }
}

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

Браузер

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

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

Тестовый клиент 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 клиент

Теперь рассмотрим, как нам обратиться к службе из веб-приложения. Процесс подключения службы не отличается от подключения в консольном приложении. Давайте рассмотрим как можно настроить авторизацию с помощью 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" />

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

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

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();
        }
    }
}

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

@{
    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>

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

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

Присоединяйтесь к социальным сетям:

 
×
%d такие блоггеры, как: