3

問題なく XML にシリアル化する LINQ-to-SQL オブジェクトがあります。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を参照してください

概要: null 値を持つ 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 は単純なファイル トレース ライターでした。


アップデート

このバグの解決策を見つけました。

JSON オブジェクトをシリアル化するために WebAPI が使用するクラスは、JSON.NET から直接ではなく、System.Net.Http.Formatting にある JsonContractResolver のインスタンスに設定されます。幸いなことに、これはオープン ソースであるため、現在のバージョンは次の場所で確認できます。

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

この正確なコードを自分のクラスにコピーし、このコード (変更なし) を使用して JSON.NET のコントラクト リゾルバーを自分のクラスに置き換え、バグを修正しました。このことから、現在リリースされている WebAPI バージョン (System.Net.Http.Formatting バージョン 4.0.20710.0) にはバグがあり、次のリリースではおそらくこの問題が修正されると結論付けています。

私のように今すぐ修正する必要がある場合は、次の手順を実行します。

  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 に答える