2010-07-30 20 views
55

Sto tentando di recuperare un elenco di oggetti da Entity Framework tramite WCF, ma sto ricevendo la seguente eccezione:DataContractSerializer errore utilizzando Entity Framework 4.0 con WCF 4.0

C'è stato un errore durante il tentativo di serializzare parametro http://tempuri.org/:GetAllResult. Il messaggio era InnerException 'Tipo 'System.Data.Entity.DynamicProxies.TestObject_240F2B681A782799F3A0C3AFBE4A67A7E86083C3CC4A3939573C5410B408ECCE' con il nome del contratto di dati 'TestObject_240F2B681A782799F3A0C3AFBE4A67A7E86083C3CC4A3939573C5410B408ECCE: http://schemas.datacontract.org/2004/07/System.Data.Entity.DynamicProxies' non è previsto. Prendi in considerazione l'utilizzo di DataContractResolver o aggiungi staticamente i tipi non noti all'elenco dei tipi noti, ad esempio utilizzando l'attributo KnownTypeAttribute o aggiungendoli all'elenco dei tipi noti passati a DataContractSerializer. '. Si prega di consultare InnerException per maggiori dettagli.

ho usato WCF in passato, ma mai con Entity Framework. Ho tutte le mie entità generate tramite Entity Framework e sono annotate con gli attributi [DataContract] e [DataMember]. Non ho proprietà di navigazione su nessuna delle mie entità.

Il GetAll() metodo chiamato è in una classe di servizio astratta:

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

e sto usando il ChannelFactory chiamare la mia realizzazione:

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

Sto ospitando come tale:

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

Quando si utilizza il debug, trova gli oggetti dal database, tuttavia, è fai ling restituendo gli oggetti.

Qualche idea su dove potrei andare storto?

risposta

88

Questo era un problema da capire, ma è perché EntityFramework crea un "proxy" della classe. La classe TestObject ho avuto è stato configurato correttamente, ma si stava creando una classe chiamata: TestObject_240F2B681A782799F3A0C3AFBE4A67A7E86083C3CC4A3939573C5410B408ECCE

Per rendere la ChannelFactory + WCF + Entity Framework lavorare tutti insieme, si deve andare nel vostro costruttore Contesto e aggiungere il seguente:

ContextOptions.ProxyCreationEnabled = false; 

Spero che questo aiuti qualcun altro.

+1

Questo mi ha aiutato molto, grazie. Se hai il problema descritto in questa domanda vale la pena leggere questo http://stackoverflow.com/questions/4596371/what-are-the-downsides-to-turning-off-proxycreationenabled-for-ctp5-of-ef- code-f –

+0

Grazie mille per la risposta! – hupseb

+1

Ho dovuto eseguire il cast del mio DbContext su un ObjectContext. In VB.NET, appare come 'DirectCast (Me, IObjectContextAdapter) .ObjectContext.ContextOptions.ProxyCreationEnabled = False' – BlueMonkMN

60

Quando si utilizza l'API DbContext per Code First (EF 4.3) ho dovuto fare:

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

Ho aggiunto questo al mio modello tt di entità framework nel costruttore: una soluzione globale fantastica. – JnJnBoo

18

Per EntityFramework 6.0 Ho dovuto cambiare la configurazione così:

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

Sei rock !! 4 ore esatte di debugging non vengono sprecate. thnx – Aki

4

si dispone di diversi altri opzioni diverse da aggiungere alcun proxy per l'intera POCO:

1) Creare un wrapper. In un'API, è probabile che tu non voglia esporre l'intero POCO ai tuoi utenti ... quindi crea un oggetto wrapper che esponga solo le cose che vuoi, e questo risolve anche il problema del proxy.

1.5) Simile a 1, ma invece di creare un wrapper, basta restituire un anonymous type (con LINQ)

2) Se non è necessario farlo in tutta l'app, potrebbe essere più logico farlo nel Controller in cui è necessario che la serializzazione ... o anche più localizzati ad un Method, tra cui using, ecco una per Controller implementazione:

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) L'altra cosa è se si sta bisogno solo per quella chiamata db , il modo più semplice per farlo è inserire la catena AsNoTracking() nella tua chiamata:

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

È possibile invece utilizzare un DTO e restituirlo. Non è necessario disattivare la proprietà Proxycreationenabled.

Problemi correlati