Пошаговое руководство. Сериализация прокси-сущностей POCO с помощью WCF (платформа Entity Framework)
Тип прокси POCO не может быть непосредственно сериализован или десериализован платформой Windows Communication Foundation (WCF), поскольку модуль сериализации DataContractSerializer способен сериализовать и десериализовать только известные типы. Тип прокси не является известным типом. Дополнительные сведения см. в подразделе «Сериализация прокси-сущностей POCO» раздела Работа с сущностями POCO (платформа Entity Framework). Для сериализации прокси-сущностей POCO как сущностей POCO воспользуйтесь классом ProxyDataContractResolver для сопоставления прокси-типов с типами POCO во время сериализации.
Пример в данном разделе демонстрирует настройку DataContractSerializer для использования класса ProxyDataContractResolver в операциях службы путем определения класса атрибута, который применяется к операциям службы и внутренним образом использует ProxyDataContractResolver для сопоставления прокси-типов с типами POCO. Он также демонстрирует связывание класса атрибутов с методами, являющимися частью контракта службы приложения WCF.
В примерах из этого раздела используются классы POCO, определенные в разделе Как определить сущности POCO (платформа Entity Framework), и модель данных на основе AdventureWorks, определенная в разделе Как настроить файлы моделирования и сопоставления для работы с пользовательскими объектами (платформа Entity Framework).
Чтобы создать проект библиотеки классов, содержащий классы POCO, выполните следующие действия.
Создайте новый проект библиотеки классов с именем POCOAdventureWorksModel.
Удалите файл исходного кода по умолчанию, добавленный к проекту.
Добавьте пустую модель с именем AdventureWorksModel. Сведения о создании пустой модели см. в подразделе «Создание пустого EDMX-файла» раздела How to: Create a New .edmx File. Измените модель, следуя шагам, описанным в разделе Пользовательский EDMX-файл AdventureWorks (платформа Entity Framework).
Отключите создание кода для EDMX-файла. Откройте EDMX-файл в конструкторе сущностей (ADO.NET Entity Data Model Designer). Щелкните правой кнопкой мыши в области конструктора и выберите пункт «Свойства». В окне Свойства выберите свойство Стратегия создания кода и укажите значение None. Если окно Свойства не отображается, нажмите клавишу F4.
Добавьте файл App.Config к проекту библиотеки классов. Щелкните правой кнопкой мыши проект POCOAdventureWorksModel, выберите пункт Добавить, затем Новый элемент.
В диалоговом окне Добавление нового элемента выберите Общие шаблоны, затем Файл конфигурации приложения. Скопируйте следующий код между тегами configuration в файле конфигурации приложения. При необходимости измените значение Data Source.
<connectionStrings> <add name="AdventureWorksEntities" connectionString="metadata=res://*/AdventureWorksModel.csdl|res://*/AdventureWorksModel.ssdl|res://*/AdventureWorksModel.msl; provider=System.Data.SqlClient;provider connection string=" Data Source=(local);Initial Catalog=AdventureWorks; Integrated Security=True;MultipleActiveResultSets=True"" providerName="System.Data.EntityClient" /> </connectionStrings>
Добавьте ссылку на библиотеку System.Runtime.Serialization. Эта библиотека нужна для WCF DataContract и для атрибутов DataMember, используемых для сериализуемых типов сущности.
Добавьте новый класс к проекту с именем
POCOClasses
. Добавьте код в файл Сериализуемые классы POCO на основе модели AdventureWorks. Он содержит тип сущности и определения контекстного объекта.Скомпилируйте проект.
Создание и настройка проекта WCF
Создайте проект WCF Service Application в том же решении, что и проект библиотеки классов с именем POCOAdventureWorksService.
Добавьте ссылку на библиотеку System.Data.Entity.
Добавьте ссылку на проект POCOAdventureWorksModel, в котором определена модель.
Добавьте строку соединения в файл конфигурации CONFIG, чтобы среда выполнения Entity Framework могла найти метаданные. Откройте файл app.config в проекте POCOAdventureWorksModel, скопируйте элемент connectionStrings и добавьте его как дочерний элемент элемента configuration файла Web.config.
Создайте новый класс и назовите его
ApplyDataContractResolverAttribute
.Добавьте следующие пространства имен в начало файла:
using System.Data.Objects; using System.ServiceModel.Description; using System.ServiceModel.Channels;
Замените код, созданный для нового класса, следующим кодом.
public class ApplyDataContractResolverAttribute : Attribute, IOperationBehavior { public ApplyDataContractResolverAttribute() { } public void AddBindingParameters(OperationDescription description, BindingParameterCollection parameters) { } public void ApplyClientBehavior(OperationDescription description, System.ServiceModel.Dispatcher.ClientOperation proxy) { DataContractSerializerOperationBehavior dataContractSerializerOperationBehavior = description.Behaviors.Find<DataContractSerializerOperationBehavior>(); dataContractSerializerOperationBehavior.DataContractResolver = new ProxyDataContractResolver(); } public void ApplyDispatchBehavior(OperationDescription description, System.ServiceModel.Dispatcher.DispatchOperation dispatch) { DataContractSerializerOperationBehavior dataContractSerializerOperationBehavior = description.Behaviors.Find<DataContractSerializerOperationBehavior>(); dataContractSerializerOperationBehavior.DataContractResolver = new ProxyDataContractResolver(); } public void Validate(OperationDescription description) { // Do validation. } }
Откройте файл интерфейса службы. По умолчанию он называется IService1.
Добавьте пространство имен
POCOAdventureWorksModel
в начало файла. Это пространство имен, в котором определяются типы POCO.Замените код, определяющий файл интерфейса службы, следующим кодом.
[ServiceContract] public interface IService1 { [OperationContract] [ApplyDataContractResolver] void UpdateOrder(Order updated); [OperationContract] [ApplyDataContractResolver] Order GetOrder(int OrderID); }
Откройте исходный код службы. По умолчанию он называется Service1.srv.cs (или .vb).
Добавьте пространство имен
POCOAdventureWorksModel
в начало файла.Замените код, определяющий класс службы, следующим кодом.
public class Service1 : IService1 { public void UpdateOrder(Order updated) { using (POCOAdventureWorksEntities context = new POCOAdventureWorksEntities()) { // Attach the original order to the context by querying the database. // Alternatively, you can require that the updated object be returned along with the original object from the client. // This means the client would need to clone the original object. Order original = context.Orders.SingleOrDefault(o => o.SalesOrderID == updated.SalesOrderID); // Apply changes to the order object. context.Orders.ApplyCurrentValues(updated); context.SaveChanges(); } } public Order GetOrder(int OrderID) { using (POCOAdventureWorksEntities context = new POCOAdventureWorksEntities()) { // You can disable the proxy creation // by setting context.ContextOptions.ProxyCreationEnabled to false context.ContextOptions.LazyLoadingEnabled = false; // The order was created as a POCO proxy object. // But it will be recieved on the client as a pure POCO. Order order = context.Orders.SingleOrDefault(o => o.SalesOrderID == OrderID); return order; } } }
Скомпилируйте проект.
Тестирование службы
Создайте консольное приложение. В качестве имени проекта укажите POCOAdventureWorksTest.
Добавьте ссылку на проект POCOAdventureWorksModel.
Добавьте ссылку на службу POCOAdventureWorksService. В Обозревателе решений щелкните правой кнопкой мыши нужную папку, затем выберите Добавить ссылку на службу.
Откройте файл app.config и добавьте в файл строку соединения. Откройте файл app.config для элемента POCOAdventureWorksModel, скопируйте элемент connectionStrings и добавьте его в качестве дочернего элемента для элемента configuration файла Web.config.
Откройте файл, содержащий функцию main.
Добавьте следующие пространства имен, в которых определены типы служб и POCO, в начало файла.
Service1Client client = new Service1Client(); int orderId = 43680; Order order = client.GetOrder(orderId); Console.WriteLine(order.DueDate); // Modify order. order.DueDate = DateTime.Now; // Update order in the database. client.UpdateOrder(order);
Замените код следующим кодом. Заметьте, что хотя служба и способна выполнять сериализацию прокси-сущностей POCO, клиент получает пустые объекты POCO.
Service1Client client = new Service1Client(); int orderId = 43680; Order order = client.GetOrder(orderId); Console.WriteLine(order.DueDate); // Modify order. order.DueDate = DateTime.Now; // Update order in the database. client.UpdateOrder(order);