Создание WCF сервиса для JSONИсточник: msug
В субботу я впервые выступил с докладом в Southern California Code Camp о том, как использовать JQuery, для выполнения AJAX-операций к конечной точке(endpoint) в WCF. Сегодня я хочу показать, как создать WCF сервис с поддержкой JSON и каким образом создавать сообщения, которые могут сереализоваться в JSON и обратно. Первым шагом будет добавление WCF сервиса к веб-сайту. Это может быть ваш текущий проект, хотя это не обязательно. При добавлении сервиса через Visual Studio 2008 у нас создаётся svc-файл, а также контент, который, в нашем случае, необходимо удалить. Visual Studio 2008 and .NET 3.5Visual Studio 2010 вот-вот появится, поэтому я попробую сделать это двумя способами. В течении нескольких дней я напишу о том, как сделать это с помощью Visual Studio 2010. В диалогом окне Add New Item выберите WCF Service. После этого к вашему веб-сайту добавится файл .svc, а так же ещё два файла и некоторые ненужные секции в файле web.config. Начнём с файлов, добавленных в проект. Файл (.vb или .cs) определяет интерфейс, реализуемый сервисом. В нём так же находятся атрибуты, говорящие WCF о том, как использовать сервис. К .svc файлу также добавляется code-behind файл, в котором описана реализация сервиса. Оба эти файла можно использовать, однако я предпочитаю удалять их. Вместо этого я создам библиотеку классов, которая будет содержать и интерфейс, и реализацию. В конечном итоге это более понятный путь для дальнейшего управления кодом ваших WCF сервисов. Во-первых это позволяет легче создавать unit тесты (я опишу это в другом докладе). Во-вторых это даёт определённую гибкость при добавлении другого поставщика, реализующего интерфейс сервиса. Вы увидите, что такой путь не усложнит разработку, а всего лишь потребует добавления ссылки на библиотеку с классом. Файл Web.config слегка загрязнился, потому что были добавлены ненужные секции behaviors, services и endpoint в секцию system.serviceModel. Ниже приведен пример добавленной конфигурации, которую можно смело удалять из файла. <behaviors> В конечном итоге это сводится к конфигурации сервиса, и я не буду отрицать, что мало знаю о конфигурировании WCF. У меня есть люди для этого. Поэтому, двинемся дальше, а в этом месте вам придётся поверить мне на слово. Единственное, что осталось изменить - это .svc файл для корректной реализации нашего сервиса. Вот пример директивы, которая по умолчанию задаётся в .svc файле. <%@ servicehost language="C#" debug="true" service="Web.Testsvc" codebehind="Testsvc.svc.cs" %> Ниже показана новая версия директивы, в которой указано, какой класс будет использоваться для реализации сервиса, а так же подключен класс WebScriptServiceHostFactory, который позволяет использовать веб протоколы и добавляет JSON сериализацию, которая нам необходима для работы нашего сервиса с JQuery Ajax. <%@ ServiceHost Language="C#" Библиотека классовСледующим шагом добавим класс для реализации сервиса. Я люблю располагать файлы в папках, указывающих их назначение. Вы можете располагать как вам угодно. Я создал папку Contracts, которая содержит интерфейсы сервиса. Я говорю во множественном числе, потому что ваше приложение может содержать много WCF сервисов. Атрибуты WCF находятся в пространстве имён System.ServiceModel, поэтому вам нужно добавить на него ссылку. Если вы используете инструмент R#, то он сам добавит ссылку, как только вы напишете первый атрибут. Первый файл, который мы добавим - это интерфейс сервиса. В нашем примере я использую контактную форму, поэтому сервис называется ContactUs. Следовательно интерфейс будется называться IContactUs.cs. Если вы помните, в интерфейсе, который мы удалили, класс был отмечен атрибутом ServiceContract. Сейчас мы определим пространство имён для интерфейса, имени сервиса, режима сессии и уровня защиты. [ServiceContract(Namespace = "urn:WCFJQuery.ContactBLL.Contracts", Теперь мы можем добавить сигнатуры методов в наш интерфейс. Для нашего приложения добавим 4 метода: PostNewContact, GetContact, GetActiveContacts и BadMethod. Каждый метод описывается как указано ниже: [OperationContract(IsTerminating = false, Далее, мы можем добавить класс для реализации сервиса. Я помещу этот файл в папку Implementation. Создаём файл ContactUs.cs. Класс ContactUs реализует интерфейс IContactUs и описан атрибутом ServiceBehavior. В этом примере свойство IncludeExceptionDetailInFaults установлено в true. Это сделано для того, что бы сообщения об исключениях отправлялись на клиент сериализуясь в нужном виде. В нашем случае JQuery получит JSON данные. Члены класса не обязательно описывать какими-нибудь атрибутами. Вы можете подключить их автоматически, используя SmartTag на имени интерфейса или инструменты типа R# или CodeRush. Сейчас у вас должны быть ссылки на классы, которые не существуют. Мы должны создать их. Они так же добавляются в папку Implementation. Каждый из этих классов - класс сообщений. Эти классы содержат тело сообщений, которое является содержимым запроса к сервису и ответа от него. Пока вы окончательно не потерялись, нужно кое что прояснить. Архитектура WCF и SOA основана на передаче сообщений и объектов. Обычно, каждый метод сервиса принимает и возвращает какой-либо объект. Я всегда люблю проверять возвращаемый объект на клиенте. В этом различие между мной и тем, кто сфокусирован на разработке WCF части приложения. Первым, что меня натолкнуло на это, был метод, который добавлял новую запись в базу данных. Автор метода не возвращал никакого подтверждающего значения или вообще какого-либо значения, просто null. Он объяснял это тем, что если что то не сработает, то сгенерируется исключение. Я думаю это плохая практика в любом коде, так как вы не должны показывать исключение клиенту. Вместо этого, вы должны обработать исключение и вернуть осмысленное значение. Вы можете прочитать больше об этом в книге Брэда Абрамса. Давайте вернёмся к коду и посмотрим что нужно передать в запрос для того, что бы вернуть объект "Контакт". Очевидно что методу сервиса необходим ContactId, который используется как ключ для объекта "Контакт". Обратите внимание, я не говорю о записе в таблице "Контакты", потому что современные приложения работают с моделью данных, а не с базой на прямую. Например Entity Framework, oData или nHibernate. Фактически объект "Контакт" может быть составлен из записей разных таблиц. Класс GetContactRequest должен быть сериализован с помощью WCF, поэтому нам необходимо добавить атрибут DataContact к классу и атрибут DataMember для каждого члена класса. В этом атрибуте определяется имя члена класса. Оно может быть любым, но вам нужно запомнить его для доступа на клиенте. Затем мы должны указать, что это значение обязательно(IsRequired=true), иначе мы попытаемся выполнить запрос без указания id контакта, который нам нужен. В конце нужно указать порядок расположения данных.(Order = 0). Это подразумевает то, что значение будет первым или с индексом 0 в сериализуемом объекте. using System.Runtime.Serialization; namespace WCFJQuery.ContactBLL.Implementation { [DataContract(Namespace = "urn:WCFJQuery.ContactBLL.Implementation", public class GetContactRequest { } Для класса GetContactResponse нужно подключить пространство имён System.Runtime.Serialization и добавить необходимые атрибуты. В этом классе находится всего один член - объект класса ContactInfo. using System.Runtime.Serialization; namespace WCFJQuery.ContactBLL.Implementation { [DataContract(Namespace = "urn:WCFJQuery.ContactBLL.Implementation", public class GetContactResponse { } Класс ContactInfo так же требует сериализации. Поэтому вы опять добавляете необходимые атрибуты. Класс ContaсtInfo содержит более одного члена класса, некоторые помечены атрибутом IsRequired, некоторые нет. В этот раз вы задаёте порядок расположения данных с индексом в диапазоне от 1 до 11. using System.Runtime.Serialization; namespace WCFJQuery.ContactBLL.Implementation { [DataContract(Namespace = "urn:WCFJQuery.ContactBLL.Implementation", [DataMember(Name = "ContactId", IsRequired = false, Order = 0)] [DataMember(Name = "FirstName", IsRequired = true, Order = 1)] ... [DataMember(Name = "Coment", IsRequired = true, Order = 11)] } Процесс создания оставшихся объектов для передачи с запросом к серверу и объектов ответа от сервера точно такой же. Запомните - любые передаваемые объекты должны сериализоваться, т.е. должны быть помечены атрибутами. Вы не обязаны добавлять ваши классы реализации в библиотеку классов, но как вы увидите в последующих докладах, это облегчает тестирование вашего кода. Теперь у нас есть готовый WCF веб-сервис, принимающий и возвращающий JSON объекты, которые могут быть использованы на клиенте. В следующем докладе мы рассмотрим инфраструктуру и реализацию AJAX вызовов, использующих JSON к WCF сервису. |