json – OData序列化
我一直在努力寻找一个自定义序列化过去2个月从OData控制器返回的实体的解决方案!请帮忙!!!
用例非常简单,我已经简化了它以解决问题点.我有一些虚拟字段附加到我的模型中的某些实体,例如:
1public class Customer 2{ 3 public int CustomerId { get; set; } 4 public string FirstName { get; set; } 5 public string LastName { get; set; } 6 public string VirtualField1 { get; set; } 7 public string VirtualField2 { get; set; } 8 public string VirtualField3 { get; set; } 9} 10
现在,假设客户端已将VirtualField1配置为“CompanyName”.
我想要做的就是创建一个自定义JSON序列化器和反序列化器:
对客户的任何GET请求(当然还有客户 – 即IQueryable<>)将通过此序列化程序,如果每个客户都有一个集合,它将用“CompanyName”替换字段“VirtualField1”的名称.
任何POST请求都将通过相反的替换 – 即 – 将“CompanyName”替换为“VirtualField1”.
**实际的替换逻辑有点复杂,但想法是一样的.
我已经阅读了谷歌本可以找到的所有内容,但找不到任何有效的例子.
以下是一些链接:
https://aspnetwebstack.codeplex.com/wikipage?title=OData%20formatter%20extensibility
**现在的OData API有点不同,但我认为原理是一样的.
customizing odata output from asp.net web api
Using OData in webapi for properties known only at runtime
所有链接的常见(以及我发现的任何信息)是我必须从DefaultODataSerializerProvider继承并将其添加到我的格式化程序:
在WebApiConfig.cs上:
1var customFormatters = ODataMediaTypeFormatters.Create(new CustomODataSerilizerProvider(), new CustomODataDeSerilizerProvider()); 2 config.Formatters.InsertRange(0, customFormatters); 3
和实际的提供者和序列化器:
1public class CustomODataSerilizerProvider : DefaultODataSerializerProvider 2 { 3 public override ODataEdmTypeSerializer GetEdmTypeSerializer(IEdmTypeReference edmType) 4 { 5 if (edmType.IsEntity()) 6 { 7 return new CustomODataEntityTypeSerializer(edmType.AsEntity(), this); 8 } 9 10 return base.GetEdmTypeSerializer(edmType); 11 } 12 } 13
**对于IQueryable结果,edmType.IsEntity()永远不会为true,因此它永远不会创建具体的序列化程序.如果我强制创建它仍然不会在CreateEntity(或任何其他创建方法)上中断.
1public class CustomODataEntityTypeSerializer : ODataEntityTypeSerializer 2 { 3 public CustomODataEntityTypeSerializer(IEdmEntityTypeReference entityType, ODataSerializerProvider serializerProvider) 4 : base(serializerProvider) 5 { 6 } 7 8 public override ODataEntry CreateEntry(SelectExpandNode selectExpandNode, EntityInstanceContext entityInstanceContext) 9 { 10 var oDataEntry = base.CreateEntry(selectExpandNode, entityInstanceContext); 11 return oDataEntry; 12 } 13 } 14
如果我将具体的序列化程序更改为从ODataCollectionSerializer继承:
1public override ODataEdmTypeSerializer GetEdmTypeSerializer(IEdmTypeReference edmType) 2 { 3 4 if (edmType.IsCollection()) 5 { 6 return new CollectionSerilizer(this); 7 } 8 9 return base.GetEdmTypeSerializer(edmType); 10 } 11
和
1public class CollectionSerilizer : ODataCollectionSerializer 2{ 3 public CollectionSerilizer(ODataSerializerProvider serializerProvider) : base(serializerProvider) 4 { 5 } 6 7 public override ODataCollectionValue CreateODataCollectionValue(IEnumerable enumerable, IEdmTypeReference elementType, 8 ODataSerializerContext writeContext) 9 { 10 var oDataCollectionValue = base.CreateODataCollectionValue(enumerable, elementType, writeContext); 11 return oDataCollectionValue; 12 } 13 14 public override void WriteObject(object graph, Type type, ODataMessageWriter messageWriter, ODataSerializerContext writeContext) 15 { 16 base.WriteObject(graph, type, messageWriter, writeContext); 17 } 18} 19
它确实在WriteObject上的断点处停止但是不起作用并且基础正在抛出:
“指定为集合的项类型的类型’Models.Customer’不是原始的或复杂的.ODataCollectionWriter只能写出原始值或复数值的集合.”
另一个有趣的事情是,即使我插入所谓的默认提供商:
1var customFormatters = ODataMediaTypeFormatters.Create(new DefaultODataSerializerProvider(), new DefaultODataDeserializerProvider()); 2 config.Formatters.InsertRange(0, customFormatters); 3
无论他们的立场如何,也就是在开头:
1config.Formatters.InsertRange(0, customFormatters); 2
或者最后:
1config.Formatters.AddRange(customFormatters); 2
OData功能 – 例如:$exapnd,如/ odata / Customers?$expand =图像完全消失,根本不起作用(这里是响应):
1[{"Images":[],"CustomerId":1,"FirstName":"Bla","LastName":"Bla", "VirtualField1":null] 2
尽管没有添加自定义格式化程序,但此实例中的图像未展开.
任何想法,想法,方向???
回答可能为时已晚,但我注意到,当涉及到OData V1-3和OData V4时微软OData工具包之间的序列化时,可用性存在显着差异.
我认为你正在使用V4,因为我也试图获得DefaultODataSerializerProvider的挂起,并且没有成功.
然后我开始了一个新的Web Api项目,为OData V1-3添加了所有NuGet包,添加了一个Web Api OData控制器,并立即成功进行任何形式的序列化定制.
这是因为OData V1-3与自定义MediaTypeFormatters一起工作,就像WebApi一样.在那之后它变得像饼一样容易.
我不会插入关于此的代码,因为使用MediaTypeFormatter的示例很多,如下所示:
http://www.asp.net/web-api/overview/formats-and-model-binding/media-formatters
好吧,你会失去一些V4功能:
http://www.asp.net/web-api/overview/releases/whats-new-in-aspnet-web-api-22\#OData
但是我确信你可以在没有严格的V4 Oasis实施的麻烦的情况下生活,微软以一种比你更圣洁的方式遵循. (可能因为这是他们开始的东西).
V4中最重要的功能:
支持OData模型中的别名属性
谁在乎.
支持ODataConventionModelBuilder中的ComplexTypeAttribute,AssociationAttribute,TimesTampAttribute和ConcurrencyCheckAttribute
你不需要它们.
提供为行动提供友好标题的能力
谁在乎.
与ODL UriParser集成
我不明白.
支持枚举,遏制和单身
你不需要那个.
支持原始类型的转换
你不需要那个.
添加了OData功能支持
这是不幸的,但通过在OData旁边使用普通的ApiController可以轻松解决.
支持函数调用的参数别名
你不需要它,无论如何都很麻烦.
支持模型中的驼峰案例命名约定
很高兴它有支持,但我建议不要这样做.
支持$filter中的cast()
不需要它.
支持开放复杂类型
是啊?您有自定义序列化.您可以序列化您想要的任何类型.
删除了EntitySetController和AsyncEntitySetController
好摆脱.
将$link更改为$ref
好的
添加了属性路由支持
不幸的是,您仍然坚持使用您在WebApiConfig中定义的路线.很重要.
问问自己,你在使用OData是为了什么?
我显然不能代表您的情况,但我会对您的用例进行分析:
– 您试图允许通过http向数据源发出复杂问题,因为您不希望每次客户端N想出新问题时都更改界面.
– 您正在尝试允许客户端请求他/她获取的数据的实际格式. CSV? XML? JSON?电子名片?哎呀,奥特? PDF?
如果这两个目标是你真正想要实现的目标,那就坚持使用V3.你将为自己省去一大堆痛苦,实现你的领域模式.
虽然我0.02美元.