2

I can't seem to solve this one. All other questions i can find with the same issue are for Newtonsoft.Json.

I use an external provided json API which returns a dictionary. But if it's empty, they return an empty array:

With data:

"booking/index": {
   "key": {
         data...
          }
}

Without data:

"booking/index": []

So the System.json deserializer fails with this error (which is understandable):

System.Text.Json.JsonException: The JSON value could not be converted to System.Collections.Generic.Dictionary`2[System.String,checkfront_reports.Models.Api.BookingIndexIndexObj]. Path: $['booking/index'] | LineNumber: 0 | BytePositionInLine: 408.

For reference here is the call i make and the data model:

var bookingIndex = await httpClient.GetFromJsonAsync<BookingIndexObj>($"booking/index?start_date={startDate.ToString("yyyy-MM-dd")}&end_date={endDate.ToString("yyyy-MM-dd")}");

public class BookingIndexObj
{
    public BookingRequestObj Request { get; set; }

    [JsonPropertyName("booking/index")]
    public Dictionary<string, BookingIndexIndexObj> BookingIndex { get; set; }
}

public class BookingIndexIndexObj
{
    public string? Code { get; set; }

    [JsonPropertyName("status_id")]
    public string? StatusId { get; set; }
}

public class BookingRequestObj
{
    public int Page { get; set; }

    public int Pages { get; set; }
}
4
  • 2
    Can you include a minimal reproducible example for quick repro? Commented May 7, 2024 at 9:09
  • From where are you getting the JSON? Commented May 7, 2024 at 9:25
  • Simplyfied, but should showcase the problem: dotnetfiddle.net/KwCMn6 Commented May 7, 2024 at 9:50
  • ^^ the commented List<KeyValuePair<string,string>> did not work. Commented May 7, 2024 at 9:56

1 Answer 1

1

I am not sure at all if this is how we are supposed to do this, but at least it worked:

(Note that I simplified the example)

using System;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Collections.Generic;
                    
public class Program
{
    public static void Main()
    {
        var emptyJson = 
            """
{
    "values": []
}
""";
    
        var nonEmptyJson = 
            """
{
    "values": {
        "key1": "value1",
        "key2": "value2"
    }
}
""";
        
        var emptyResult = JsonSerializer.Deserialize<Model>(emptyJson);
        var nonEmptyResult = JsonSerializer.Deserialize<Model>(nonEmptyJson);
        
        emptyResult.Dump();
        nonEmptyResult.Dump();
    }
}

public class Model
{
    [JsonPropertyName("values")]
    [JsonConverter(typeof(MySpecialConverter))]
    public Dictionary<string,string> Values {get;set;} = new();
}

public class MySpecialConverter : JsonConverter<Dictionary<string,string>>
{
// Omitted writer for brevity. 
    public override void Write(Utf8JsonWriter writer,
            Dictionary<string,string> dictionaryValue,
            JsonSerializerOptions options) => throw new NotSupportedException();
            
    public override Dictionary<string,string> Read(ref Utf8JsonReader reader,
            Type typeToConvert,
            JsonSerializerOptions options)
            {
// Check for '"booking/index": []' - case:
                if (reader.TokenType == JsonTokenType.StartArray)
                {
                  reader.Read();
                  return new Dictionary<string,string>();
                }
// Otherwise pass-through to default converter.
                var converter = (JsonConverter<Dictionary<string,string>>)options.GetConverter(typeof(Dictionary<string,string>));
                return converter.Read(ref reader, typeToConvert, options);
            }
}

=> Fiddle: https://dotnetfiddle.net/J6NbVE

For your reference:
I based this upon this article: How to write custom converters for JSON serialization (marshalling) in .NET

Sign up to request clarification or add additional context in comments.

3 Comments

Hi Fildor, that is also the solution i'm currently working on, and this works if the json returns an empty array. But if there is actual data, then it just closes the browser window (it's an asp.net app) and stops the debugging with no errors at all. This indicates to me that there is an unsafe memory leak or something else going on in regards to the reader.
In that case you need to try and gather some more information. Maybe you can find out what inputs exactly cause unexpected errors (and which don't) and try and build reproduction so you can look for fixes.
I finallt found out why my and yours code didn't work. I passed the converter through the options parameter for the await httpClient.GetFromJsonAsync<BookingIndexObj> call. That made the app crash. Adding the converter through the JsonConverter attribute as in your example solved the issue! Thanks for the help!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.