christopher clark
christopher clark

Reputation: 2103

Json with Nested Objects and each are differently named

I have a json object that is coming from an endpoint.

{
"user_info": {
    "myapp1": {
      "roles": [
        "requestor"
      ]
    },
    "myapp2": {
      "roles": [
        "requests-edit",
        "requests-view"
      ]
    },
    "account": {
      "roles": [
        "manage-account",
        "manage-account-links",
        "view-profile"
      ]
    }
  }
}

Based on this structure its pretty clear that there are two strongly typed objects. user_info and roles. However, the apps (myapp1, myapp2, account) are not in an array, they are "dynamic" or "anonymous" objects.

What is the recommended way to get the roles with a known app name?

EG, some pseudo code.

// returns the sub objects as a dictionary of <string, Roles>;
var anonjson = JsonAnon.DeserializeOnProperty<string, Roles>("user_info");
var roles = anonjson.Where(x => x.Key.Value == "myapp2").FirstOrDefault();
// i forget what dictionaries use to get by key I put x.Key, this could be invalid.

Upvotes: 1

Views: 240

Answers (2)

RoadRunner
RoadRunner

Reputation: 26315

Similar to what @OwnBlood suggested, you can make two classes using the Newtonsoft.Json framework:

public class Application
{
    [JsonProperty("roles")]
    public IEnumerable<string> Roles { get; set; }
}

public class User
{
    [JsonProperty("user_info")]
    public IDictionary<string, Application> UserInfo { get; set; }
}

Then you can deserialize with the JsonConvert.DeserializeObject() method:

var deserializedJson = JsonConvert.DeserializeObject<User>(jsonString);

And you can create a method that filters out the roles from a specific application name using LINQ:

private static IEnumerable<string> GetUserApplicationRoles(string applicationName, User data) => 
    data.UserInfo
        .TryGetValue(applicationName, out var value) ?
            value.Roles : 
            Enumerable.Empty<string>();

Explanation:

  • Since UserInfo is a IDictionary<string, Application>, we can use TryGetValue to access the specific applicationName. This allows O(1) access.
  • Then we can simply return the IEnumerable<string> roles, or an empty collection, in this case Enumerable.Empty<string>.

Working demo found at dotnetfiddle.net

Upvotes: 2

OwnBlood
OwnBlood

Reputation: 197

Hey I suggest creating 2 classes for Deserialization

    public class UserInfo
    {
        [JsonProperty("user_info")]
        public Dictionary<string, Account> Users { get; set; }
    }

    public class Account
    {
        [JsonProperty("roles")]
        public List<string> Roles { get; set; }
    }

The deserialization could then look like this

        var info = JsonConvert.DeserializeObject<UserInfo>(jsonString);
        var allRoles = info.Users.SelectMany(x => x.Value.Roles);

The examle uses the Newtonsoft package

Hope this helps.

Upvotes: 3

Related Questions