ASP.NET WebAPI(逆)シーケンス化[SerializableAttribute]で修飾されたクラスのピット

3088 ワード

問題を発見する


ASP.NET WebAPIプロジェクトには、このようなViewModelクラスがあります.
[Serializable]
class Product
{
    public int Id { get; set; }
    public decimal Price { get; set; }
    public DateTime ProductDate { get; set; }
}

ControllerとActionコードは次のとおりです.
public class ProductController : ApiController
{
    public Product Get(int id)
    {
        return new Product()
        {
            Id = 1,
            Price = 12.9m,
            ProductDate = new DateTime(1992, 1, 1)
        };
    }
}

クライアントはこのリソースを要求した:http://localhost:5000/api/product/1、その結果、WebAPIは次のようなJSONを返すことが分かった.
{
  "k__BackingField": 1,
  "k__BackingField": 12.9,
  "k__BackingField": "1992-01-01T00:00:00"
}

自動プロパティにはフィールドが定義されていませんが、C#コンパイラはprivate int k__BackingFieldのような対応するプライベートフィールドを生成します.WebAPIのシーケンス化では属性名をJSONのキーとして使用することを期待していますが、ここでWebAPIのシーケンス化はコンパイラが生成したプライベートフィールドであり、明らかに私たちの要求に合致しません.
変なところは、Jsonを単独で使うと.NETクラスライブラリをシーケンス化すると、期待されるJSONが得られ、以下のようになる.
{
  "Id": 1,
  "Price": 12.9,
  "ProductDate": "1992-01-01T00:00:00"
}

原因を見つける


Googleを経て、SerializableAttributeと関係があった.JsonからNET 4.5 Release 2のリリースが始まり、このような機能が追加されました.
タイプにSerializableAttributeがあることが検出された場合、そのタイプのすべてのプライベート/公開フィールドがシーケンス化され、そのプロパティは無視されます.この新しいプロパティが不要な場合は、クラスにJsonObjectAttributeを適用して上書きするか、D e f a u l t ContractResolverのI g n o r e SerializableAttributeをグローバル範囲でtrueに設定します.release 3のバージョンからI g n o r e SerializableAttributeのデフォルトはtrueです.
ASP.NET WebAPIはJsonに依存する.NETは、IgnoreSerializableAttributeをfalseに設定します.つまり、SerializableAttributeを無視しないため、クラスが[SerializableAttribute]で修飾されると、シーケンス化されたフィールドのみが属性を無視し、自動属性を使用するとコンパイラが自動的に生成するフィールド名が出力されます.

問題を解決する


問題の原因を理解したら、以下の方法で解決できます.
  • [Serializable]
  • を削除
  • アプリケーション[JsonObjectAttribute]
  • I n g o r e SerializableAttribute
  • の設定
    最も簡単な方法は[Serializable]を取り除くことであり,何らかの理由で取り除くことができなければ,他の2つの方法を用いることができる.

    JsonObjectAttributeの適用

    [Newtonsoft.Json.JsonObject]
    [System.Serializable]
    class Product
    {
        public int Id { get; set; }
        public decimal Price { get; set; }
        public DateTime ProductDate { get; set; }
    }

    I g n o r e SerializableAttributeの設定

    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            //        .........
    
            //   SerializerSettings        IgnoreSerializableAttribute = true
            config.Formatters.JsonFormatter.SerializerSettings = new JsonSerializerSettings();
        }
    }

    参考:Json.NET 4.5 Release 2 – Serializable support and bug fixesWhy won't Web API deserialize this but JSON.Net will?
    転載先:https://www.cnblogs.com/songxingzheng/p/6482431.html