序列化 – JSON.NET作为WebAPI 2 OData序列化程序与ODataMediaTypeFormatter

我试图使用JSON.NET作为WebAPI 2堆栈中的默认序列化程序.我已经实现了JsonMediaTypeFormatter,其中我已经使用JSON.NET serializer进行序列化/反序列化数据,并创建了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)调用某些查询,我将收到带有元数据信息的经典OData响应,计数属性:

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

(有些字段被跳过,但是我的Notes属性为null值)
但是,如果我添加JsonContentNegotiator与JsonMediaTypeFormatter作为一个序列化程序 – 我只收到实体列表:

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

(没有Notes字段,因为NullValueHandling.Ignore)
更.如果我删除动作方法中的[Queryable]属性 – 我收到另一个结果:

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

在这种情况下,我收到了Count,但是在这里仍然没有元数据. odata响应属性名称与默认值完全不同.

我的头脑正在吹起来我只想使用JSON.NET作为我的Web应用程序的任何部分的序列化程序(由于一些强大的限制).我该怎么做?

最佳答案
我已经弄清楚了我的问题,找到了解决方案. 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);
    }
}

ODataDeserializer:

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);
    }
}

而且我也从WebAPI OData源代码添加了EdmLibsHelper类,在GetEdmTypeReference()和GetEdmType()方法的项目中,因为这个类是内部的.

转载注明原文:序列化 – JSON.NET作为WebAPI 2 OData序列化程序与ODataMediaTypeFormatter - 代码日志