2

I recently upgraded my asp.net core web api to .NET 6. Prior to that, the model binding worked fine.

my request class:

public class FindUserRequest
{
    public string EmailAddress { get; set; }

    public string Id { get; set; }

    public DateTime? DateOfBirth { get; set; }
}

My API controller method:

[HttpPost("FindUser")]
public IActionResult FindUser([FromBody] FindUserRequest request)
{
            
    var response = FindUser(request);

    return Ok(response);
}

The JSON being passed in the body:

{
  "EmailAddress": "jdoe@example.com",
  "Id": "1234",
  "DateOfBirth": "03/09/2022"
}

if I pass an ISO formatted date for the DateOfBirth property (e.g. 2022-03-09) everything is fine - but if I pass a date value like 03/09/2022 my request object completely fails to bind and the request parameter is NULL. I tried implementing a custom model binder but I can never seem to get access to the JSON in the request body when I do that. I wish there was a simple 'date format' kind of attribute I could put on the DateOfBirth property but I haven't found anything that seems to work there either. Any Ideas?

jamauss
  • 1,001
  • 1
  • 15
  • 35

1 Answers1

1

So the solution I ended up going with was writing a custom JsonConverter for DateTime types.


public class USDateTimeFormatConverter : JsonConverter<DateTime?>
{

    public override DateTime? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        using (var jsonDoc = JsonDocument.ParseValue(ref reader))
        {
            string dateValue = jsonDoc.RootElement.GetString();

            if (DateTime.TryParseExact(dateValue, "yyyy-MM-dd", CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal, out DateTime isoDateTime))
                return isoDateTime; // ISO8601 format worked

            if (DateTime.TryParseExact(dateValue, "MM/dd/yyyy", CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal, out DateTime usDateTime))
                return usDateTime; // US MM/dd/yyyy format worked

            if (DateTime.TryParse(dateValue, out DateTime otherDateTime))
                return otherDateTime; // some other format worked

            return null; // whatever the string was, it couldn't be recognized and parsed as any kind of date value
        }
    }

    public override void Write(Utf8JsonWriter writer, DateTime? value, JsonSerializerOptions options)
    {
        writer.WriteStringValue(value.Value.ToString("yyyy-MM-dd", System.Globalization.CultureInfo.InvariantCulture));
    }
}

Then configure it in Startup.cs

public void ConfigureServices(IServiceCollection services)
{
    // This Json Serializer Converter was added due to model binding
    // issues when date values are formatted like MM/dd/yyyy instead of
    // ISO8601 format e.g. yyyy-MM-dd
    services.AddMvc().AddJsonOptions(options =>
    {
        options.JsonSerializerOptions.Converters.Add(new USDateTimeFormatConverter());
    });
}
jamauss
  • 1,001
  • 1
  • 15
  • 35
  • 1
    Although your solution may work, I would suggest to make sure dates are following JSON standard on serialization. See https://stackoverflow.com/questions/10286204/what-is-the-right-json-date-format for more details – Nicolas Boisvert Mar 09 '22 at 20:46
  • I'll have a look at that @NicolasBoisvert thanks – jamauss Mar 09 '22 at 20:58