2010-07-30 3 views
55

Я пытаюсь получить список объектов из Entity Framework через WCF, но я получаю следующее исключение:DataContractSerializer Ошибка с помощью Entity Framework 4.0 с WCF 4.0

Была ошибку при попытке сериализовать параметр http://tempuri.org/:GetAllResult. Сообщение InnerException был «Type„System.Data.Entity.DynamicProxies.TestObject_240F2B681A782799F3A0C3AFBE4A67A7E86083C3CC4A3939573C5410B408ECCE“с именем контракта данных„TestObject_240F2B681A782799F3A0C3AFBE4A67A7E86083C3CC4A3939573C5410B408ECCE: http://schemas.datacontract.org/2004/07/System.Data.Entity.DynamicProxies“не ожидается. Подумайте об использовании DataContractResolver или добавьте любые типы, не известные статически в список известных типов - например, с помощью атрибута KnownTypeAttribute или путем добавления их в список известных типов, переданных DataContractSerializer. '. Дополнительную информацию см. В InnerException.

Я использовал WCF в прошлом, но никогда не использовал Entity Framework. У меня есть все мои сущности, созданные через Entity Framework, и аннотируются с атрибутами [DataContract] и [DataMember]. У меня нет свойств навигации ни на одном из моих объектов.

метод

GETALL() вызывается в абстрактном классе обслуживания:

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

И я использую ChannelFactory назвать мою реализацию:

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

Я хостинг это так:

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

При использовании отладки он находит объекты из базы данных, однако, это fai возвращая объекты.

Любые идеи относительно того, где я могу ошибиться?

ответ

88

Это была боль, чтобы понять, но это потому, что EntityFramework создает «прокси» вашего класса. Класс TestObject я был настроен правильно, но он создает класс под названием: TestObject_240F2B681A782799F3A0C3AFBE4A67A7E86083C3CC4A3939573C5410B408ECCE

Чтобы сделать ChannelFactory + WCF + Entity Framework работать вместе, вы должны идти в свой Context конструктор и добавьте следующее:

ContextOptions.ProxyCreationEnabled = false; 

Я надеюсь, что это поможет кому-то еще.

+1

Это очень помогло мне. Если у вас есть проблема, описанная в этом вопросе, также стоит прочитать этот http://stackoverflow.com/questions/4596371/what-are-the-downsides-to-turning-off-proxycreationenabled-for-ctp5-of-ef- code-f –

+0

Большое спасибо за этот ответ! – hupseb

+1

Мне пришлось сначала передать свой DbContext в ObjectContext. В VB.NET это выглядит как DirectCast (Me, IObjectContextAdapter) .ObjectContext.ContextOptions.ProxyCreationEnabled = False' – BlueMonkMN

60

При использовании API DbContext для Code First (EF 4.3) я должен был сделать:

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

Я добавил это к моему шаблону шаблона сущности в конструкторе - удивительное глобальное решение. – JnJnBoo

18

Для EntityFramework 6,0 Мне пришлось изменить конфигурацию, а также:

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

Вы рок! 4 прямых часа отладки r не пропали даром. Thnx – Aki

4

У вас есть несколько других параметры, отличные от добавления прокси-сервера для всего вашего POCO:

1) Создайте обертку. В API, скорее всего, вы не хотите подвергать весь POCO своим пользователям ... поэтому создайте объект-оболочку, который предоставляет только то, что вам нужно, и это также решает проблему прокси.

1.5) Довольно похоже на 1, но вместо создания обертки просто верните anonymous typeLINQ)

2) Если вам не нужно делать это достаточно широко, это может иметь смысл сделать это в Controller, где вам нужно, что сериализации ... или даже более локализованный в Method, в том числе using, вот за 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) другое дело, если вы нуждаясь это только для того дб вызова , самый простой способ сделать это - связать AsNoTracking() по вашему звонку:

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

Вы можете вместо этого использовать DTO и вернуть это. Не нужно отключать свойство Proxycreationenabled.