WebAPI 2 としての JSON.NET OData シリアライザーと ODataMediaTypeFormatter 質問する

WebAPI 2 としての JSON.NET OData シリアライザーと ODataMediaTypeFormatter 質問する

WebAPI 2 スタックで JSON.NET をデフォルトのシリアライザーとして使用しようとしています。JsonMediaTypeFormatter を実装し、その中でデータのシリアル化/デシリアル化に JSON.NET シリアライザーを使用し、このメディア タイプ フォーマッタを使用するために JsonContentNegotiator を作成しました。OData クエリを除いてすべて正常に動作します。アクション メソッドに [Queryable] メタデータを追加すると、応答オブジェクトにはメタデータ情報が含まれず、エンティティのリストのみが含まれます。

小さな例。私のアクションメソッド:

[Queryable]
public async Task<PageResult<RuleType>> GetRuleType(ODataQueryOptions<RuleType> options)
{
    var ret = await _service.ListRuleTypesAsync(options);
    return new PageResult<RuleType>(
        ret,
        Request.GetNextPageLink(),
        Request.GetInlineCount());
}

デフォルトの OData シリアル化を使用し、ルール タイプ (例: .../odata/RuleType?$inlinecount=allpages&$skip=0&$top=1) でクエリを呼び出すと、メタデータ情報と count プロパティを含む従来の OData 応答が返されます。

odata.metadata ".../odata/$metadata#RuleType" 
odata.count    "2" 
value
        0    {
                 Id: 1
             Name: "General"
             Code: "General"
             Notes: null
             }

(一部のフィールドはスキップされていますが、Notes プロパティには null 値があります) ただし、シリアライザーとしてJsonContentNegotiatorwithを追加するとJsonMediaTypeFormatter、エンティティのリストのみが返されます。

[
  {
    "Id": 1,
    "Name": "General",
    "Code": "General"
  }
]

(Notes フィールドはここにはありませんNullValueHandling.Ignore。) さらに、[Queryable]アクション メソッドで属性を削除すると、別の結果が得られます。

{
  "Items": [
    {
      "Id": 1,
      "Name": "General",
      "Code": "General"
    }
  ],
  "Count": 2
}

この場合、Count は受け取りましたが、メタデータはまだありません。また、odata 応答プロパティ名はデフォルトとはまったく異なります。

頭が混乱しています。Web アプリのどの部分でも、JSON.NET をシリアライザーとして使用したいだけです (いくつかの厳しい制限があるため)。どうすればいいでしょうか?

ベストアンサー1

私はすでに自分の問題を理解し、解決策を見つけました。ODataはODataMediaTypeFormatterから継承された個別のメディアタイプフォーマッタを使用します。また、ODataはシリアル化とデシリアル化に異なるフォーマッタを使用します。この動作を置き換えるには、ODataDeserializerProviderクラスおよび/またはODataSerializerProviderクラスの子孫を実装し、それらのクラスをHttpConfiguration.Formattersコレクションに追加する必要があります。

var odataFormatters = ODataMediaTypeFormatters
    .Create(new MyODataSerializerProvider(), new MuODataDeserializerProvider());
config.Formatters.AddRange(odataFormatters);

小さなデシリアライゼーション プロバイダーの例:

public class JsonODataDeserializerProvider : ODataDeserializerProvider
{
    public override ODataEdmTypeDeserializer GetEdmTypeDeserializer(IEdmTypeReference edmType)
    {
        var kind = GetODataPayloadKind(edmType);

        return new JsonODataEdmTypeDeserializer(kind, this);
    }

    private static ODataPayloadKind GetODataPayloadKind(IEdmTypeReference edmType)
    {
        switch (edmType.TypeKind())
        {
            case EdmTypeKind.Entity:
                return ODataPayloadKind.Entry;
            case EdmTypeKind.Primitive:
            case EdmTypeKind.Complex:
                return ODataPayloadKind.Property;
            case EdmTypeKind.Collection:
                IEdmCollectionTypeReference collectionType = edmType.AsCollection();
                return collectionType.ElementType().IsEntity() ? ODataPayloadKind.Feed : ODataPayloadKind.Collection;
            default:
                return ODataPayloadKind.Entry;
        }
    }

    public override ODataDeserializer GetODataDeserializer(IEdmModel model, Type type, HttpRequestMessage request)
    {
        var edmType = model.GetEdmTypeReference(type);

        return edmType == null ? null : GetEdmTypeDeserializer(edmType);
    }
}

ODataデシリアライザー:

public class JsonODataEdmTypeDeserializer : ODataEdmTypeDeserializer
{
    public JsonODataEdmTypeDeserializer(ODataPayloadKind payloadKind) : base(payloadKind)
    {
    }

    public JsonODataEdmTypeDeserializer(ODataPayloadKind payloadKind, ODataDeserializerProvider deserializerProvider) : base(payloadKind, deserializerProvider)
    {
    }

    public override object Read(ODataMessageReader messageReader, Type type, ODataDeserializerContext readContext)
    {
        var data = readContext.Request.Content.ReadAsStringAsync().Result;

        return JsonConvert.DeserializeObject(data, type);
    }
}

また、このクラスは内部クラスであるため、GetEdmTypeReference() および GetEdmType() メソッドを使用して、WebAPI OData ソース コードから EdmLibsHelper クラスをプロジェクトに追加しました。

おすすめ記事