0

I need to have the System.Text.Json.JsonSerializer be able to deserialize this nested Dictionary type structure, but I'm getting the following error:

Unable to cast object of type 'System.Text.Json.JsonElement' to type 'System.String'.

I have the following JSON

{
  "ACL": {
    "granted": {
      "Business": {
        "Delete": [
          "Customer1",
          "Customer2"
        ]
      },
      "Account": {
        "Create": [
          "Customer1",
          "Customer3"
        ]
      }
    }
  }
}

Going into the following model

using System.Collections.Specialized;
public record AclRecord 
{
    public Dictionary<string, Dictionary<string, Dictionary<string, StringCollection>>> ACL { get; set; }
}

What would a JsonConverter to deserialize this type of triple nested Dictionary type structure look like?

3
  • Use var acl=JsonConvert.DeserializeObject<AclRecord>(json); and forget about system.text.json forever Commented Aug 13, 2022 at 19:57
  • @Serge I don't have that option. There is an underlying service using System.Text.Json, so I need a converter to make it work. Commented Aug 13, 2022 at 20:04
  • Then create a custom converter. You dont have any choice. System.Text.Json works only for a very simple cases Commented Aug 13, 2022 at 20:12

2 Answers 2

1

If you're willing to use List<string> instead of StringCollection for your deserialization target, this will work out of the box:

public record AclRecord
{
    public Dictionary<string, Dictionary<string, Dictionary<string, List<string>>>> ACL { get; set; }
}

var obj = JsonSerializer.Deserialize<AclRecord>(json);

If you MUST use StringCollection, you will need to write a custom converter.

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

Comments

0

Replacing StringCollection with List<string> as suggested in this answer by David L is the best solution to your problem, as StringCollection is an untyped collection from .Net 1.1 and typed collections should always be preferred over untyped collections.

That being said, if you must deserialize a StringCollection with System.Text.Json (e.g. because you are working with a legacy class you cannot rewrite), you may do so with the following simple JsonConverter<T>:

public class StringCollectionConverter : JsonConverter<StringCollection>
{
    public override StringCollection? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) =>
        JsonSerializer.Deserialize<List<string>>(ref reader, options)?.Aggregate(new StringCollection(), (sc, s) => { sc.Add(s); return sc; });
    
    public override void Write(Utf8JsonWriter writer, StringCollection value, JsonSerializerOptions options) => 
        JsonSerializer.Serialize(writer, value.Cast<string>(), options);
}

If your StringCollection is large and you would like to avoid an intermediate List<String>, modify Read() as follows:

public override StringCollection? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
    if (reader.TokenType != JsonTokenType.StartArray)
        throw new JsonException();
    var sc = new StringCollection();
    while (reader.Read() && reader.TokenType != JsonTokenType.EndArray)
        sc.Add(reader.GetString());
    return sc;
}

Then add the converter to JsonSerializerOptions and deserialize as follows:

var options = new JsonSerializerOptions 
{ 
    Converters = { new StringCollectionConverter(), /* Add other converters here */ },
    // Set other options below
    WriteIndented = true,
};
var model = JsonSerializer.Deserialize<AclRecord>(json, options);

To configure the options for Asp.NET Core 3.1 and later, see How to set json serializer settings in asp.net core 3?.

Demo fiddles here and here.

Comments

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.