In this article, we will explore how to get a JSON array using IConfiguration. In modern web applications, JSON is a widely used data interchange format due to its lightweight nature and ease of use. When developing an ASP.NET Core application, it is common to store configuration data, such as settings and connection strings, in JSON files like appsettings.json.

ASP.NET Core provides the IConfiguration interface for accessing configuration data from various sources, including JSON files.

Support Code Maze on Patreon to get rid of ads and get the best discounts on our products!
Become a patron at Patreon!
To download the source code for this article, you can visit our GitHub repository.

Let’s dive in.

JSON File Structure and Sample Data

Before starting, let’s consider the file structure and the sample JSON data stored in the appsettings.json file to demonstrate how to get a JSON array using IConfiguration. The JSON file includes arrays and nested arrays as well.

Let’s see what is the structure of the appsettings.json file:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*",
  "AppSettings": {
    "Users": [
      {
        "Id": 1,
        "Name": "John Doe",
        "Role": "Admin"
      },
      {
        "Id": 2,
        "Name": "John Smith",
        "Role": "User"
      }
    ],
    "Groups": [
      {
        "Id": 1,
        "Name": "Developers",
        "Members": [
          {
            "Id": 1,
            "Name": "John Doe"
          },
          {
            "Id": 2,
            "Name": "John Smith"
          }
        ]
      }
    ]
  }
}

On the first level, we create an AppSettings object with two arrays, Users and Groups. The array Users has other objects with simple properties while the array Groups has objects where one of the properties, Members, is another array of objects. 

Get JSON Array Using IConfiguration With GetSection() and GetChildren()

In this section, we will get a JSON array using IConfiguration with the help of the GetSection() and GetChildren() methods. GetSection() retrieves a configuration sub-section with a specified key, and GetChildren() returns the immediate descendant configuration sub-sections. By using them together we can navigate hierarchically on any JSON structure.

Let’s now see the model that we will use in this section:

public record User(int Id, string Name, string Role);

Further, the first method that we will use in the API:

public static IEnumerable<User> GetUsersArrayFromAppSettings(IConfiguration configuration)
{
    IConfigurationSection usersSection = configuration.GetSection("AppSettings:Users");
    IEnumerable<IConfigurationSection> usersArray = usersSection.GetChildren();
    
    return usersArray.Select(configSection => 
        new User 
        (
            Id: int.Parse(configSection["Id"]!.ToString()),
            Name: configSection["Name"]!.ToString(),
            Role: configSection["Role"]!.ToString())
        );
}

First, we use the method GetSection() which is returning an IConfigurationSection. IConfigurationSection represents a section of application configuration values and inherits from IConfiguration, so all methods available through IConfiguration we can use on IConfigurationSection as well. The usersSection is an array of users.

Next, we use the IConfiguration.GetChildren() method to get each element in the array as a separate IConfigurationSection. The GetChildren() method returns IEnumerable<IConfigurationSection>. Each IConfigurationSection represents an item in the array Users in the appsettings.json.

Finally, we extract the data from each IConfigurationSection element. We use the LINQ Select() method to project from IConfigurationSection to User object with the Id, Name and Role properties. Then, we use an indexer on the configSection to read the data. Because the indexer returns the data in a string type, for the Id property we parse it back to an int.

Get JSON Array Using Using IConfiguration With Get<T>()

It is often more convenient to map the JSON data to a C# type. Let’s create the necessary types to represent the JSON data:

public record User(int Id, string Name, string Role);

public record AppSettings
{
    public List<User>? Users { get; init; }
};

Further, with the help of IConfiguration.Get<T>() method, we will get a JSON array, in a much more straightforward way:

public static List<User>? GetUsersArrayFromAppSettingsV2(IConfiguration configuration)
{
    return configuration.GetSection("AppSettings:Users").Get<List<User>>();
}

We use the GetSection() method to get the IConfigurationSection with AppSettings:Users key. In the appsettings.json file, this is an array of users. Then, instead of going through each child, we use the Get<T>() method where T in our case is List<User>, and it attempts to bind it to the specified type. 

