【发布时间】:2014-02-19 16:14:20
【问题描述】:
在过去的 2 个个月,我一直在尝试寻找一种自定义序列化从 OData 控制器返回的实体的解决方案!请帮忙!!!
用例非常简单,为了解决问题,我进一步简化了它。我的模型中的某些实体附加了一些虚拟字段,例如:
public class Customer
{
public int CustomerId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string VirtualField1 { get; set; }
public string VirtualField2 { get; set; }
public string VirtualField3 { get; set; }
}
现在,假设客户端已将 VirtualField1 配置为“CompanyName”。
我要做的就是创建一个自定义的 JSON 序列化器和反序列化器:
- 任何对客户(当然客户 - 即 - IQueryable)的 GET 请求都将通过此序列化程序,该序列化程序将在每个客户的集合案例。
- 任何 POST 请求都将通过相反的替换 - 即 - 将“CompanyName”替换为“VirtualField1”。
** 实际的替换逻辑有点复杂,但思路是一样的。
我已经阅读了 google 可以找到的所有内容,但找不到任何可行的示例。
以下是一些链接:
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 上:
var customFormatters = ODataMediaTypeFormatters.Create(new CustomODataSerilizerProvider(), new CustomODataDeSerilizerProvider());
config.Formatters.InsertRange(0, customFormatters);
以及实际的提供者和序列化器:
public class CustomODataSerilizerProvider : DefaultODataSerializerProvider
{
public override ODataEdmTypeSerializer GetEdmTypeSerializer(IEdmTypeReference edmType)
{
if (edmType.IsEntity())
{
return new CustomODataEntityTypeSerializer(edmType.AsEntity(), this);
}
return base.GetEdmTypeSerializer(edmType);
}
}
** edmType.IsEntity() 对于 IQueryable 结果永远不会为真,因此它永远不会创建具体的序列化程序。如果我强制创建它仍然不会在 CreateEntity (或任何其他创建方法)上中断。
public class CustomODataEntityTypeSerializer : ODataEntityTypeSerializer
{
public CustomODataEntityTypeSerializer(IEdmEntityTypeReference entityType, ODataSerializerProvider serializerProvider)
: base(serializerProvider)
{
}
public override ODataEntry CreateEntry(SelectExpandNode selectExpandNode, EntityInstanceContext entityInstanceContext)
{
var oDataEntry = base.CreateEntry(selectExpandNode, entityInstanceContext);
return oDataEntry;
}
}
如果我将具体的序列化程序更改为从 ODataCollectionSerializer 继承:
public override ODataEdmTypeSerializer GetEdmTypeSerializer(IEdmTypeReference edmType)
{
if (edmType.IsCollection())
{
return new CollectionSerilizer(this);
}
return base.GetEdmTypeSerializer(edmType);
}
和
public class CollectionSerilizer : ODataCollectionSerializer
{
public CollectionSerilizer(ODataSerializerProvider serializerProvider) : base(serializerProvider)
{
}
public override ODataCollectionValue CreateODataCollectionValue(IEnumerable enumerable, IEdmTypeReference elementType,
ODataSerializerContext writeContext)
{
var oDataCollectionValue = base.CreateODataCollectionValue(enumerable, elementType, writeContext);
return oDataCollectionValue;
}
public override void WriteObject(object graph, Type type, ODataMessageWriter messageWriter, ODataSerializerContext writeContext)
{
base.WriteObject(graph, type, messageWriter, writeContext);
}
}
它确实在 WriteObject 上的断点处停止,但不起作用并且基础正在抛出:
“指定为集合项类型的类型‘Models.Customer’不是原始或复杂的。ODataCollectionWriter 只能写入原始或复杂值的集合。”
另一个有趣的事情是,即使我插入了所谓的默认提供程序:
var customFormatters = ODataMediaTypeFormatters.Create(new DefaultODataSerializerProvider(), new DefaultODataDeserializerProvider());
config.Formatters.InsertRange(0, customFormatters);
无论他们的位置如何,要么是在开头:
config.Formatters.InsertRange(0, customFormatters);
或在最后:
config.Formatters.AddRange(customFormatters);
OData 功能 - 即 - 例如:在 /odata/Customers?$expand=Images 中的 $exapnd 完全消失并且根本不起作用(这是响应):
[{"Images":[],"CustomerId":1,"FirstName":"Bla","LastName":"Bla", "VirtualField1":null]
尽管没有添加它们所做的自定义格式化程序,但此实例中的图像未扩展。
有什么想法、想法、方向???
【问题讨论】:
-
你有没有找到答案,我有一个带有自定义集合的类型,我使用自定义 JsonConverter 这适用于 vanilla WebAPI,但是一旦我将 OData 引入混合对象从 API 返回的不能再在我的客户端中反序列化。我几乎没有发现如何让这个工作。如果您找到了解决方案,可以分享一下吗?
-
不幸的是,我没有,而且据我所知,它不能使用 ODate 完成。究其原因,深层次是OData的序列化机制,与模型深度耦合。因此修改模型会破坏序列化。我认为存在的唯一可能的方法是添加一些过滤器 After 序列化发生。祝你好运,如果你找到方法,请添加一些信息。
-
我放弃了这种方法。我决定删除 OData 包并坚持使用 vanilla WebAPI,因为创建和使用可跟踪实体对我来说更重要。
-
祝你好运!使用 API 很好,但是在发送循环依赖对象时要小心,因为 JSON 序列化器在这方面做得不好(A 包含 B 包含 A,如果不处理,基本上会导致无限响应,这显然是避免使用 OData,因为您必须使用 $expand 来获取对象访问器)。
-
谢谢。顺便说一句:WebAPI 现在使用 Json.NET,它非常擅长处理 ref 循环。
标签: json serialization asp.net-web-api odata