56

I am attempting to retrieve a list of objects from Entity Framework via WCF, but am receiving the following exception:

There was an error while trying to serialize parameter http://tempuri.org/:GetAllResult. The InnerException message was '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.'. Please see InnerException for more details.

I have used WCF in the past, but never with Entity Framework. I have all my entities generated via Entity Framework and are annotated with [DataContract] and [DataMember] attributes. I have no Navigation Properties on any of my entities.

The GetAll() method being called is in an abstract service class:

[ServiceContract]
public interface IService<T>
{
    [OperationContract]
    List<T> GetAll();
}

And I am using the ChannelFactory to call my implementation:

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

I am hosting it as such:

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

When using debugging, it finds the objects from the database, however, it is failing returning the objects.

Any ideas as to where I may be going wrong?

Brandon
  • 10,744
  • 18
  • 64
  • 97

5 Answers5

92

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;
starball
  • 20,030
  • 7
  • 43
  • 238
Brandon
  • 10,744
  • 18
  • 64
  • 97
  • 1
    This helped me a lot thanks. If you have the problem described in this question it's also worth reading this http://stackoverflow.com/questions/4596371/what-are-the-downsides-to-turning-off-proxycreationenabled-for-ctp5-of-ef-code-f – Phil Hale Mar 21 '12 at 22:51
  • 1
    I had to cast my DbContext to an ObjectContext first. In VB.NET, that looks like `DirectCast(Me, IObjectContextAdapter).ObjectContext.ContextOptions.ProxyCreationEnabled = False` – BlueMonkMN Nov 21 '13 at 21:05
  • 1
    I know we're not supposed to add comments that are just a 'thank you', but this worked great for me too. Hadn't see this mentioned in any tutorials, and had virtually no debugging information at first because an infinite loop was occurring in my Json Serialization. Thank you. – Adam Marshall Feb 03 '14 at 13:37
  • 1
    In entity framework 7 I had to edit the constructor of my DbContext class and added the (C#) line 'this.Configuration.ProxyCreationEnabled = false;' No need to cast to ObjectContext. You saved me hours (possibly days) of work. – Rob Vermeulen Jun 22 '16 at 16:03
  • This helped me out a lot, thank you! I went into my context constructor and added `this.Configuration.ProxyCreationEnabled = false;`. Works like a champ now! – Hooplator15 Mar 06 '17 at 02:59
  • Thanks! Was looking for a solution some days. Worked for me. – Florian Falk Jul 07 '21 at 09:32
60

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;
    }
}
a-h
  • 4,244
  • 2
  • 23
  • 29
  • 1
    I added this to my entity framework tt template in the constructor - awesome global solution. – Jenn Oct 16 '13 at 21:50
20

For EntityFramework 6.0 I had to change configuration as well:

public class MyContext : DbContext
{
    public MyContext() : base("name=MyContext")
    {
        Configuration.ProxyCreationEnabled = false;
    }
}
georger
  • 1,568
  • 21
  • 24
5

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();
}
Serj Sagan
  • 28,927
  • 17
  • 154
  • 183
1

You can instead use a DTO and return that. No need to turn off the Proxycreationenabled property.

Deepak Pathak
  • 626
  • 1
  • 9
  • 19