本文介绍了JSON.NET 作为 WebAPI 2 OData 序列化器与 ODataMediaTypeFormatter的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用 JSON.NET 作为 WebAPI 2 堆栈中的默认序列化程序.我已经实现了 JsonMediaTypeFormatter,其中我使用了 JSON.NET 序列化器来序列化/反序列化数据,并创建了 JsonContentNegotiator 来使用这个媒体类型格式化器.除了 OData 查询之外,一切正常 - 如果我添加 [Queryable] 元数据或操作方法,则响应对象不包含任何元数据信息,仅包含实体列表.

I'm trying to use JSON.NET as a default serializer in WebAPI 2 stack. I've implemented JsonMediaTypeFormatter, in which I've used JSON.NET serializer for serialize/deserialize data and created JsonContentNegotiator for using this media type formatter. All works fine except OData querying - if I add [Queryable] metadata ot action method, then response object doesn't contains any metadata information, only list of entities.

小例子.我的操作方法:

Small example. My action method:

[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 响应:

If I use default OData serialize and call some query by Rule type (for example - .../odata/RuleType?$inlinecount=allpages&$skip=0&$top=1), I receive classic OData response with metadata info and count property:

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

(跳过了一些字段,但我的 Notes 属性为空值)但是如果我添加我的 JsonContentNegotiatorJsonMediaTypeFormatter 作为序列化器 - 我只收到实体列表:

(some fields skipped, but I have Notes property with null value)But if I add my JsonContentNegotiator with JsonMediaTypeFormatter as a serializer - I receive only list of entities:

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

(由于 NullValueHandling.Ignore,这里没有 Notes 字段)更.如果我在操作方法中删除 [Queryable] 属性 - 我会收到另一个结果:

(no Notes field here because of NullValueHandling.Ignore)Even more. If I remove [Queryable] attribute in action method - I receive another result:

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

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

In this case I've received Count, but still no metadata here. And also odata response property names completely differs from default.

我脑子里一片空白.我只想在我的 Web 应用程序的任何部分中使用 JSON.NET 作为我的序列化程序(由于一些严格的限制).我该怎么做?

My mind is blowing up. I just want to use JSON.NET as my serializer in any part of my web app (because of some strong restrictions). How can I do this?

推荐答案

我已经找到了我的问题并找到了解决方案.OData 使用从 ODataMediaTypeFormatter 继承的单独媒体类型格式化程序.OData 还使用不同的格式化程序进行序列化和反序列化.为了替换这种行为,我们必须实现 ODataDeserializerProvider 和/或 ODataSerializerProvider 类的后代,并将这些类添加到 HttpConfiguration.Formatters 集合中

I've already figured out my problem and found the solution. OData uses separate media type formatters, inherited from ODataMediaTypeFormatter. Also OData uses different formatters for serialization and deserialization. For replacing this behavior we have to implement descendants of ODataDeserializerProvider and/or ODataSerializerProvider classes and add those classes to the HttpConfiguration.Formatters collections by

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

小型反序列化提供程序示例:

Small deserialization provider example:

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:

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

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

And I also have added EdmLibsHelper class from WebAPI OData source code in my project with GetEdmTypeReference() and GetEdmType() methods because this class is internal.

这篇关于JSON.NET 作为 WebAPI 2 OData 序列化器与 ODataMediaTypeFormatter的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-04 23:13