2010-07-30 9 views
55

Estoy intentando recuperar una lista de objetos de Entity Framework a través de WCF, pero estoy recibiendo la siguiente excepción:error DataContractSerializer utilizando Entity Framework 4.0 con WCF 4.0

Hubo un error al intentar serializar parámetro http://tempuri.org/:GetAllResult. El mensaje era InnerException 'Tipo 'System.Data.Entity.DynamicProxies.TestObject_240F2B681A782799F3A0C3AFBE4A67A7E86083C3CC4A3939573C5410B408ECCE' con el nombre de contrato de datos 'TestObject_240F2B681A782799F3A0C3AFBE4A67A7E86083C3CC4A3939573C5410B408ECCE: http://schemas.datacontract.org/2004/07/System.Data.Entity.DynamicProxies' no se espera. Considere usar un DataContractResolver o agregue cualquier tipo no conocido de forma estática a la lista de tipos conocidos, por ejemplo, utilizando el atributo KnownTypeAttribute o agregándolos a la lista de tipos conocidos pasados ​​a DataContractSerializer. '. Por favor, consulte InnerException para más detalles.

He utilizado WCF en el pasado, pero nunca con Entity Framework. Tengo todas mis entidades generadas a través de Entity Framework y están anotadas con los atributos [DataContract] y [DataMember]. No tengo propiedades de navegación en ninguna de mis entidades.

método

El GetAll() se llama se encuentra en una clase de servicio abstracto:

[ServiceContract] 
public interface IService<T> 
{ 
    [OperationContract] 
    List<T> GetAll(); 
} 

y estoy usando el ChannelFactory a llamar a mi aplicación:

Binding binding = new NetTcpBinding(); 
EndpointAddress endpointAddress = new EndpointAddress("net.tcp://localhost:8081/" + typeof(TestObjectService).Name); 
using (ChannelFactory<ITestObjectService> channel = new ChannelFactory<ITestObjectService>(binding, endpointAddress)) 
{ 
    ITestObjectService testObjectService = channel.CreateChannel(); 
    testObjects = testObjectService.GetAll(); 
    channel.Close(); 
} 

Estoy recibiendo como tal:

Type type = typeof(TestObjectService); 
ServiceHost host = new ServiceHost(type, 
      new Uri("http://localhost:8080/" + type.Name), 
      new Uri("net.tcp://localhost:8081/" + type.Name)); 
host.Open(); 

Al usar la depuración, encuentra los objetos de la base de datos, sin embargo, es fai Ling devolviendo los objetos.

¿Alguna idea de dónde puedo estar yendo mal?

Respuesta

88

Esto fue un dolor de entender, pero es porque EntityFramework crea un 'proxy' de su clase. La clase TestObject que tuve fue configurado correctamente, pero que estaba creando una clase llamada: TestObject_240F2B681A782799F3A0C3AFBE4A67A7E86083C3CC4A3939573C5410B408ECCE

Para hacer el + WCF + Marco de la entidad ChannelFactory trabajar todos juntos, debe ir a su constructor Contexto y añadir lo siguiente:

ContextOptions.ProxyCreationEnabled = false; 

Espero que esto ayude a otra persona.

+1

Esto me ayudó mucho gracias. Si tiene el problema descrito en esta pregunta, también vale la pena leer este http://stackoverflow.com/questions/4596371/what-are-the-downsides-to-turning-off-proxycreationenabled-for-ctp5-of-ef- code-f –

+0

¡Muchas gracias por esa respuesta! – hupseb

+1

Tuve que convertir mi DbContext a ObjectContext primero. En VB.NET, eso se ve como 'DirectCast (Me, IObjectContextAdapter) .ObjectContext.ContextOptions.ProxyCreationEnabled = False' – BlueMonkMN

60

Al utilizar la API DbContext de Código First (EF 4.3) que tenía que hacer:

public class MyClass : DbContext 
{ 
    public MyClass() 
    { 
     base.Configuration.ProxyCreationEnabled = false; 
    } 
} 
+1

Agregué esto a mi plantilla entity tt de marco en el constructor - impresionante solución global. – JnJnBoo

18

Para ADO.NET Entity Framework 6.0 que tenía que cambiar de configuración, así:

public class MyContext : DbContext 
{ 
    public MyContext() : base("name=MyContext") 
    { 
     Configuration.ProxyCreationEnabled = false; 
    } 
} 
+1

¡Rock! 4 horas consecutivas de depuración no se desperdician. thx – Aki

4

Tiene varios otros opciones distintas a agregar ningún proxy a todo su POCO:

1) Cree un contenedor. En una API, es probable que no desee exponer todo el POCO a sus usuarios ... así que cree un objeto envoltorio que solo exponga lo que desea, y esto también resuelve el problema del proxy.

1.5) Casi como 1, pero en lugar de crear un contenedor, simplemente devuelva un anonymous type (con LINQ)

2) Si no necesita hacerlo en toda la aplicación, puede tener más sentido hacerlo en el Controller donde se necesita que la serialización ... o incluso más localizada a una Method, incluyendo using, he aquí una aplicación por Controller:

public class ThingController : ApiController 
{ 
    public ThingController() 
    { 
     db = new MyContext(); 
     db.Configuration.ProxyCreationEnabled = false; 
    } 

    private MyContext db; 

    // GET api/Thing 
    public IQueryable<Thing> GetThings() 
    { 
     return db.Things; 
    } 

    //... 

    protected override void Dispose(bool disposing) 
    { 
     if (disposing) 
      db.Dispose(); 

     base.Dispose(disposing); 
    } 
} 

3) La otra cosa es si usted está necesitando sólo para esa llamada db , la forma más fácil de hacerlo es encadenar AsNoTracking() en su llamada:

List<Thing> things; 
using (var db = new MyContext()) 
{ 
    things = db.Things.AsNoTracking().ToList(); 
} 
1

En cambio, puede usar un DTO y devolverlo. No es necesario desactivar la propiedad Proxycreationenabled.

Cuestiones relacionadas