Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

DataContractSerializer Error using Entity Framework 4.0 with WCF 4.0

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.


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;
    }
}

For EntityFramework 6.0 I had to change configuration as well:

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

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();
}