Get Nested JSON Array Using IConfiguration With Get<T>()

Finally, we will read nested JSON arrays using the IConfiguration.Get<T>() method. This method works by attempting to bind the configuration instance to a new instance of the provided type T. If this configuration section has a value, that will be used. Otherwise, the binding is done by recursively matching property names against configuration keys.

First, we will extend our model so that we can map the groups and members of each group from the appsettings.json file:

public record User(int Id, string Name, string Role);

public record Member(int Id, string Name);

public record Group(int Id, string Name)
{
    public List<Member>? Members { get; init; }
};

public record AppSettings
{
    public List<User>? Users { get; init; }
    public List<Group>? Groups { get; init; }
};

We add the Member and Group types, which are records. Then, we extend the AppSettings record with the Groups property. 

Further, we will read the nested array Members under the Group record type:

public static IEnumerable<Member>? GetGroupMembers(IConfiguration configuration)
{
    AppSettings? appSettings = configuration.GetSection("AppSettings")?.Get<AppSettings>();
    
    return appSettings?.Groups?.SelectMany(x => x.Members);
}

We use the GetSection() and the Get<T>() methods as in the previous example, with the only difference in the key, and the key is AppSettings. Then, we iterate through the Groups and with the help of SelectMany() and Distinct() methods, we return all distinct Members from each group.

Pitfalls of Using IConfiguration

When working with arrays using IConfiguration in ASP.NET Core, it’s essential to be aware of potential problems that can arise and know how to handle them effectively. In this section, we will explore some common challenges and provide solutions to deal with them.

Missing or Incorrect Configuration Section

One common issue is when the configuration section containing the array is missing or incorrectly specified. This can lead to errors or unexpected behavior when trying to retrieve the array from the configuration. To handle this, you can use conditional checks to verify the existence of the section before accessing it:

if (configuration.GetSection("MyArraySection").Exists())
{
    var myArray = configuration.GetSection("MyArraySection").Get<string[]>();
    // Process the array
}
else
{
    // Handle the missing section scenario
}

Mismatch Between JSON Structure and C# Class Structure

Another challenge can arise when there is a mismatch between the structure of the JSON array in the configuration file and the corresponding C# class structure used for mapping. In such cases, the mapping may fail, resulting in null or default values. It’s crucial to ensure that the structure of the C# class matches the JSON structure accurately. Consider using tools like Newtonsoft.Json or System.Text.Json to deserialize the array into a strongly typed object. This allows for better validation and error handling during the mapping process.

Misinterpretation of Null Values

Handling null values in arrays can be tricky, especially when dealing with optional or nullable elements. By default, when deserializing an array, null values are ignored and not included in the resulting array. If you need to include null values, you can configure the deserialization behavior accordingly. For example, using Newtonsoft.Json, you can specify NullValueHandling.Include to ensure null values are preserved in the deserialized array.

Incorrect Data Type Mapping

It’s essential to ensure that the data types specified in the configuration match the expected types in your code. If there is a mismatch, the mapping process may throw an exception or provide unexpected results. Take care to validate the data types and handle any potential type conversion errors appropriately. You can use techniques like TryParse() to handle conversions and provide meaningful error messages when encountering incompatible data types.

Ignoring Case Sensitivity

In ASP.NET Core’s configuration system, keys are case-sensitive by default. This means that the configuration keys in the JSON file must match the keys used when accessing the configuration values. Be cautious about any differences in letter casing, as it can lead to configuration values not being found or retrieved correctly.

Conclusion

In this article, we have explored different ways to get JSON arrays and nested JSON arrays using the IConfiguration interface in ASP.NET Core. We have demonstrated how to access the JSON data directly and how to map it to C# record types for more structured access and processing.

We should mention at this point that using the Options pattern provided by ASP.NET Core is superior to this approach (due to type safety, ease of testing, sub-section mapping, etc.).

Liked it? Take a second to support Code Maze on Patreon and get the ad free reading experience!
Become a patron at Patreon!