首页 文章

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

提问于
浏览
56

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

尝试序列化参数_2573502时出错 . InnerException消息是'Type ' System.Data.Entity.DynamicProxies.TestObject_240F2B681A782799F3A0C3AFBE4A67A7E86083C3CC4A3939573C5410B408ECCE ' with data contract name ' TestObject_240F2B681A782799F3A0C3AFBE4A67A7E86083C3CC4A3939573C5410B408ECCE:http://schemas.datacontract.org/2004/07/System.Data.Entity.DynamicProxies ' is not expected. Consider using a DataContractResolver or add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to 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();

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

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

5 回答

  • 60

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

    要使ChannelFactory WCF实体框架全部协同工作,您必须进入Context构造函数并添加以下内容:

    ContextOptions.ProxyCreationEnabled = false;
    

    我希望这有助于其他人 .

  • 1

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

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

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

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

    除了不为整个POCO添加代理外,您还有其他几个选项:

    1)创建一个包装器 . 在API中,您可能不希望将整个POCO公开给您的用户...因此创建一个只暴露您想要的东西的包装器对象,这也解决了代理问题 .

    1.5)非常像1,但不是创建一个包装器,只需返回 anonymous type (使用 LINQ

    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)另一件事是如果你只需要那个db调用,最简单的方法就是将 AsNoTracking() 链接到你的调用中:

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

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

相关问题