I have an OData Api with a data model object with a number of nullable DateTime fields.
e.g.
public class Book : EntityBase
{
...
public DateTime? CreatedDate { get; set; }
public DateTime? UpdatedDate { get; set; }
...
}
The client consuming the OData API requires the DateTime fields to be formatted in the 'yyyy-MM-dd' format instead of the default long format which is like '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;
}
}
I also tried "property.Value = ((DateTimeOffset)property.Value).DateTime.ToShortDateString();" instead of the above.
This serializer is then registered using
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));
});
However I get this error when the OData endpoint is called
can't parse JSON. Raw result:
{"@odata.context":"https://localhost:5000/odata/$metadata#Book","value":[
I also tried applying a Json serializer but this had no effect on the data served from the OData endpoints:
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"));
}
}
I'm using Microsoft.AspNetCore.OData 7.4.1 in a .NET Core 3.1 Web Api. Any suggestions on how to change the DateTime format/serialization for data served via a OData API would be much appreciated.