Datetime 用于.Net Core 3.1 Web Api的自定义OData日期时间序列化程序

Datetime 用于.Net Core 3.1 Web Api的自定义OData日期时间序列化程序,datetime,serialization,odata,asp.net-core-webapi,jsonserializer,Datetime,Serialization,Odata,Asp.net Core Webapi,Jsonserializer,我有一个ODataAPI,其中包含一个数据模型对象,该对象具有许多可为空的DateTime字段 e、 g 使用OData API的客户端要求将日期时间字段格式化为“yyyy-MM-dd”格式,而不是像“yyy-MM-ddTHH:MM:ss”这样的默认长格式 public class CustomODataSerializerProvider : DefaultODataSerializerProvider { private readonly CustomODataEntityTypeS

我有一个ODataAPI,其中包含一个数据模型对象,该对象具有许多可为空的DateTime字段

e、 g

使用OData API的客户端要求将日期时间字段格式化为“yyyy-MM-dd”格式,而不是像“yyy-MM-ddTHH:MM:ss”这样的默认长格式

public class CustomODataSerializerProvider : DefaultODataSerializerProvider
{
    private readonly CustomODataEntityTypeSerializer _entityTypeSerializer;

    public CustomODataSerializerProvider(IServiceProvider rootContainer)
        : base(rootContainer)
    {
        _entityTypeSerializer = new CustomODataEntityTypeSerializer(this);
    }

    public override ODataEdmTypeSerializer GetEdmTypeSerializer(Microsoft.OData.Edm.IEdmTypeReference edmType)
    {
        if (edmType.Definition.TypeKind == EdmTypeKind.Entity || edmType.Definition.TypeKind == EdmTypeKind.Complex)
            return _entityTypeSerializer;
        else
            return base.GetEdmTypeSerializer(edmType);
    }
}

public class CustomODataEntityTypeSerializer : ODataResourceSerializer
{
    public CustomODataEntityTypeSerializer(ODataSerializerProvider provider)
        : base(provider) { }

    public override Microsoft.OData.ODataProperty CreateStructuralProperty(Microsoft.OData.Edm.IEdmStructuralProperty structuralProperty, ResourceContext resourceContext)
    {
        var property = base.CreateStructuralProperty(structuralProperty, resourceContext);
        if (property.Name.Contains("Date"))
        {
            property.Value = ((DateTime)property.Value).ToShortDateString();
        }
        return property.Value != null ? property : null;
    }
}
我还尝试了“property.Value=((DateTimeOffset)property.Value).DateTime.ToSortDateString();”而不是上面的

然后使用

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();
            endpoints.EnableDependencyInjection();
            endpoints.Select().Expand().OrderBy().Filter().Count().MaxTop(10);
            endpoints.MapODataRoute("odata", "odata", a =>
            {
                a.AddService(Microsoft.OData.ServiceLifetime.Singleton, typeof(IEdmModel), sp => GetEdmModel(app.ApplicationServices));
                a.AddService(Microsoft.OData.ServiceLifetime.Singleton, typeof(ODataSerializerProvider), sp => new CustomODataSerializerProvider(sp));
            });
            //endpoints.MapODataRoute("odata", "odata", GetEdmModel(app.ApplicationServices));
        });
但是,当调用OData端点时,会出现此错误

 can't parse JSON.  Raw result:

{"@odata.context":"https://localhost:5000/odata/$metadata#Book","value":[
我还尝试应用Json序列化程序,但这对OData端点提供的数据没有影响:

    services
        .AddControllers()
        .AddJsonOptions(options =>
        {
            options.JsonSerializerOptions.IgnoreNullValues = false;
            options.JsonSerializerOptions.Converters.Add(new DateTimeConverter());
        })
        .SetCompatibilityVersion(CompatibilityVersion.Version_3_0);

    public class DateTimeConverter : JsonConverter<DateTime>
    {
        public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        {
            Debug.Assert(typeToConvert == typeof(DateTime));
            return DateTime.Parse(reader.GetString());
        }

        public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options)
        {
            writer.WriteStringValue(value.ToUniversalTime().ToString("yyyy-MM-dd"));
        }
    }
服务
.AddControllers()
.AddJsonOptions(选项=>
{
options.JsonSerializerOptions.IgnoreNullValues=false;
options.JsonSerializerOptions.Converters.Add(new DateTimeConverter());
})
.SetCompatibilityVersion(CompatibilityVersion.Version_3_0);
公共类DateTimeConverter:JsonConverter
{
公共覆盖日期时间读取(参考Utf8JsonReader reader,键入typeToConvert,JsonSerializerOptions选项)
{
Assert(typeToConvert==typeof(DateTime));
return DateTime.Parse(reader.GetString());
}
公共重写无效写入(Utf8JsonWriter编写器、日期时间值、JsonSerializerOptions选项)
{
writer.WriteStringValue(value.ToUniversalTime().ToString(“yyyy-MM-dd”);
}
}

我正在.NET Core 3.1 Web Api中使用Microsoft.AspNetCore.OData 7.4.1。如果您对如何更改通过OData API提供的数据的日期时间格式/序列化有任何建议,我们将不胜感激。

在声明您的EDM时,您可以使用
EDM.Date
格式标记要反序列化的特定字段,例如:

公共静态IEdmModel GetedModel()
{
ODataConventionModelBuilder=新ODataConventionModelBuilder();
builder.EnableLowerCamelCase();
建筑商实体集(“账簿”);
属性(p=>p.CreatedDate.AsDate();
builder.EntityType().Property(p=>p.UpdateDate.AsDate();
返回builder.GetEdmModel();
}
对于以下简单控制器:

名称空间WebAPI.Controllers
{
[ApiController]
[路线(“[控制器]”)]
公共类BookController:ControllerBase
{
私有静态只读列表书籍=新列表
{
新书{
BookId=1,
CreatedDate=新日期时间(2020,01,02),
UpdateDate=新日期时间(2020,02,03)
},
新书{
BookId=2,
CreatedDate=null,
UpdateDate=null
},
};
[启用查询]
公共IEnumerable Get()
{
var result=Books.ToArray();
返回结果;
}
}
}
您可以看到使用YYYY-MM-DD格式序列化的
DateTime?
字段:

{
“@odata.context”:”https://localhost:5001/odata/$metadata#图书“,
“价值”:[
{
“createdDate”:“2020-01-02”,
“更新日期”:“2020-02-03”,
“bookId”:1
},
{
“createdDate”:空,
“UpdateDate”:null,
“bookId”:2
}
]
}
和https://localhost:5001/odata/$metadata XML声明这些字段的类型为
Edm.Date


    services
        .AddControllers()
        .AddJsonOptions(options =>
        {
            options.JsonSerializerOptions.IgnoreNullValues = false;
            options.JsonSerializerOptions.Converters.Add(new DateTimeConverter());
        })
        .SetCompatibilityVersion(CompatibilityVersion.Version_3_0);

    public class DateTimeConverter : JsonConverter<DateTime>
    {
        public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        {
            Debug.Assert(typeToConvert == typeof(DateTime));
            return DateTime.Parse(reader.GetString());
        }

        public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options)
        {
            writer.WriteStringValue(value.ToUniversalTime().ToString("yyyy-MM-dd"));
        }
    }