DataContractSerializer错误使用entity framework4.0与WCF 4.0
我试图通过WCF从entity framework检索对象的列表,但我收到以下exception:
尝试序列化参数http://tempuri.org/:GetAllResult时发生错误。 该消息的InnerException是“types‘System.Data.Entity.DynamicProxies.TestObject_240F2B681A782799F3A0C3AFBE4A67A7E86083C3CC4A3939573C5410B408ECCE’数据合同名称‘TestObject_240F2B681A782799F3A0C3AFBE4A67A7E86083C3CC4A3939573C5410B408ECCE: http://schemas.datacontract.org/2004/07/System.Data.Entity.DynamicProxies预计不会’。 考虑使用DataContractResolver或将任何不知道的types静态添加到已知types列表中 – 例如,通过使用KnownTypeAttribute属性或将它们添加到传递给DataContractSerializer的已知types列表中。 请参阅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();
在使用debugging时,它会从数据库中查找对象,但是无法返回对象。
任何想法,我可能会出错哪里?
这是一个痛苦的解决,但这是因为EntityFramework创build您的类的“代理”。 TestObject类已正确设置,但它创build了一个名为:TestObject_240F2B681A782799F3A0C3AFBE4A67A7E86083C3CC4A3939573C5410B408ECCE
要使ChannelFactory + WCF +entity framework一起工作,您必须进入您的Context构造函数并添加以下内容:
ContextOptions.ProxyCreationEnabled = false;
我希望这可以帮助别人。
Code First(EF 4.3)使用DbContext API时,我必须这样做:
public class MyClass : DbContext { public MyClass() { base.Configuration.ProxyCreationEnabled = false; } }
对于EntityFramework 6.0我也必须改变configuration:
public class MyContext : DbContext { public MyContext() : base("name=MyContext") { Configuration.ProxyCreationEnabled = false; } }
除了向您的整个POCO添加代理之外,您还有其他几个选项:
1)创build一个包装。 在一个API中,你可能不希望把整个POCO公开给你的用户…所以创build一个只公开你想要的东西的包装对象,这也解决了代理问题。
1.5)非常像1,但不是创build一个包装,只是返回一个anonymous type
(与LINQ
)
2)如果您不需要在应用程序范围内执行此操作,则可以在需要序列化的Controller
执行此using
,或者在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(); }
您可以改为使用DTO并返回。 无需closuresProxycreationenabled属性。