繁体   English   中英

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

[英]Custom OData DateTime Serializer for .Net Core 3.1 Web Api

我有一个带有数据模型对象的 OData Api,其中包含许多可为空的 DateTime 字段。

例如

public class Book : EntityBase
{
    ...
    public DateTime? CreatedDate { get; set; }
    public DateTime? UpdatedDate { get; set; }
    ...
}

使用 OData API 的客户端需要将 DateTime 字段格式化为“yyyy-MM-dd”格式,而不是像“yyyy-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.ToShortDateString();” 而不是上面的。

然后使用注册此序列化程序

        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"));
        }
    }

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

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

public static IEdmModel GetEdmModel()
{
    ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
    builder.EnableLowerCamelCase();
    builder.EntitySet<Book>("Book");
    builder.EntityType<Book>().Property(p => p.CreatedDate).AsDate();
    builder.EntityType<Book>().Property(p => p.UpdatedDate).AsDate();
    return builder.GetEdmModel();
}

对于一个简单的控制器,例如:

namespace WebAPI.Controllers
{
    [ApiController]
    [Route("[controller]")]
    public class BookController : ControllerBase
    {
        private static readonly List<Book> Books = new List<Book>
        {
            new Book() {
                BookId = 1,
                CreatedDate = new DateTime(2020, 01, 02),
                UpdatedDate = new DateTime(2020, 02, 03)
            },
            new Book() {
                BookId = 2,
                CreatedDate = null,
                UpdatedDate = null
            },
        };

        [EnableQuery]
        public IEnumerable<Book> Get()
        {
            var result = Books.ToArray();
            return result;
        }
    }
}

你能看到DateTime? 使用 YYYY-MM-DD 格式序列化的字段:

{
  "@odata.context": "https://localhost:5001/odata/$metadata#Book",
  "value": [
    {
      "createdDate": "2020-01-02",
      "updatedDate": "2020-02-03",
      "bookId": 1
    },
    {
      "createdDate": null,
      "updatedDate": null,
      "bookId": 2
    }
  ]
}

而 https://localhost:5001/odata/$metadata XML 将这些字段声明为Edm.Date类型:

<edmx:Edmx Version="4.0">
    <edmx:DataServices>
        <Schema Namespace="WebAPI">
            <EntityType Name="Book">
                <Key>
                    <PropertyRef Name="bookId"/>
                </Key>
                <Property Name="createdDate" Type="Edm.Date"/>
                <Property Name="updatedDate" Type="Edm.Date"/>
                <Property Name="bookId" Type="Edm.Int32" Nullable="false"/>
            </EntityType>
        </Schema>
        <Schema Namespace="Default">
            <EntityContainer Name="Container">
                <EntitySet Name="Book" EntityType="WebAPI.Book"/>
            </EntityContainer>
        </Schema>
    </edmx:DataServices>
</edmx:Edmx>

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM