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

C# OData V4无法正确序列化包含System.Object属性的POCO(?)的列表,c#,serialization,json.net,asp.net-web-api2,odata,C#,Serialization,Json.net,Asp.net Web Api2,Odata,我正在使用当前可用的ODataNuget包编写一个带有WebAPI2的ODataV4服务 我有一个类Foo的实体集,如下所示: class Foo { string SomePropertyUnrelatedToThePost {get; set;} ... IList<Bar> TheImportantPropertyList {get; set;} } 在使用中,除了基本值之外,Bar#Value从不被分配任何值,但有些是基本值,有些不是:bool、by

我正在使用当前可用的ODataNuget包编写一个带有WebAPI2的ODataV4服务

我有一个类
Foo
的实体集,如下所示:

class Foo {
    string SomePropertyUnrelatedToThePost {get; set;}
    ...
    IList<Bar> TheImportantPropertyList {get; set;}
}
在使用中,除了基本值之外,Bar#Value从不被分配任何值,但有些是基本值,有些不是:bool、byte、char、short、int、long、string、Decimal、DateTime

我正在使用ODataConventionModelBuilder(如下所示)按照文档指示注册Foo集:

...
builder.EntitySet<Foo>("Foos"); 
更让我困惑的是,我可以在控制器方法中手动序列化一个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?我还有其他核心误解吗? 在我写这个问题时,我突然想到,如果我更改了我的模型以包含赋值属性的System.Type,我可以编写一个自定义序列化程序,但它似乎不应该达到这个目的

编辑:当我手动序列化我的
Foo
时,我没有使用默认的OData序列化程序,而是使用新的Newtonsoft JsonSerializer。默认的OData序列化程序和反序列化程序不喜欢类型为
Object
的属性

我已经准备好了。波斯特帮了忙。作为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)));
在我的自定义序列化程序中,我注意到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;
  }
}
内部密封类MySerializer:ODataResourceSerializer
{
公共MySerializer(ODataSerializerProvider sp):基(sp){}
公共覆盖ODataResource CreateResource(选择ExpandNode选择ExpandNode,ResourceContext ResourceContext)
{
ODataResource resource=base.CreateResource(选择ExpandNode,resourceContext);
如果(resource!=null&&resourceContext.ResourceInstance为条b)
资源=BarToResource(b);
返回资源;
}
私人ODataResource BarToResource(b栏)
{
var odr=新ODataResource
{
属性=新列表
{
新财产
{
Name=“Name”,
Value=b.名称
},
新财产
{
Name=“Value”,
值=b。值是DateTime dt?新的DateTimeOffset(dt):b。值
},
新财产
{
Name=“Group”,
值=b组
},
}
};
返回odr;
}
}

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

你能解释一下为什么需要这个吗?另外,您可以发布您的EDM配置吗?谢谢谢谢,这是为我在网上发布的为数不多的解决方案之一,但当我调用它时,我注意到路由已经停止工作。对于实体集,您是否必须对上面的构建器执行任何其他操作@维克多·威尔逊
config.MapODataServiceRoute("odata", "api/v1", b =>
               b.AddService(ServiceLifetime.Singleton, sp => builder.GetEdmModel())
                .AddService<ODataSerializerProvider>(ServiceLifetime.Singleton, sp => new MySerializerProvider(sp)));
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);            
    }        
}
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;
  }
}