0

I have a class something like this

public class A{
    public Guid userId { get; set; }
    public Guid businessId { get; set; }
    public Dictionary<int, long> rights { get; set; }
}

And I want to covert this json to this class

    {
    "userId": "dc2af693-72e1-49a7-80aa-6416c6536bdf",
    "businessId": "0110eea4-7a47-4a7c-95ea-10547ab49652",
    "rights": "{\"19\":1,\"17\":15,\"18\":1,\"23\":1,\"1\":31,\"20\":3,\"3\":1,\"16\":0}",
   }

But when Im trying to convert it with NewtonSoft.Json

JsonConvert.DeserializeObject<A>(json);

I get the following error Cannot Cast System.string to System.Dictionary<int,long> What happens is that my rights get converted to a string something like this

"{"19":1, "17":15, "18":1, ..., "16":0}"

If I deserialize this string again it works as I desire is there better method to do this.

6
  • 1
    Actually the content of "rights" is a string, as all the quotes are escaped by backslashes (\") Commented Oct 5, 2021 at 12:58
  • 1
    Have you tried creating a sample object and serializing it first to see what it looks like serialized? I find this to be a good method of finding some of the more easy-to-miss errors when building complex strings. Commented Oct 5, 2021 at 13:00
  • 1
    The data in rights is effectively a Json representation of a dictionary, so this could be a two-step process: first deserialize rights as a string, them deserialize it again as a dictionary: Dictionary<int, long> RightValues => JsonConvert.DeserializeObject<Dictionary<int, long>>(rights); Commented Oct 5, 2021 at 13:05
  • @CMGeek this json is the payload of a jwt token where all of are added as claims to user of the token. Commented Oct 5, 2021 at 13:16
  • You'll need to decorate the rights property with a custom JsonConverter - in the custom JsonConverter you'll be able to deserialize the string and then convert into a dictionary. Commented Oct 5, 2021 at 13:19

3 Answers 3

3

Since the rights is in string format, you can add custom JsonConverter which converts the string to dictionary

public class A
{
    public Guid userId { get; set; }
    public Guid businessId { get; set; }
    [JsonConverter(typeof(RightsSerializer))]
    public Dictionary<int, long> rights { get; set; }
}

Here is the RightsSerializer

public class RightsSerializer : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(Dictionary<int, long>);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.Null) return null;

        var jt = JToken.Load(reader);
        return JsonConvert.DeserializeObject<Dictionary<int, long>>(jt.Value<String>());
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        serializer.Serialize(writer, value);
    }
}

And DeserializeObject

var json = File.ReadAllText("json1.json");
var result = JsonConvert.DeserializeObject<A>(json);
Sign up to request clarification or add additional context in comments.

2 Comments

I'm doing like this currently but the class is scoped which I can inject anywhere to get the value isn't there any short-hand where my class is contains the dictionary.
@MuhammadJamali, then you need custom runtime serializer. updated the post to reflect the same
0

changing the class to something like this will help. althoutgh you need to make code better than this.

        public class A
    {
        public Guid userId { get; set; }
        public Guid businessId { get; set; }

        //[JsonConverter(typeof(Dictionary<int, long>))]
        public string rights { get; set; }

        public Dictionary<int, long> rightss => JsonConvert.DeserializeObject<Dictionary<int, long>>(rights);
    }

Comments

0

You can't do it without deserializing twice, but you could hide it with a private subclass.

public class A {
   public Guid userId {get;set;}
   public Guid businessId {get;set;}
   public Dictionary<int, long> rights {get;set;}

   private class B {
      public Guid userId {get;set;}
      public Guid businessId {get;set;}
      public string rights {get;set;}
   }

   private B b;

   public A (string json) {
      var o = new JsonSerializerOptions();
      o.AllowTrailingCommas = true;
      b = JsonSerializer.Deserialize<B>(json, o);
      userId = b.userId;
      businessId = b.businessId;
      rights = JsonSerializer.Deserialize<Dictionary<int, long>>(b.rights,o);
   }
}

Usage with test in fiddle:

Fiddle

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.