3

我有一个 LINQ-to-SQL 对象,可以毫无问题地序列化为 XML。我可以调用 Newtonsoft.Json.JsonConvert.SerializeObject() 并得到 JSON 结果。当我在 WebAPI 中传递与对象相同的结果时,我得到一个错误(见下文)。我构建了一个跟踪编写器来捕获 null 内部异常路径,如果路径是 '' ,我不确定如何找出导致错误的项目?

20130301122959: Started serializing AnvilDB.Partner. Path ''.
20130301122959: Error serializing AnvilDB.Partner. An item with the same key has already been added. Path ''.
Error: An item with the same key has already been added.
   at System.ThrowHelper.ThrowArgumentException(ExceptionResource resource)
   at System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add)
   at System.Collections.Generic.Dictionary`2.Add(TKey key, TValue value)
   at System.Web.Http.Metadata.Providers.AssociatedMetadataProvider`1.CreateTypeInformation(Type type)
   at System.Web.Http.Metadata.Providers.AssociatedMetadataProvider`1.GetTypeInformation(Type type)
   at System.Web.Http.Metadata.Providers.AssociatedMetadataProvider`1.GetMetadataForProperty(Func`1 modelAccessor, Type containerType, String propertyName)
   at System.Web.Http.Validation.ModelValidationRequiredMemberSelector.IsRequiredMember(MemberInfo member)
   at System.Net.Http.Formatting.JsonContractResolver.ConfigureProperty(MemberInfo member, JsonProperty property)
   at System.Net.Http.Formatting.JsonContractResolver.CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
   at Newtonsoft.Json.Serialization.DefaultContractResolver.CreateProperties(Type type, MemberSerialization memberSerialization)
   at Newtonsoft.Json.Serialization.DefaultContractResolver.CreateObjectContract(Type objectType)
   at Newtonsoft.Json.Serialization.DefaultContractResolver.CreateContract(Type objectType)
   at Newtonsoft.Json.Serialization.DefaultContractResolver.ResolveContract(Type type)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.CalculatePropertyValues(JsonWriter writer, Object value, JsonContainerContract contract, JsonProperty member, JsonProperty property, JsonContract& memberContract, Object& memberValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(JsonWriter writer, Object value, JsonObjectContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)
20130301123002: Started serializing System.Web.Http.HttpError. Path ''.
20130301123002: Started serializing System.Web.Http.HttpError. Path 'InnerException'.
20130301123002: Finished serializing System.Web.Http.HttpError. Path 'InnerException'.
20130301123002: Finished serializing System.Web.Http.HttpError. Path ''.
4

2 回答 2

6

四处挖掘我发现我可以为序列化程序设置一个错误处理程序,然后检查 ErrorContext.Member 值。这指向 XElement 类型的属性。进一步搜索发现这是一个已知/报告的错误,但尚未修复;见https://github.com/JamesNK/Newtonsoft.Json/issues/53

摘要:如果您有一个具有空值的 XElement 属性,JSON.NET 将失败。

这是我为诊断根本原因而添加的内容:

    base.Configuration.Formatters.JsonFormatter.SerializerSettings.Error = (sender, args) =>
    {
        string e = string.Format("{0}: {1}", args.ErrorContext.Member, args.ErrorContext.Path, args.ErrorContext.Error.Message);
        myTracer.Trace(System.Diagnostics.TraceLevel.Error, e, args.ErrorContext.Error);
    };

myTracer 是一个简单的文件跟踪编写器。


更新

我现在找到了解决此错误的方法。

WebAPI 用来序列化 JSON 对象的类不是直接来自 JSON.NET,而是设置为 JsonContractResolver 的一个实例,该实例位于 System.Net.Http.Formatting 中。幸运的是这是开源的,所以你可以在这里看到当前版本:

http://aspnetwebstack.codeplex.com/SourceControl/changeset/view/4764b0111b91#src/System.Net.Http.Formatting/Formatting/JsonContractResolver.cs

我将这个确切的代码复制到我自己的类中,并用我自己的类替换了 JSON.NET 中的 Contract Resolver,使用此代码(未更改)并修复了错误。由此我得出结论,当前发布的 WebAPI 版本(System.Net.Http.Formatting 版本 4.0.20710.0)存在 bug,下一个版本大概会修复这个问题。

如果您像我一样需要立即修复它,请执行以下步骤:

  1. 使用 JsonContractResolver.cs 代码创建您自己的合约解析器类
  2. 更改您的启动配置以覆盖 ContractResolver 设置:

样本:

var settings = System.Web.Http.GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings; 
// create formatter 
var formatter = new System.Net.Http.Formatting.JsonMediaTypeFormatter(); 
settings.ContractResolver = new MyJsonContractResolver(formatter);

这应该会有所帮助。

于 2013-03-01T14:50:37.943 回答
0

这看起来像 Web API 中的错误。我建议在这里提交一个关于它的错误:

http://aspnetwebstack.codeplex.com/workitem/list/basic

同时,我认为您可以通过如下设置配置来解决此问题:

config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new DefaultContractResolver();
于 2013-03-01T13:12:52.500 回答