Pull to refresh

Простой пример использования WCF в Visual Studio 2010. Часть 1

Reading time 10 min
Views 95K
Original author: Dennis van der Stelt
Вас ожидают две части:



Прошло много времени с тех пор, как я написал оригинальный пост Простой пример использования WCF. Это было еще до выхода Visual Studio 2008, и с тех пор многое изменилось. Поскольку множество людей по-прежнему задают вопросы в комментариях к тому посту, давайте посмотрим, что в настоящее время мы должны сделать, чтобы поднять и запустить службу (service), а также обратиться к ней из клиентского приложения.

На этот раз мы начнем со сборки библиотеки классов (class library assembly — DLL), и ещё мы разместим службу внутри консольного приложения. Клиент снова будет использовать приложение Windows Forms. Хотя мы делаем всё в Visual Studio 2010, многое применимо также и к VS2008. Я буду упоминать, когда это будет не так и буду предлагать альтернативный вариант. В этот раз я буду немного подробней описывать то, что мы должны сделать, так что этот пост будет немного больше, чем оригинальный.

Создание проекта


Сначала создайте новую библиотеку классов, где мы определим саму службу. Выберите New Project и Class Library в качестве шаблона проекта. Укажите название проекта «EmailService» и имя решения «WCFSimpleExample2010». Если вы не можете установить имя решению, проверьте, выбрана ли опция Create directory for solution.



Создание контракта


Cначала мы создадим контракт только с одним методом, или операцию, как их называют в WCF. Переименуйте файл в IEmailValidator.cs и создайте интерфейс с таким же именем.
Теперь добавьте сигнатуру метода ValidateAddress, который принимает один аргумент EmailAddress типа string и возвращает булево значение. Это обычный интерфейс, ничего сложного.
  1. public interface IEmailValidator
  2. {
  3.     bool ValidateAddress(string emailAddress);
  4. }
* This source code was highlighted with Source Code Highlighter.

Теперь мы должны сообщить WCF, что это наш контракт. Мы делаем это путем добавления атрибутов, но сначала мы должны добавить ссылку на System.ServiceModel. Щелкните правой кнопкой мыши по проекту и выберите пункт Add reference, затем выберите System.ServiceModel из списка. Я использую Visual Studio 2010 Pro Power Tools, так что моё изображение на скриншоте может отличаться от вашего, но идея та же.





Теперь вы можете добавить атрибуты к интерфейсу. Выше определения интерфейса поместите атрибут ServiceContract, а над операцией – атрибут OperationContract. Добавьте директиву using System.ServiceModel в самом начале файла с кодом, или пусть Visual Studio сделает это за вас, когда вы наведёте курсор на одно из имён атрибутов. Если вы ввели его правильно и с учетом регистра, можно нажать CTRL +. и тогда появится контекстное меню, которое позволит добавить директиву using автоматически. В итоге ваш интерфейс должен выглядеть следующим образом:
  1. [ServiceContract]
  2. public interface IEmailValidator
  3. {
  4.     [OperationContract]
  5.     bool ValidateAddress(string emailAddress);
  6. }
* This source code was highlighted with Source Code Highlighter.


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


Теперь, когда мы создали контракт, мы должны написать код для службы, чтобы на самом деле сделать то, что мы хотим сделать. Создайте новый класс, реализующий интерфейс. Мы будем использовать регулярное выражение для проверки адреса электронной почты и в случае его корректности возвращать значение true. Вы должны либо набрать что-то вроде следующего кода, либо написать свой собственный. :-)
  1. public class EmailValidator : IEmailValidator
  2. {
  3.     public bool ValidateAddress(string emailAddress)
  4.     {
  5.         Console.WriteLine("Validating: {0}", emailAddress);
  6.         
  7.         string pattern = @"^([0-9a-zA-Z]([-.\w]*[0-9a-zA-Z])*@(([0-9a-zA-Z])+([-\w]*[0-9a-zA-Z])*\.)+[a-zA-Z]{2,9})$";
  8.         return Regex.IsMatch(emailAddress, pattern);
  9.     }
  10. }
