【问题标题】:DataContractSerializer Error using Entity Framework 4.0 with WCF 4.0使用带有 WCF 4.0 的实体框架 4.0 的 DataContractSerializer 错误
【发布时间】:2010-07-30 15:20:26
【问题描述】:

我正在尝试通过 WCF 从 Entity Framework 检索对象列表,但收到以下异常:

尝试序列化参数http://tempuri.org/:GetAllResult 时出错。该消息的InnerException是‘用数据合同名称‘TestObject_240F2B681A782799F3A0C3AFBE4A67A7E86083C3CC4A3939573C5410B408ECCE“类型’System.Data.Entity.DynamicProxies.TestObject_240F2B681A782799F3A0C3AFBE4A67A7E86083C3CC4A3939573C5410B408ECCE:http://schemas.datacontract.org/2004/07/System.Data.Entity.DynamicProxies’预计不会。考虑使用 DataContractResolver 或将任何静态未知的类型添加到已知类型列表中 - 例如,通过使用 KnownTypeAttribute 属性或将它们添加到传递给 DataContractSerializer 的已知类型列表中。有关详细信息,请参阅 InnerException。

我过去使用过 WCF,但从未使用过实体框架。我的所有实体都是通过 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();

使用调试时,它从数据库中查找对象,但是返回对象失败。

关于我可能出错的地方有什么想法吗?

【问题讨论】:

    标签: .net entity-framework


    【解决方案1】:

    这很难弄清楚,但这是因为 EntityFramework 为您的班级创建了一个“代理”。我的 TestObject 类设置正确,但它正在创建一个名为:TestObject_240F2B681A782799F3A0C3AFBE4A67A7E86083C3CC4A3939573C5410B408ECCE 的类

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

    ContextOptions.ProxyCreationEnabled = false;
    

    我希望这对其他人有帮助。

    【讨论】:

    • 这对我很有帮助,谢谢。如果您遇到此问题中描述的问题,那么也值得阅读此stackoverflow.com/questions/4596371/…
    • 非常感谢您的回答!
    • 我必须先将我的 DbContext 转换为 ObjectContext。在 VB.NET 中,这看起来像 DirectCast(Me, IObjectContextAdapter).ObjectContext.ContextOptions.ProxyCreationEnabled = False
    • 我知道我们不应该添加只是“谢谢”的 cmets,但这对我也很有效。在任何教程中都没有看到这一点,并且起初几乎没有调试信息,因为我的 Json 序列化中发生了无限循环。谢谢。
    • 在实体框架 7 中,我必须编辑 DbContext 类的构造函数并添加 (C#) 行 'this.Configuration.ProxyCreationEnabled = false;'无需转换为 ObjectContext。您为我节省了数小时(可能是数天)的工作时间。
    【解决方案2】:

    将 DbContext API 用于 Code First (EF 4.3) 时,我必须这样做:

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

    【讨论】:

    • 我在构造函数中将它添加到我的实体框架 tt 模板 - 很棒的全局解决方案。
    【解决方案3】:

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

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

    【讨论】:

    • 你摇滚!!连续 4 小时的调试没有浪费。谢谢
    【解决方案4】:

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

    1) 创建一个包装器/DTO。在 API 中,您可能不想将整个 POCO 暴露给您的用户......所以创建一个只暴露您想要的东西的包装器对象,这也解决了代理问题。

    1.5) 很像 1,但不是创建包装器,而是返回一个 anonymous type(带有 LINQ

    2) 如果您不需要在应用程序范围内执行此操作,则在您需要序列化的Controller 中执行此操作可能更有意义......或者甚至更本地化为Method,包括@ 987654325@,这是每个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) 另一件事是,如果您只是为了那个 db 调用而需要它,最简单的方法是将 AsNoTracking() 链接到您的调用中:

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

    【讨论】:

      【解决方案5】:

      您可以改为使用 DTO 并将其返回。无需关闭 Proxycreationenabled 属性。

      【讨论】:

        猜你喜欢
        • 2011-09-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多