使用带有WCF 4.0的Entity Framework 4.0时出现DataContractSerializer错误

Bra*_*don 56 .net entity-framework

我试图通过WCF从实体框架中检索对象列表,但我收到以下异常:

尝试序列化参数http://tempuri.org/:GetAllResult时出错.该消息的InnerException是"类型'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();
}
Run Code Online (Sandbox Code Playgroud)

我正在使用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();
}
Run Code Online (Sandbox Code Playgroud)

我这样托管它:

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();
Run Code Online (Sandbox Code Playgroud)

使用调试时,它会从数据库中找到对象,但是,它无法返回对象.

关于我可能出错的地方的任何想法?

Bra*_*don 90

这很难理解,但这是因为EntityFramework创建了一个类的"代理".我正确设置的TestObject类,但它创建了一个名为的类:TestObject_240F2B681A782799F3A0C3AFBE4A67A7E86083C3CC4A3939573C5410B408ECCE

要使ChannelFactory + WCF + Entity Framework一起工作,您必须进入Context构造函数并添加以下内容:

ContextOptions.ProxyCreationEnabled = false;
Run Code Online (Sandbox Code Playgroud)

我希望这有助于其他人.


a-h*_*a-h 60

当使用DbContext API代码优先(EF 4.3)时,我必须这样做:

public class MyClass : DbContext
{
    public MyClass()
    {
        base.Configuration.ProxyCreationEnabled = false;
    }
}
Run Code Online (Sandbox Code Playgroud)


geo*_*ger 20

对于EntityFramework 6.0,我还必须更改配置:

public class MyContext : DbContext
{
    public MyContext() : base("name=MyContext")
    {
        Configuration.ProxyCreationEnabled = false;
    }
}
Run Code Online (Sandbox Code Playgroud)


Ser*_*gan 5

除了不向整个 POCO 添加代理之外,您还有其他几种选择:

1) 创建一个包装器/DTO。在 API 中,您可能不想将整个 POCO 公开给您的用户……因此创建一个仅公开您想要的内容的包装器对象,这也解决了代理问题。

1.5) 与 1 非常相似,但不是创建包装器,而是返回一个anonymous type(with LINQ)

2)如果您不需要在应用程序范围内执行此操作,则Controller在需要序列化的地方执行此操作可能更有意义……甚至更本地化为 a 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);
    }
}
Run Code Online (Sandbox Code Playgroud)

3)另一件事是,如果您只需要该 db 调用,最简单的方法是链接AsNoTracking()到您的调用中:

List<Thing> things;
using (var db = new MyContext())
{
    things = db.Things.AsNoTracking().ToList();
}
Run Code Online (Sandbox Code Playgroud)