You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 21:09:00