如何在OData Web API中控制JSON datetime的序列化与反序列化格式
自定义Microsoft.AspNetCore.OData DateTime序列化/反序列化格式方案
该方案通过在OData中间件层注入自定义序列化、反序列化器实现格式调整,不修改业务模型,不影响EF Core的OData查询转换能力。
步骤1:实现自定义OData资源序列化器
继承ODataResourceSerializer,重写属性写入逻辑,调整DateTime/DateTimeOffset的输出格式:
using Microsoft.AspNetCore.OData.Formatter.Serialization; using Microsoft.OData; using Microsoft.OData.Edm; public class CustomDateTimeODataSerializer : ODataResourceSerializer { public CustomDateTimeODataSerializer(ODataSerializerProvider serializerProvider) : base(serializerProvider) { } public override ODataProperty CreateStructuralProperty(IEdmStructuralProperty structuralProperty, ResourceContext resourceContext) { var property = base.CreateStructuralProperty(structuralProperty, resourceContext); if (property.Value is DateTimeOffset dateTimeOffset) { // 格式化为yyyy-MM-ddTHH:mm:ss±HH格式 property.Value = dateTimeOffset.ToString("yyyy-MM-ddTHH:mm:sszz"); } else if (property.Value is DateTime dateTime) { // 可根据实际业务需求调整DateTime Kind的处理逻辑 var offset = dateTime.Kind == DateTimeKind.Utc ? TimeSpan.Zero : TimeZoneInfo.Local.GetUtcOffset(dateTime); var dto = new DateTimeOffset(dateTime, offset); property.Value = dto.ToString("yyyy-MM-ddTHH:mm:sszz"); } return property; } }
步骤2:实现自定义序列化提供器
将自定义序列化器注册到OData的序列化提供链中:
public class CustomODataSerializerProvider : ODataSerializerProvider { private readonly CustomDateTimeODataSerializer _serializer; public CustomODataSerializerProvider(IServiceProvider serviceProvider) : base(serviceProvider) { _serializer = new CustomDateTimeODataSerializer(this); } public override IODataEdmTypeSerializer GetEdmTypeSerializer(IEdmTypeReference edmType) { if (edmType.Definition.TypeKind is EdmTypeKind.Entity or EdmTypeKind.Complex) { return _serializer; } return base.GetEdmTypeSerializer(edmType); } }
步骤3:实现自定义反序列化器,适配短时区格式
确保请求传入的yyyy-MM-ddTHH:mm:ss±HH格式可以被正确解析:
using Microsoft.AspNetCore.OData.Formatter.Deserialization; using Microsoft.OData.Edm; public class CustomDateTimeODataDeserializer : ODataResourceDeserializer { public CustomDateTimeODataDeserializer(ODataDeserializerProvider deserializerProvider) : base(deserializerProvider) { } public override object ReadStructuralProperty(IEdmStructuralProperty structuralProperty, ODataProperty property, ODataDeserializerContext readContext) { if (property.Value is string strValue && (structuralProperty.Type.PrimitiveKind() == EdmPrimitiveTypeKind.DateTimeOffset || structuralProperty.Type.PrimitiveKind() == EdmPrimitiveTypeKind.DateTime)) { if (DateTimeOffset.TryParse(strValue, out var dto)) { return structuralProperty.Type.PrimitiveKind() == EdmPrimitiveTypeKind.DateTime ? dto.DateTime : dto; } } return base.ReadStructuralProperty(structuralProperty, property, readContext); } }
步骤4:实现自定义反序列化提供器
public class CustomODataDeserializerProvider : ODataDeserializerProvider { private readonly CustomDateTimeODataDeserializer _deserializer; public CustomODataDeserializerProvider(IServiceProvider serviceProvider) : base(serviceProvider) { _deserializer = new CustomDateTimeODataDeserializer(this); } public override IODataEdmTypeDeserializer GetEdmTypeDeserializer(IEdmTypeReference edmType) { if (edmType.Definition.TypeKind is EdmTypeKind.Entity or EdmTypeKind.Complex) { return _deserializer; } return base.GetEdmTypeDeserializer(edmType); } }
步骤5:在服务配置中注册自定义组件
在Program.cs中配置OData时注入自定义的序列化、反序列化提供器:
builder.Services.AddControllers() .AddOData(opt => { opt.Select().Filter().OrderBy().Expand().Count().SetMaxTop(null); // 替换为你自己的Edm模型构建逻辑 var model = BuildEdmModel(); opt.AddRouteComponents("odata", model, services => { // 注册自定义序列化、反序列化提供器 services.AddSingleton<IODataSerializerProvider, CustomODataSerializerProvider>(); services.AddSingleton<IODataDeserializerProvider, CustomODataDeserializerProvider>(); }); });
该方案所有逻辑都在OData中间件层完成,业务模型仍然使用原生DateTime/DateTimeOffset类型,不会对EF Core的查询转换、OData原生查询功能造成任何影响。
内容的提问来源于stack exchange,提问作者Chris
相关产品推荐
相关产品推荐

