0

I have a .NET Core Web API using ODATA. To support a legacy requirement, I'd like to change the default format of DateTime members to something like "yyyy-MM-dd HH:mm:ss", then be able to override the format on individual members. I understand this is different from JsonConverter and may require a custom ODATA serializer, but I am not sure how to do so.

2 Answers2

1

Since .NET 5.0 this has moved. You now add the ODataPayloadValueConverter on the options.AddRouteComponent

            .AddOData(options =>
            {
                options.AddRouteComponents("odata", GetEdmModel(), action =>
                {
                    action.AddSingleton(typeof(ODataPayloadValueConverter), new ODataByteArrayAsHexJsonConverter());
                })
                .Filter().Select().Expand().Count().OrderBy().SetMaxTop(50).SkipToken();
            });

I've used it to replace the standard byte[] serializer (which uses base64 encoding), with an implementation that uses hex encoding instead.

public class ODataByteArrayAsHexJsonConverter : ODataPayloadValueConverter
{
    public override object ConvertToPayloadValue(object value, IEdmTypeReference edmTypeReference)
    {
        if (value is byte[] byteValue)
        {
            return Helper.ConvertByteToHexString(byteValue);
        }
        else
        {
            return base.ConvertToPayloadValue(value, edmTypeReference);
        }
    }

    public override object ConvertFromPayloadValue(object value, IEdmTypeReference edmTypeReference)
    {
        if (edmTypeReference.IsByte() && value is string stringValue)
        {
            return Helper.ConvertHexStringToByte(stringValue);
        }
        else
        {
            return base.ConvertFromPayloadValue(value, edmTypeReference);
        }
    }
}
jmahlitz
  • 41
  • 2
0

I found a good solution using ODataPayloadValueConverter. Below is the implementation for DateTime, but you could easily add other types as needed.

class MyPayloadValueConverter : ODataPayloadValueConverter
{
    public override object ConvertToPayloadValue(object value, IEdmTypeReference edmTypeReference)
    {
        if (value is DateTime)
        {
            return String.Format("{0:yyyy-MM-dd HH:mm:ss}", value, CultureInfo.InvariantCulture);
        }
        else
        {
            return base.ConvertToPayloadValue(value, edmTypeReference);
        }
    }

    public override object ConvertFromPayloadValue(object value, IEdmTypeReference edmTypeReference)
    {
        if (edmTypeReference.IsDate() && value is string)
        {
            return DateTime.Parse((string)value, CultureInfo.InvariantCulture);
        }
        else
        {
            return base.ConvertFromPayloadValue(value, edmTypeReference);
        }
    }
}

Wire up your converter in Startup.cs like this:

    app.UseEndpoints(endpoints =>
    {
        ...

        endpoints.MapODataRoute("odata", "odata", action =>
        {
            action.AddService(Microsoft.OData.ServiceLifetime.Singleton, typeof(ODataPayloadValueConverter), pvc => new MyPayloadValueConverter());
        });
    });