1

I have an object defined as such

public class FilingSearchCriteria
{
    public int? FilerId { get; set; }
    public int? TypeId { get; set; }
    public DateTime? StartDate { get; set; }
    public DateTime? EndDate { get; set; }
    public bool? Legacy { get; set; }
    public bool? NoAtttachments { get; set; }
    public bool? MissingFields { get; set; }
    public bool? MissingAttachments { get; set; }
    public string DocketNumber { get; set; }
 
}

A a Net Core controller takes it as a parameter. Issue is most of the time the JSON that comes only has a few of those properties (by design), which seems to cause a deserialization failure so what my controller gets is the above object with all properties set to null.

How can I tell the default net core system.text.json serialzier to accept "partial" object like that?

Adding incoming JSON

{"EndDate":"Tue, 02 Feb 2021 18:07:33 GMT","StartDate":"Tue, 26 Jan 2021 18:07:33 GMT"}
americanslon
  • 4,048
  • 4
  • 32
  • 57
  • What you described is strange. I don't think the json serializer (whatever kind) works that way by default. If any provided properties in the json match with any properties in the class, the corresponding properties should be populated with values correctly. You should post your json as well (and looks like you're not even tried debugging yet). – King King Feb 02 '21 at 18:00
  • Right? That's what I thought too. I don't really know how to debug this, hence why I am here. There is no way I know of to inject myself into the controller deserialization process to see what it's doing. For what it's worth this is a completely working app after being migrated to net core. Old ASP.Net version used Newtonsoft but for Core version I wanted to try to stick with default System.Text.Json. I have posted the incoming json – americanslon Feb 02 '21 at 18:05
  • I can't reproduce your problem. If I just do `JsonSerializer.Deserialize("{}")` then a `FilingSearchCriteria` is returned with all properties null, see https://dotnetfiddle.net/G1CeeC. – dbc Feb 02 '21 at 18:09
  • @americanslon you can open the Developer inspector tool (if using a browser) to see what's actually sent (in the request body). There you should verify the json that is sent. – King King Feb 02 '21 at 18:10
  • OK, with that JSON sample I am getting the following exception: `System.FormatException: The JSON value is not in a supported DateTime format.`. See https://dotnetfiddle.net/GU3R41. The real issue is that StartDate is not in ISO 8601-1:2019 format format. You will need to write a custom converter for that datetime format, see [DateTime and DateTimeOffset support in System.Text.Json](https://learn.microsoft.com/en-us/dotnet/standard/datetime/system-text-json-support). – dbc Feb 02 '21 at 18:10
  • Yeah I used your fiddle to get the same. Looks like that's the issue, would be nice if that error actually appeared when not manually using JSON Deserialize. Thanks for the .Net Fiddle intro. With all the JS fiddles it never even occurred to me there is .Net one. – americanslon Feb 02 '21 at 18:12
  • It may have been A problem but it's not THE problem as I still get an object with null properties. I posted another question with more details https://stackoverflow.com/questions/66015759/asp-net-core-serialization-results-in-empty-object – americanslon Feb 02 '21 at 18:45

1 Answers1

0

Your StartDate and EndDate properties are not in ISO 8601-1:2019 format, which would look like "2021-02-02T18:07:33Z" instead of "Tue, 02 Feb 2021 18:07:33 GMT". From DateTime and DateTimeOffset support in System.Text.Json:

The JsonSerializer, Utf8JsonReader, Utf8JsonWriter, and JsonElement types parse and write DateTime and DateTimeOffset text representations according to the extended profile of the ISO 8601-1:2019 format; for example, 2019-07-26T16:59:57-05:00.
...
With default options, input DateTime and DateTimeOffset text representations must conform to the extended ISO 8601-1:2019 profile. Attempting to deserialize representations that don't conform to the profile will cause JsonSerializer to throw a JsonException.

Thus you will need to create a custom JsonConverter<DateTime?> along the lines of DateTimeConverterUsingDateTimeParse that Microsoft shows in Custom support for DateTime and DateTimeOffset such as:

public class CustomDateTimeConverter : JsonConverter<DateTime?>
{
    //const string Format = "Tue, 02 Feb 2021 18:07:33 GMT";
    const string Format = "dddd, dd MMM yyyy hh:mm:ss";

    // Adapted from https://learn.microsoft.com/en-us/dotnet/standard/datetime/system-text-json-support#using-datetimeoffsetparse-and-datetimeoffsettostring
    public override DateTime? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) =>
        DateTime.Parse(reader.GetString(), CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal);

    public override void Write(Utf8JsonWriter writer, DateTime? value, JsonSerializerOptions options) =>
        writer.WriteStringValue(value?.ToUniversalTime().ToString(Format, CultureInfo.InvariantCulture)+" GMT");
}

You can then add the converter to JsonSerializerOptions.Converters or apply it directly to the model like so:

public class FilingSearchCriteria
{
    public int? FilerId { get; set; }
    public int? TypeId { get; set; }

    [JsonConverter(typeof(CustomDateTimeConverter))]
    public DateTime? StartDate { get; set; }
    [JsonConverter(typeof(CustomDateTimeConverter))]
    public DateTime? EndDate { get; set; }
    // Remainder unchanged

Notes:

  • System.Text.Json seems to require distinct JsonConverter<T> converters for DateTime? and DateTime -- and generally for nullables and their underlying types.

  • DateTime.Parse() apparently does not support parsing multiple names time zones so if you are receiving DateTime strings with a mixture of different time zones, say both "GMT" and "EDT", you will need to write a more complex converter.

  • My converter assumes you want your dates and times adjusted to universal. You can modify that if it is not desired.

Demo fiddle here.

dbc
  • 104,963
  • 20
  • 228
  • 340
  • 1
    I just changed the way dates are generated on the JSON side to be ISO and now your fiddle works. Issue is the built in NET Core deserialization still doesn't. I started a different question as there is something else going on I think. https://stackoverflow.com/questions/66015759/asp-net-core-serialization-results-in-empty-object – americanslon Feb 02 '21 at 19:07
  • @americanslon - OK. This answer addresses the issue shown in the [mcve] for this question, so asking a new question with a different [mcve] is a good idea. – dbc Feb 02 '21 at 19:18