11

I am breaking my head over this issue. I did find something on the internet about it, but not a clear answer. My problem:

I have to classes in Model section of an MVC3 web app: ParentClass and ChildClass On ParentClass there is a property Children of type List

I used EF Code First, which neatly generates a parent table and a child table for me in the database.

Now I need a REST service that gives back a List or a single ParentClass.

When I remove the property Children from the ParentClass there is no problem. But with the propoerty Children there I keep getting an error.

Error: "The type System.Data.Entity.DynamicProxies.ParentClass_A0EBE0D1022D01EB84B81873D49DEECC60879FC4152BB115215C3EC16FB8003A was not expected. Use the XmlInclude or SoapInclude attribute to specify types that are not known statically."}

Some code:

Classes:

     public class ParentClass
{
    public int ID { get; set; }
    public string Name {get;set;}
    public virtual List<ChildrenClass> Children { get; set; }

}

public class ChildrenClass
{
    public int ID { get; set; }
    public string MyProperty { get; set; }
}

Service:

[ServiceContract]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
[ServiceBehavior(IncludeExceptionDetailInFaults = true)] 
public class MyService
{

    static MyContext db;
    public MyService() { db = new MyContext(); }


    [WebGet(UriTemplate = "")]
    public List<ParentClass> GetParents()
    {
        var result = db.Parents.ToList();
        return result;

    }

I will not get the result when callinh this service. What am I doing wrong?

Mounhim
  • 1,584
  • 16
  • 32

3 Answers3

12

I had to DisableProxyCreation in the context configuration:

[OperationContract] 
[WebGet(UriTemplate = "")] 
public List<ParentClass> GetParents() 
{ 
     using (DBContext context = new DBContext()) 
     {
         context.Configuration.ProxyCreationEnabled = false; 
         List<ParentClass> parents = context.Parents
             .Include("Children") 
             .ToList();
         return parents; 
      }
}

This worked out for me fine.

Er Suman G
  • 349
  • 2
  • 9
Mounhim
  • 1,584
  • 16
  • 32
  • Just what I was looking for. Do you know of any downsides of disabling this? – hooked82 May 05 '12 at 06:23
  • 1
    There are many good tings from Proxies, keeping track of updates and such. No errors from forgetting to include statements. I still have no solutions for serializing proxi entities – Poul K. Sørensen Oct 17 '12 at 11:25
0

In some situations a simple solution is to use a wrapper class so that all the properties exposed are known types.

Usually you won't be using an ObjectContext or a DbContext in your controller classes anyway so in an earlier layer (Business or Service layer) you can do a quick translation from the objects coming from the DB into ViewModel style objects, similar to what you'd do in an MVC app, but instead of passing them on to a View you return them to the caller.

Maybe you can't use it in all cases, but often it's a workable compromise.

grahamesd
  • 4,103
  • 1
  • 24
  • 26
0

It seems to be serialising the proxy classes for your POCOs, my first recommendation would be to use the proxydatacontractresolver: http://msdn.microsoft.com/en-us/library/system.data.objects.proxydatacontractresolver.aspx.

Also I would work on having things spelt out explicitly when loading data for sending over web service ... i.e.

Change Parent class to

public class ParentClass
{
    public int ID { get; set; }
    public string Name {get;set;}
    public List<ChildrenClass> Children { get; set; }

}

Alter your content to turn off lazy loading: Disable lazy loading by default in Entity Framework 4

And explicitly specify what you want to load when returning data being sent over the wire.

[WebGet(UriTemplate = "")]
public List<ParentClass> GetParents()
{
    var result = db.Parents.Include("Children").ToList();
    return result;

}

Have a look at the following answer: Entity Framework Code First - Eager Loading not working as expected? for more advanced Include calls.

Also a piece of advice from experience, I wouldn't return your data classes over the wire as they form a contract for the consumer of your web service. You are best to have another set of classes that you map your data values into.

That way if your data classes change, you don't have to change the web service client unless explicitly required.

And using paging is important if you are expecting 1000's of rows in the Parent or Child classes otherwise you end up with N+1 select, see : What is SELECT N+1?.

Community
  • 1
  • 1
JTew
  • 3,049
  • 3
  • 29
  • 38
  • 1
    I have tried the DataContractResolver, but that didnt help. The disableproxycreation did help. But if I understand correctly I should separate the POCO's filled from the database from the classes to use in the services. But doesn't that mean that each object needs to be duplicated, meaning a ParentClass for usage within the site and the business logic and a separate ParentClass for usage in the service. Isn't that too much duplicating code? – Mounhim Nov 18 '11 at 21:49
  • We are using DTO's and Automapper to separate our resource model from our domain model. There are many advantages to this including separate validation and separate/different structures – suing Jan 06 '12 at 11:56
  • It is quite often overkill to duplicate your POCOs for N different uses, including the additive work and maintenance of maps/xlats. Many developers take the approach of carefully defining their POCOs once and then using them for both data transfer and data access, especially on smaller projects. If there comes a time when this no longer works (schema changes, refactors, etc) then new POCOs should be defined and mapping performed as necessary. This kind of shift/refactor doesn't affect web clients at all, it's only really a problem for .NET consumers of class libraries. E.g. binary dependents. – Shaun Wilson Jan 16 '13 at 19:34
  • I would agree that duplicating POCO is counter-productive. Where the underlying intent behind the use of the POCO is different you should have a different POCO. From experience I know that classes for a Data layer should not be exposed over the wire as data contracts. As soon as you change the database layer that infers that the data contract has changed and all consuming clients should change also. So reusing data POCOs doesn't allow you the flexibility to version your data/service interfaces for clients. – JTew Jan 16 '13 at 20:50