简体   繁体   中英

Serializing Parent/Child Object to with EF and WebApi

I have the following model inside an entity framework:

public class Customer
{
[XmlIgnore]
public virtual ICollection<Customer> Children { get; set; }

public string Name { get; set; }
}

Now I try to serialize this using web api:

public class CustomerController:ApiController {
   public HttpResponseMessage GetAll()
   {
     using (var tc = new DataContext())
     {
        List<Customer> allCustomers = tc.Customers.ToList();
        return Request.CreateResponse(HttpStatusCode.OK, allCustomers);              
     }
   }
}

When I do this and call the method using POST I receive the following error:

The 'ObjectContent`1' type failed to serialize the response body for content type 'application/json; charset=utf-8

InnerException: "Error getting value from 'Children' on 'System.Data.Entity.DynamicProxies.Customer"

InnerException(2): "The ObjectContext instance has been disposed and can no longer be used for operations that require a connection."

customers.Children is currently an empty List.

My guess this problem occurs because Children is of the same type as Customer causing an "infinite serialization loop". (I got no better words to describe that)

I already tried XmlIgnore to prevent that property to be serialized but with no effect.

Don't declare that navigation property as virtual or disable Lazy Loading behavior. Lazy loading is enable by default and is achieved by creating instances of derived proxy types and then overriding virtual properties to add the loading hook. So, if you want to work with XML serializer I recommend you turn off lazy loading:

public class YourContext : DbContext 
{ 
    public YourContext() 
    { 
        this.Configuration.LazyLoadingEnabled = false; 
    } 
}

In case you want to load the related entity ( Children ), you can use the Include extension method as part of a query. This behavior is called Eager Loading .

using System.Data.Entity;  // For extension method `Include`

List<Customer> allCustomers = tc.Customers.Include(c=>c.Children).ToList();

These links can help you to understand better what I explain in my answer:

If you remove the virtual keyword from your navigation properties, the POCO entity not meet the requirements described in the second link, so, EF won't create a proxy class to lazy load your navigation properties. But if you disabled lazy loading, even when your navigation properties are virtual , they won't be loaded in any entity. It's good idea disable lazy loading when you are using a serializer. Most serializers work by accessing each property on an instance of a type.

Just for the sake of knowledge: The following also works:

public class Customer
{
[XmlIgnore,JSonIgnore]
public virtual ICollection<Customer> Children { get; set; }

public string Name { get; set; }
}

The magic is "JsonIgnore" there.

Nonetheless: @octavioccl 's answer is a much better solution which requires more work but creates better code.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM