I'm building a MVC4 application that uses both Controllers and ApiControllers. I modified the default Web API route to include action names. When I try to get a list of Benchmarks, I'm getting this error message:
The 'ObjectContent`1' type failed to serialize the response body for content type 'application/json; charset=utf-8'
The InnerException is this (I'm returning JSON in that case, same happens with XML):
"InnerException": {
"Message": "An error has occurred.",
"ExceptionMessage": "Error getting value from 'IdentityEqualityComparer' on 'NHibernate.Proxy.DefaultLazyInitializer'.",
"ExceptionType": "Newtonsoft.Json.JsonSerializationException",
"StackTrace": " at Newtonsoft.Json.Serialization.DynamicValueProvider.GetValue(Object target) at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(JsonWriter writer, Object value, JsonObjectContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty) at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(JsonWriter writer, Object value, JsonContract valueContract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty) at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeISerializable(JsonWriter writer, ISerializable value, JsonISerializableContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty) at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(JsonWriter writer, Object value, JsonContract valueContract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty) at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(JsonWriter writer, Object value, JsonObjectContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty) at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(JsonWriter writer, Object value, JsonContract valueContract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty) at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeList(JsonWriter writer, IWrappedCollection values, JsonArrayContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty) at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(JsonWriter writer, Object value, JsonContract valueContract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty) at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.Serialize(JsonWriter jsonWriter, Object value) at Newtonsoft.Json.JsonSerializer.SerializeInternal(JsonWriter jsonWriter, Object value) at System.Net.Http.Formatting.JsonMediaTypeFormatter.<>c__DisplayClassd.<WriteToStreamAsync>b__c() at System.Threading.Tasks.TaskHelpers.RunSynchronously(Action action, CancellationToken token)",
"InnerException": {
"Message": "An error has occurred.",
"ExceptionMessage": "Common Language Runtime detected an invalid program.",
"ExceptionType": "System.InvalidProgramException",
"StackTrace": " at GetIdentityEqualityComparer(Object ) at Newtonsoft.Json.Serialization.DynamicValueProvider.GetValue(Object target)"
}
This is the code that I run:
// GET api/benchmark/getincomplete
[HttpGet]
public IList<Benchmark> GetIncomplete()
{
var s = HibernateModule.CurrentSession;
var benchList = s.QueryOver<Benchmark>()
.Where(b => !b.Completed)
.Where(b => !b.Deleted)
.OrderBy(b => b.Id).Asc
.List<Benchmark>();
return benchList;
}
And this is the Benchmark model:
public class Benchmark
{
public virtual int Id { get; set; }
[Required]
[DataType(DataType.Date)]
public virtual DateTime Date { get; set; }
[Required, ScriptIgnore]
public virtual IList<TestResult> Results { get; set; }
[Required]
public virtual IList<TestCase> TestCases { get; set; }
[AllowHtml]
public virtual string Description { get; set; }
public virtual Device Device { get; set; }
public virtual bool Published { get; set; }
[Display(Name = "Deleted"), ScriptIgnore]
public virtual bool Deleted { get; set; }
public virtual bool Completed { get; set; }
public Benchmark()
{
Results = new List<TestResult>();
TestCases = new List<TestCase>();
Published = false;
Deleted = false;
Completed = false;
}
}
I'm not quite sure where the problem lies. Could it be the NHibernate Proxy (I use Fluent NHibernate)? The odd thing is that if I don't use an ApiController, and manually return JSON, this works just perfectly!
Update:
As per the answer below, this is the code I had to add in Application_Start() :
HttpConfiguration config = GlobalConfiguration.Configuration;
((DefaultContractResolver)config.Formatters.JsonFormatter.SerializerSettings.ContractResolver).IgnoreSerializableAttribute = true;
This fixes the JSON error, good luck with XML. Add this to the WebApiConfig class under the Register Method.
UPDATE:
I found two solutions to this. The first and easiest to implement is to change any IEnumerables, ICollections to a type of List. The WebAPI can serialize this objects, it however cannot serialize interface types.
The other option is to not use the native JSON serializer the first method I posted still works.
The
IdentityEqualityCompairer
in the NHibernate framework appears to have the[SerializableAttribute]
annotation.Taken from a comment on an answer here Why won't Web API deserialize this but JSON.Net will? it looks like JSON.NET is configured a little differently between WebApi usage and it's standalone usage.
So given you cannot take the
[SerializableAttribute]
off (as it is not within your code) you could try changing the default WebApi JSON.NET setting to ignore it using this answer here:Perhaps also consider Using a DTO for your results being sent over in the response - this will give you full control over the object being sent over the wire.
hmmm, Following may help.
I was getting the same exception, and in my case I was passing the actual poco entity created for entity code first. Since, it contains navigation properties such as IList Locations, I just created the viewmapper/dto entity on top of it to return.
It works find now.
Poco Entity:
ViewMapper/Dto