无法序列化内容类型的响应正文

时间:2012-12-27 10:26:34

标签: rest fluent-nhibernate asp.net-mvc-4 asp.net-web-api

我正在构建一个同时使用Controllers和ApiControllers的MVC4应用程序。我修改了默认Web API路由以包含操作名称。当我尝试获取基准列表时,我收到此错误消息:

  

'ObjectContent`1'类型无法序列化响应正文   内容类型'application / json;字符集= UTF-8'

InnerException就是这个(我在这种情况下返回JSON,与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)"
}

这是我运行的代码:

// 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;
        }

这是基准模型:

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

我不太清楚问题出在哪里。可能是NHibernate代理(我使用Fluent NHibernate)?奇怪的是,如果我不使用ApiController,并手动返回JSON,这就完美了!

更新

根据下面的答案,这是我必须在Application_Start()中添加的代码:

HttpConfiguration config = GlobalConfiguration.Configuration;
((DefaultContractResolver)config.Formatters.JsonFormatter.SerializerSettings.ContractResolver).IgnoreSerializableAttribute = true;

3 个答案:

答案 0 :(得分:9)

这解决了JSON错误,祝你好运。将其添加到Register Method下的WebApiConfig类中。

  var json = config.Formatters.JsonFormatter;
  json.SerializerSettings.PreserveReferencesHandling=Newtonsoft.Json.PreserveReferencesHandling.Objects;
  config.Formatters.Remove(config.Formatters.XmlFormatter);

更新:

我找到了两个解决方案。第一个也是最容易实现的是将任何IEnumerables,ICollections更改为List类型。 WebAPI可以序列化这些对象,但是它不能序列化接口类型。

public class Store
{

  [StringLength(5)]
    public string Zip5 { get; set; }

    public virtual List<StoreReport> StoreReports { get; set; }  //use a list here
 }

另一个选择是不使用本机JSON序列化程序,我发布的第一个方法仍然有用。

答案 1 :(得分:7)

NHibernate框架中的IdentityEqualityCompairer似乎有[SerializableAttribute]注释。

从对这里的答案Why won't Web API deserialize this but JSON.Net will?的评论中得出,看起来JSON.NET在WebApi使用和它的独立使用之间的配置略有不同。

  

默认情况下,Json.NET序列化程序将IgnoreSerializableAttribute设置为true。在WebAPI中,我们将其设置为false。

因此,如果您无法关闭[SerializableAttribute](因为它不在您的代码中),您可以尝试使用此答案here更改默认的WebApi JSON.NET设置以忽略它:

((DefaultContractResolver)config.Formatters.JsonFormatter.SerializerSettings.ContractResolver).IgnoreSerializableAttribute = true;

也许还会考虑使用DTO将结果发送到响应中 - 这样您就可以完全控制通过网络发送的对象。

答案 2 :(得分:2)

嗯,以下可能有所帮助。

我得到了同样的例外,在我的情况下,我首先传递了为实体代码创建的实际poco实体。因为它包含导航属性,例如IList Locations,我只是在它上面创建了viewmapper / dto实体以返回。

现在可以找到。

Poco实体:

public class Tag
{
public int Id{get;set;}
public string Title{get;set;}
public IList<Location> Locations{get;set;}
}

ViewMapper / DTO

public class TagResultsViewMapper
{
public int Id{get;set;}
public string Title{get;set;}
//just remove the following relationship 
//public IList<Location> Locations{get;set;}
}