我一直在尝试为过去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请求都将通过此序列化器进行处理,在每个客户集合中用"CompanyName"替换字段"VirtualField1"的名称。
- 任何POST请求都将经过相反的替换 - 也就是用"VirtualField1"替换"CompanyName"。
** 实际的替换逻辑有点复杂,但思路是相同的。
我已经阅读了谷歌能够找到的一切内容,但没有发现任何可行的示例。
以下是一些链接:
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上中断(或任何其他create方法)。
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功能,例如$expand(如/odata/Customers?$expand=Images)完全消失且无法工作(以下是响应): [{"Images":[],"CustomerId":1,"FirstName":"Bla","LastName":"Bla", "VirtualField1":null]
在此实例中,图像没有被扩展,尽管未添加自定义格式化程序时会扩展。
有任何想法、思路或方向吗?