Tutorial: Serializar objetos proxy POCO con WCF (Entity Framework)

El tipo de proxy POCO no se puede serializar o deserializar directamente mediante Windows Communication Foundation (WCF), ya que el motor de serialización DataContractSerializer solo puede serializar y deserializar tipos conocidos. El tipo proxy no es un tipo conocido. Para obtener más información, vea la sección sobre Serialización de objetos proxy POCO en el tema Trabajar con entidades POCO (Entity Framework). Para serializar objetos proxy POCO como entidades POCO, utilice la clase ProxyDataContractResolver para asignar tipos proxy a tipos POCO durante la serialización.

El ejemplo de este tema muestra cómo hacer que el DataContractSerializer utilice la clase ProxyDataContractResolver en operaciones del servicio definiendo una clase de atributos, la cual se aplicará a las operaciones del servicio, que internamente utiliza el ProxyDataContractResolver para asignar tipos proxy a tipos POCO. También muestra cómo asociar la clase de atributos a métodos que forman parte de un contrato de servicio en su aplicación WCF.

Los ejemplos de este tema utilizan las clases POCO que se definen en Cómo: Definir entidades POCO (Entity Framework) y un modelo de datos basado en AdventureWorks que se define en Cómo: Personalizar archivos de asignación y modelado para trabajar con objetos personalizados (Entity Framework).

Para crear el proyecto de biblioteca de clases que contiene las clases POCO.

  1. Cree un nuevo proyecto de biblioteca de clases denominado POCOAdventureWorksModel.

  2. Quite el archivo de código fuente predeterminado que se agregó al proyecto.

  3. Agregue un modelo vacío denominado AdventureWorksModel. Para crear un modelo vacío, vea la sección Para crear un archivo .edmx vacío dentro del tema How to: Create a New .edmx File. Modifique el modelo siguiendo los pasos de Archivo .edmx personalizado de AdventureWorks (Entity Framework).

  4. Deshabilite la generación de código para el archivo .edmx. Abra el archivo .edmx en ADO.NET Entity Data Model Designer (Entity Designer). Haga clic con el botón secundario en la superficie del diseñador y seleccione Propiedades. En la ventana Propiedades, seleccione la propiedad Estrategia de generación de código y haga clic en None. Si la ventana Propiedades no está visible, presione F4.

  5. Agregue el archivo app.config al proyecto de biblioteca de clases. Haga clic con el botón secundario en POCOAdventureWorksModel, haga clic en Agregar y, a continuación, haga clic en Nuevo elemento.

  6. En el cuadro de diálogo Agregar nuevo elemento, seleccione las plantillas General y seleccione Archivo de configuración de aplicación. Copie el siguiente código entre las etiquetas configuration de su archivo de configuración de aplicación. Modifique el valor de Data Source si es necesario.

    <connectionStrings>
      <add name="AdventureWorksEntities" 
          connectionString="metadata=res://*/AdventureWorksModel.csdl|res://*/AdventureWorksModel.ssdl|res://*/AdventureWorksModel.msl;
              provider=System.Data.SqlClient;provider connection string=&quot;
              Data Source=(local);Initial Catalog=AdventureWorks;
              Integrated Security=True;MultipleActiveResultSets=True&quot;" 
          providerName="System.Data.EntityClient" />
    </connectionStrings>
    
  7. Agregue una referencia a la biblioteca System.Runtime.Serialization. Esta biblioteca es necesaria para los atributos DataMember y DataContract de WCF que se utilizan en los tipos de entidad serializables.

  8. Agregue una nueva clase a su proyecto denominado POCOClasses. Agregue el código que aparece en Clases POCO serializables basadas en el modelo AdventureWorks al archivo. Este contiene las definiciones del contexto del objeto y el tipo de entidad.

  9. Compile el proyecto.

Para crear y configurar el proyecto WCF.

  1. Cree un proyecto WCF Service Application en la misma solución que el proyecto de biblioteca de clases denominado POCOAdventureWorksService.

  2. Agregue una referencia a la biblioteca System.Data.Entity.

  3. Agregue una referencia al proyecto POCOAdventureWorksModel, que es donde se define el modelo.

  4. Agregue la cadena de conexión al archivo .config para que el motor de ejecución de Entity Framework pueda encontrar los metadatos. Abra el archivo app.config en su proyecto POCOAdventureWorksModel, copie el elemento connectionStrings y agréguelo como un elemento secundario del elemento configuration del archivo Web.config.

  5. Cree una nueva clase con el nombre ApplyDataContractResolverAttribute.

  6. Agregue los siguientes espacios de nombres al principio del archivo:

    using System.Data.Objects;
    using System.ServiceModel.Description;
    using System.ServiceModel.Channels;
    
  7. Reemplace el código generado para la nueva clase por el código siguiente:

    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.
        }
    }
    
  8. Abra el archivo de interfaz del servicio. De manera predeterminada, se denomina IService1.

  9. Agregue el espacio de nombres POCOAdventureWorksModel al principio del archivo. Este es el espacio de nombres donde se definen los tipos POCO.

  10. Reemplace el código que define el archivo de interfaz del servicio por el siguiente código:

    [ServiceContract]
    public interface IService1
    {
        [OperationContract]
        [ApplyDataContractResolver]
        void UpdateOrder(Order updated);
    
        [OperationContract]
        [ApplyDataContractResolver]
        Order GetOrder(int OrderID);
    }
    
  11. Abra el código fuente del servicio. De forma predeterminada, se denomina Service1.srv.cs (o .vb)

  12. Agregue el espacio de nombres POCOAdventureWorksModel al principio del archivo.

  13. Reemplace el código que define la clase del servicio por el siguiente código:

    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;
            }
        }
    }    
    
  14. Compile el proyecto.

Para probar el servicio.

  1. Cree una aplicación de consola. Escriba POCOAdventureWorksTest como nombre del proyecto.

  2. Agregue una referencia al proyecto POCOAdventureWorksModel.

  3. Agregue una referencia al servicio POCOAdventureWorksService. En el Explorador de soluciones, haga clic con el botón secundario en la carpeta de referencias y, a continuación, seleccione Agregar referencia de servicio.

  4. Abra el archivo app.config y agregue la cadena de conexión al archivo. Abra el archivo app.config para POCOAdventureWorksModel, copie el elemento connectionStrings y agréguelo como un elemento secundario del elemento configuration del archivo Web.config.

  5. Abra el archivo que contiene la función principal.

  6. Agregue los siguientes espacios de nombres, donde se definen el servicio y los tipos POCO, al principio del archivo:

    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);
    
  7. Reemplace el código por el siguiente código. Observe que, aunque el servicio pudo serializar los objetos proxy POCO, el cliente recibió objetos POCO puros.

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

Vea también

Conceptos

Serializar objetos (Entity Framework)