* This source code was highlighted with Source Code Highlighter.

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

Создание хоста


Как уже говорилось, в качестве хоста мы будем использовать консольное приложение. Добавьте новый проект и теперь выберите Console Application в качестве шаблона проекта. Назовите его «ConsoleHost».



Добавьте ссылку на System.ServiceModel снова, а также к проекту EmailService. В вашем методе Main, создайте объект ServiceHost и передайте ему корректные аргументы в конструкторе, как показано ниже.
  1. Type serviceType = typeof(EmailValidator);
  2. Uri serviceUri = new Uri("http://localhost:8080/");
  3. ServiceHost host = new ServiceHost(serviceType, serviceUri);
  4. host.Open();
* This source code was highlighted with Source Code Highlighter.

В строке 4 мы создаём объект ServiceHost. В качестве первого аргумента он получает тип реализации нашей службы. И базовый адрес (base address) в качестве второго аргумента. Вы можете прочитать больше о базовых адресах здесь и больше о размещении здесь. Тип определен в строке 1, базовый адрес – в строке 2. Наконец, в строке 5 наш хост запускается.

WCF4: Стандартные конечные точки


Вот это уже является особенностью .NET Framework 4.0 и это невозможно осуществить в предыдущей версии .NET. Стандартные конечные точки – это новая возможность, созданная для того, чтобы сделать конфигурирование вашей службы менее хлопотным. Я хотел бы явным образом определить все подробно, чтобы каждый знал, что происходит. Но в нашем примере, всё и так работает очень хорошо. Если вы не используете. NET 4.0, можете дальше не читать и перейти ко второй части, которая будет опубликовано позже.
Вы можете добавить стандартные конечные точки самостоятельно, добавив host.AddDefaultEndpoints (); к коду, прямо перед строкой host.Open ();.
Как мы можем увидеть, что конечные точки настроены по умолчанию? У меня есть небольшой скрипт из далёкого прошлого, который отображает всё, что сейчас запущено. Я не буду вдаваться в подробности, просто вставьте следующие строки кода после host.Open ();.
  1. #region Output dispatchers listening
  2. foreach (Uri uri in host.BaseAddresses)
  3. {
  4.     Console.WriteLine("\t{0}", uri.ToString());
  5. }
  6. Console.WriteLine();
  7. Console.WriteLine("Number of dispatchers listening : {0}", host.ChannelDispatchers.Count);
  8. foreach (System.ServiceModel.Dispatcher.ChannelDispatcher dispatcher in host.ChannelDispatchers)
  9. {
  10.     Console.WriteLine("\t{0}, {1}", dispatcher.Listener.Uri.ToString(), dispatcher.BindingName);
  11. }
  12. Console.WriteLine();
  13. Console.WriteLine("Press <ENTER> to terminate Host");
  14. Console.ReadLine();
  15. #endregion
* This source code was highlighted with Source Code Highlighter.

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





Как вы можете видеть, это нам говорит о том, что конечная точка MEX (aka metadata) пока не настроена. Теперь есть легкий способ сделать это через новые стандартные конечные точки. Мое первое впечатление было, что это будет работать.
  1. Type serviceType = typeof(EmailValidator);
  2. Uri serviceUri = new Uri("http://localhost:8080/");
  3. ServiceHost host = new ServiceHost(serviceType, serviceUri);
  4. host.AddDefaultEndpoints();
  5. // This actually doesn't just simply work.
  6. host.AddServiceEndpoint(new ServiceMetadataEndpoint());
* This source code was highlighted with Source Code Highlighter.

