问题描述
我正在尝试使用 JSON.NET 作为 WebAPI 2 堆栈中的默认序列化程序.我已经实现了 JsonMediaTypeFormatter,其中我使用 JSON.NET 序列化程序来序列化/反序列化数据,并创建了 JsonContentNegotiator 来使用这个媒体类型格式化程序.除 OData 查询外,一切正常 - 如果我添加 [Queryable] 元数据 ot 操作方法,则响应对象不包含任何元数据信息,仅包含实体列表.
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 属性)但是,如果我将 JsonContentNegotiator
与 JsonMediaTypeFormatter
添加为序列化程序 - 我只会收到实体列表:
(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
,此处没有备注字段)更.如果我在操作方法中删除 [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.
我的心都快炸了.我只想在我的网络应用程序的任何部分使用 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的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!