![](/img/trans.png)
[英]Every singe field can be edited except the DateTime. Always resets to defaut - MVC ASP.NET Core 3.1 Web App
[英]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.