我正在使用当前可用的OData NuGet软件包使用Web API 2编写OData V4服务。
我有一个类Foo
的实体集,如下所示:
class Foo {
string SomePropertyUnrelatedToThePost {get; set;}
...
IList<Bar> TheImportantPropertyList {get; set;}
}
Bar
没有太多进展:
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");
并将Bar
注册为builder.ComplexType<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
类型的属性。
答案 0 :(得分:4)
我明白了。 This帖子有帮助。作为OData的新手,需要一段时间才能完成文档,因为大部分内容都已过时。
在我的WebApiConfig.cs
中,我使用了在OData中注入ODataSerializerProvider
的新方法:
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;
}
}
我意识到这是一个非常具体的问题和答案,但我希望有人发现它有用。