after a lot of help yesterday, I came up against a known error in asp.net4 beta - I upgraded to VS2012 RC Express (4.5), and now I\'m getting an internal server error, and I
To resolve the error 500 issue when returning JSON with entities with virtual keyword I did the following,
public class BookingsController : ApiController
{
private BookingsContext db = new BookingsContext();
// GET api/Bookings
public IEnumerable<tblCustomerBooking> GettblCustomerBookings()
{
db.Configuration.ProxyCreationEnabled = false;
return db.tblCustomerBookings.AsEnumerable();
}
}
It's enough to disable proxy creation (which disables lazy loading as well) for the specific circumstances where proxies are disturbing, like serialization. This disables proxy creation only for the specific context instance of db
db.Configuration.ProxyCreationEnabled = false;
http://blogs.msdn.com/b/adonet/archive/2011/01/31/using-dbcontext-in-ef-feature-ctp5-part-6-loading-related-entities.aspx
http://blogs.msdn.com/b/adonet/archive/2011/01/27/using-dbcontext-in-ef-feature-ctp5-part-1-introduction-and-model.aspx
I guess you are getting an exception at serialization due to lazy loading of the entities.
This thread may help you.
UPDATE:
Try if this working or not and if yes then the issue is mostly what I said
public IList<tblCustomerBooking> GettblCustomerBookings()
{
var custBookings = db.tblCustomerBookings.Include("tblRentals").AsEnumerable();
return custBookings
.Select(c => new tblCustomerBooking
{
customer_id = c.customer_id,
customer_name = c.customer_name,
customer_email = c.customer_email,
tblRentals = c.tblRentals
.Select(r => new tblRentals
{
rental_id = r.rental_id,
// other props exclude the
// tblCustomerBooking
})
}
).ToList();
}
I guess if you are using JSON.NET library with web api you can easily control the properties that don't need to be serialized by specifying the [JsonIgnore]
attribute and there by you can avoid writing the above LINQ query.
http://code.msdn.microsoft.com/Using-JSONNET-with-ASPNET-b2423706
http://james.newtonking.com/archive/2009/10/23/efficient-json-with-json-net-reducing-serialized-json-size.aspx
[Update]
1, change the action code to include the navigation property data:
// GET api/Bookings
public IEnumerable<tblCustomerBooking> GettblCustomerBookings()
{
return db.tblCustomerBookings.Include("tblRentals").AsEnumerable();
}
2, turn off proxy in data context
EF suggests to turn off proxy when serializing POCO.
If you want to support proxy, there are different ways for different serializers:
JSON.net serializer: It can support proxy by upgrading to latest version. Version 4.5.1 has a bug that can't support ignore NonserializedAttribute. It will block proxy to be serialized.
DataContractSerializer (JSON/XML): use ProxyDataContractResolver to resolve the types, here is a walkthrough.
3, enable preserving reference in model class
Both json.net and DataContract serializer support detecting circular reference and they give developer to control how to handle it.
Change the model class to following:
[JsonObject(IsReference = true)]
[DataContract(IsReference = true)]
public class tblCustomerBooking
{
[Key()]
public int customer_id { get; set; }
[DataMember]
public string customer_name { get; set; }
[DataMember]
public string customer_email { get; set; }
[DataMember]
public virtual ICollection<tblRental> tblRentals { get; set; }
}
public class tblRental
{
[Key()]
public int rental_id { get; set; }
public int room_id { get; set; }
public DateTime check_in { get; set; }
public DateTime check_out { get; set; }
public decimal room_cost { get; set; }
public int customer_id { get; set; }
[ForeignKey("customer_id")]
public virtual tblCustomerBooking tblCustomerBooking { get; set; }
}
Note that, if the model is attributed with DataContract, you have to specify DataMember for all its members, otherwise none of them will be serialized.
are you doing:
db.tblCustomerBookings.Include("tblRentals").Select(i =>
new { i.something //etc });
also, which MediaTypeFormatter are you using, Xml or Json? Error 500 often means that Formatter is choking.
Switch to JSON.NET formatter (in Web API RC the easiest way is to do GlobalConfiguration.Configuration.Formatters.RemoveAt(1)
- this removes XML formatter) and see if it helps or at least gives more meaningful error (or request your method with content type JSON).
You might want to add a global error handler to your project. It can trap and log any odd errors that are happening in background threads. This S/O article talks about some solid approaches. They will save you lots of time in any project: ASP.NET MVC Error Logging in Both Global.asax and Error.aspx
I struggled with this issue of serializing the proxy object to a poco as well. You can build into your context a flag that switches the db.Configuration.ProxyCreationEnabled = false;
Or you should set up a viewmodel and take the proxy object and assign the parameters to the viewmodel.
public IEnumerable<tblCustomerBooking> GettblCustomerBookings()
{
return db.tblCustomerBookings.Select(cb=> new CustomerBookingsViewModel{id=cb.Id, et.....);
}
or use an anonymous type:
.Select(cb=>new{id=cb.id....}