В строке 5 вы видите, что мы добавляем стандартные конечные точки, а в 7 строке добавляем ServiceMetadataEndpoint или конечную точку MEX. К сожалению, поведение метаданных (Metadata behavior) не может быть добавлено само по себе, так что вы все еще должны сделать это самостоятельно. Другим способом является возможность указать в конфигурации, что вы хотите включить метаданные. Ещё одной новинкой в WCF4 является возможность наследовать конфигурации. Вы можете указать в machine.config или в вашей локальной конфигурации, что должно быть включено по умолчанию для служб WCF. Я рекомендую вам не делать этого в machine.config, но это только мое мнение. Вот как я реализовал это в конфигурации моего проекта, файле app.config нашего консольного приложения-хоста. Обращу ваше внимание, что в следующей части мы будем делать это по старинке, способом, который будет работать в Visual Studio 2008 и который я сам предпочитаю.
  1. <?xml version="1.0" encoding="utf-8" ?>
  2. <configuration>
  3.     <system.serviceModel>
  4.         <behaviors>
  5.             <serviceBehaviors>
  6.                 <behavior>
  7.                     <serviceMetadata httpGetEnabled="True"/>
  8.                 </behavior>
  9.             </serviceBehaviors>
  10.         </behaviors>
  11.     </system.serviceModel>
  12. </configuration>
* This source code was highlighted with Source Code Highlighter.

Как вы можете видеть, я не указал имя для поведения, в WCF4 это означает, что оно будет использоваться всеми службами. Это также означает, что для каждой службы нужен базовый адрес для конечных точек HTTP.
Для справки, вот код для нашего консольного приложения-хоста:
  1. static void Main(string[] args)
  2. {
  3.     Type serviceType = typeof(EmailValidator);
  4.     Uri serviceUri = new Uri("http://localhost:8080/");
  5.     ServiceHost host = new ServiceHost(serviceType, serviceUri);        
  6.     host.Open();
  7.     #region Output dispatchers listening
  8.     foreach (Uri uri in host.BaseAddresses)
  9.     {
  10.         Console.WriteLine("\t{0}", uri.ToString());
  11.     }
  12.     Console.WriteLine();
  13.     Console.WriteLine("Number of dispatchers listening : {0}", host.ChannelDispatchers.Count);
  14.     foreach (System.ServiceModel.Dispatcher.ChannelDispatcher dispatcher in host.ChannelDispatchers)
  15.     {
  16.         Console.WriteLine("\t{0}, {1}", dispatcher.Listener.Uri.ToString(), dispatcher.BindingName);
  17.     }
  18.     Console.WriteLine();
  19.     Console.WriteLine("Press <ENTER> to terminate Host");
  20.     Console.ReadLine();
  21.     #endregion
  22. }
* This source code was highlighted with Source Code Highlighter.


Получение доступа к метаданным


Теперь мы можем открыть Internet Explorer или любой другой браузер, запустить наше консольное приложение-хост (в противном случае, конечные точки будут недоступны) и перейти к URI нашей службы: http://localhost:8080/
Если вы видите экран со ссылкой на WSDL, вероятнее всего, вы справились с созданием службы.

Создание клиентского приложения


Теперь мы добавим еще один проект, который будет обращаться к службе, и у нас будет возможность проверить, являются ли действительными указанные адреса электронной почты, или, по крайней мере удовлетворяющими нашему регулярному выражению.
Добавьте новое консольное приложение и на этот раз назовите его ConsoleClient. Убедитесь, что ваша служба (хост) запущена, и при этом не работает в режиме отладки. Самый простой способ это установить проект ConsoleHost как стартовый проект и нажать CTRL + F5, чтобы запустить его не в режиме отладки.
Теперь нам нужно прокси-класс (proxy class), который будет находиться между нашим клиентом и службой. Есть два способа создания прокси для нашей службы. Я предпочитаю делать это вручную, чтобы точно знать, что происходит. Я покажу это в первую очередь.

Создание прокси вручную


