DataContractSerializer Error using Entity Framework 4.0 with WCF 4.0
Solution 1:
This was a pain to figure out but it is because EntityFramework creates a 'proxy' of your class. The TestObject class I had was setup correctly, but it was creating a class called: TestObject_240F2B681A782799F3A0C3AFBE4A67A7E86083C3CC4A3939573C5410B408ECCE
To make the ChannelFactory + WCF + Entity Framework all work together, you must go into your Context constructor and add the following:
ContextOptions.ProxyCreationEnabled = false;
I hope this helps someone else.
Solution 2:
When using the DbContext API for Code First (EF 4.3) I had to do:
public class MyClass : DbContext
{
public MyClass()
{
base.Configuration.ProxyCreationEnabled = false;
}
}
Solution 3:
For EntityFramework 6.0 I had to change configuration as well:
public class MyContext : DbContext
{
public MyContext() : base("name=MyContext")
{
Configuration.ProxyCreationEnabled = false;
}
}
Solution 4:
You have several other options other than adding no proxy to your entire POCO:
1) Create a wrapper/DTO. In an API, it is likely that you don't want to expose the whole POCO to your users... so create a wrapper object that only exposes the stuff you want, and this also solves the proxy problem.
1.5) Pretty much like 1, but instead of creating a wrapper, just return an anonymous type
(with LINQ
)
2) If you don't need to do it app wide, it may make more sense to do it in the Controller
where you need that serialization... or even more localized to a Method
, including using
, here's a per Controller
implementation:
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) The other thing is if you're needing it just for that db call, the easiest way to do it is to chain AsNoTracking()
into your call:
List<Thing> things;
using (var db = new MyContext())
{
things = db.Things.AsNoTracking().ToList();
}