我正在使用当前可用的OData NuGet包使用Web API 2编写OData V4服务.
我有一个Foo类的实体集,如下所示:
class Foo {
string SomePropertyUnrelatedToThePost {get; set;}
...
IList<Bar> TheImportantPropertyList {get; set;}
}
酒吧没有太多的事情:
class Bar {
string Name {get; set;}
int? Group {get; set;}
object Value {get; set;}
}
在使用中,Bar#Value从未分配除基本值以外的任何东西,但有些是基元,有些则没有:bool,byte,char,short,int,long,string,Decimal,DateTime …
我使用ODataConventionModelBuilder像文档说明那样注册Foo集,如下所示:
...
builder.EntitySet<Foo>("Foos");
并使用builder.ComplexType< Bar>();将我的Bar注册为复杂类型.似乎并没有改变结果.
问题是,当我在ODataController中返回Foo对象时,JSON响应中不包含Bar#Value.
{
...
"SomePropertyUnrelatedToThePost": "Foo was here",
...
"TheImportantPropertyList": [
{
"Name": "TheAnswer",
"Group": null
},
{
"Name": "TheQuestion",
"Group": null
}
]
}
令我感到困惑的是,我可以在控制器方法中手动序列化Foo,如下所示:
var settings = GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings;//.CreateJsonSerializer();
var s = JsonSerializer.Create(settings);
...
var json = Encoding.Default.GetString(...);
产生适当的序列化结果:
{
"SomePropertyUnrelatedToThePost": "Foo was here",
...
"TheImportantPropertyList": [
{
"Name": "TheAnswer",
"Value": 42,
"Group": null
},
{
"Name": "TheQuestion",
"Value": "What is the airspeed velocity of an unladen swallow?",
"Group": null
}
]
}
我是否错误地配置了OData?我还有其他一些核心误解吗?
在我写这个问题时,我想到,如果我更改模型以包含已分配Value属性的System.Type,则可以编写一个自定义序列化程序,但似乎不必这样做.
编辑:当我手动序列化Foo时,我没有使用默认的OData序列化器,而是使用了新的Newtonsoft JsonSerializer.默认的OData序列化器和反序列化器根本不喜欢Object类型的属性.
解决方法:
我知道了This个帖子有所帮助.作为OData的新手,花了一些时间来阅读文档,因为其中大多数已过时.
在我的WebApiConfig.cs中,我使用了将ODataSerializerProvider注入OData的新方法:
config.MapODataServiceRoute("odata", "api/v1", b =>
b.AddService(ServiceLifetime.Singleton, sp => builder.GetEdmModel())
.AddService<ODataSerializerProvider>(ServiceLifetime.Singleton, sp => new MySerializerProvider(sp)));
MySerializerProvider:
internal sealed class MySerializerProvider : DefaultODataSerializerProvider
{
private MySerializer _mySerializer;
public MySerializerProvider(IServiceProvider sp) : base(sp)
{
_mySerializer = new MySerializer(this);
}
public override ODataEdmTypeSerializer GetEdmTypeSerializer(IEdmTypeReference edmType)
{
var fullName = edmType.FullName();
if (fullName == "Namespace.Bar")
return _mySerializer;
else
return base.GetEdmTypeSerializer(edmType);
}
}
在我的自定义序列化程序中,我注意到OData不会自动将DateTime转换为DateTimeOffset. MySerializer:
internal sealed class MySerializer : ODataResourceSerializer
{
public MySerializer(ODataSerializerProvider sp) : base(sp) { }
public override ODataResource CreateResource(SelectExpandNode selectExpandNode, ResourceContext resourceContext)
{
ODataResource resource = base.CreateResource(selectExpandNode, resourceContext);
if (resource != null && resourceContext.ResourceInstance is Bar b)
resource = BarToResource(b);
return resource;
}
private ODataResource BarToResource(Bar b)
{
var odr = new ODataResource
{
Properties = new List<ODataProperty>
{
new ODataProperty
{
Name = "Name",
Value = b.Name
},
new ODataProperty
{
Name = "Value",
Value = b.Value is DateTime dt ? new DateTimeOffset(dt) : b.Value
},
new ODataProperty
{
Name = "Group",
Value = b.Group
},
}
};
return odr;
}
}
我意识到这是一个非常具体的问题和答案,但我希望有人觉得它有用.