Для начала запустите командную строку Visual Studio 2010 (или Visual Studio 2008) и перейдите к месту расположения ConsoleClient. Поскольку это командная строка Visual Studio, вы должны иметь доступ к генератору прокси svcutil.exe. Введите следующую команду:
svcutil http://(парсер_на_хабре_лох)localhost:8080/ /o:ServiceProxy.cs /config:App.Config /n:*,ConsoleClient

Эта команда должна сгенерировать два файла: прокси службы и файл конфигурации приложения. Вернитесь в Visual Studio к своему приложении ConsoleClient. Для того, чтобы App.Config и ServiceProxy.cs стали доступны, вам необходимо кликнуть иконку в верхней части Solution Explorer, как показано на скриншоте снизу. Теперь новые файлы отображаются и вы можете включить их в проект.
Замечание: на скриншоте в окне консоли указано неверное пространство имён ConsoleHost вместо ConsoleClient.





Когда мы запустили svcutil.exe мы передали ему в качестве первого аргумента место расположения нашей службы, как указано в хосте. Это и есть базовый адрес. Вторым аргументом является наш прокси. Третий аргумент указывает, что мы также хотим обновить конфигурацию приложения, а если она не доступна, создать её. Последний аргумент – пространство имён для нашего прокси, которое на данный момент такое же, как и у нашего приложение.

Вызов службы


Теперь мы можем, наконец, обратиться к службе. Переходим к методу Main в классе Program снова. Теперь мы имеем доступ к прокси-классу, который имеет имя нашей службы с суффиксом Client. В данном случае EmailValidatorClient.
  1. EmailValidatorClient svc = new EmailValidatorClient();
  2. bool result = svc.ValidateAddress("dennis@bloggingabout.net");
* This source code was highlighted with Source Code Highlighter.

В строке 1 вы можете видеть инициализацию прокси. Это не означает установку соединение, она произойдёт при первом вызове. В строке 2 происходит вызов службы и получение результата обратно.
Ниже код нашего метода Main, который будет запрашивать адреса электронной почты.
  1. static void Main(string[] args)
  2. {
  3.     while (true)
  4.     {
  5.         Console.WriteLine("Enter an email address or press [ENTER] to quit...");
  6.         string emailAddress = Console.ReadLine();
  7.         if (string.IsNullOrEmpty(emailAddress))
  8.             return;
  9.         EmailValidatorClient svc = new EmailValidatorClient();
  10.         bool result = svc.ValidateAddress(emailAddress);
  11.         Console.WriteLine("Email address is valid : {0}", result);
  12.     }
  13. }
* This source code was highlighted with Source Code Highlighter.


Создание прокси через Visual Studio, легкий путь.


Вместо создания прокси службы вручную, с помощью svcutil.exe, вы также можете позволить Visual Studio создать его для вас. Просто щелкните правой кнопкой мыши по проекту и выберите «Add Service Reference...» Появится диалоговое окно, где необходимо будет ввести адрес вашей службы и пространство имён.



Теперь мы в пространстве имён ConsoleClient , но оно объединяет и уже существующие пространства имён. Так что теперь вы можете получить доступ к EmailValidatorClient через ConsoleClient.EmailValidatorClient. И это одна из причин, почему мне не нравится использовать автоматически сгенерированный прокси-класс. Теперь вы должны не забыть добавить директиву using для этого пространства имён. Вероятно, лучшим решением будет в диалоговом окне указать пространство имён Proxies или что-то подобное, чтобы полное название пространства имён имело больше смысла.

Запуск клиента


Если служба по-прежнему запущена (если нет, то перезапустите её), вы можете щелкнуть правой кнопкой мыши по проекту ConsoleClient и выбрать Debug и Start new instance. Всё, вы закончили.

Что дальше?


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

Отсюда вы можете скачать решение для Visual Studio 2010. В следующей части будет также доступно решение для Visual Studio 2008.
Tags:
Hubs:
+38
Comments 19
Comments Comments 19

Articles