【问题标题】:Failed to serialize the response body for content type未能序列化内容类型的响应正文
【发布时间】:2012-12-12 18:01:04
【问题描述】:

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

“ObjectContent`1”类型未能序列化响应正文 内容类型'应用程序/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;

【问题讨论】:

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


    【解决方案1】:

    这修复了 JSON 错误,祝 XML 好运。将此添加到注册方法下的 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 这让我一整天都陷入困境,这就是让这一切发生的答案。太感谢了!!我还在需要的地方添加了[JsonIgnore]
    • 我想在我的 web api 中使用未被实体框架跟踪的 ViewModel,这个解决方案成功地序列化了我的新类型
    【解决方案2】:

    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 将结果发送到响应中 - 这将使您可以完全控制通过网络发送的对象。

    【讨论】:

    • 确实解决了这个问题!现在我遇到了另一个问题,因为 NHibernate 没有实现一个功能,但这是一个不同的话题。
    • 只需将该代码添加到WebApiConfig.cs?为什么NHibernate 会出现在这里?
    【解决方案3】:

    嗯,以下可能会有所帮助。

    我遇到了同样的异常,在我的情况下,我首先传递了为实体代码创建的实际 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;}
    }
    

    【讨论】:

    • 从类中删除整个关系并不是一个解决方案。
    • @RaySülzer 在那种特定的情况下它对我有用。可能是你有不同的问题。但是,我设置了另一个角度来看待问题。可能有人可以从中受益。你为什么投了反对票。我可以向您发送示例/演示来证明这一点。所以请不要投它,而不是投反对票
    • 但是你返回的是一个完全不同的类......为什么不从原始类中删除公共 IList 呢?人们遇到这个问题是因为他们需要使用 Enity Framework 序列化 ICollections,而 Microsoft 可耻地忽略了这一需求。
    • 好吧,这只是一个例子。每当您更改 ef poco 实体时。您将其命名为 dto、viewmapper 或您想要命名的名称。因为,如果您从 ef poco 中删除导航属性。它会破坏实体关联。所以我们的想法是保持域设计不变,并且只获取所需的信息。
    猜你喜欢
    • 2013-03-28
    • 2017-02-01
    • 2016-02-07
    • 1970-01-01
    • 2017-07-17
    • 1970-01-01
    • 2012-10-07
    • 1970-01-01
    • 2013-10-01
    相关资源
    最近更新 更多