OData V4无法正确序列化包含System.Object属性的POCO(?)列表

我正在使用当前可用的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;
  }
}

我意识到这是一个非常具体的问题和答案,但我希望有人觉得它有用.

上一篇:如何在OData中按嵌套属性过滤?


下一篇:c#-无法安装软件包“ Microsoft.Extensions.DependencyInjection.Abstractions 1.0.0”