Manage configuration in your .NET Core web projects by using the IOptions interface

Every application out there needs to read some configuration written from the programmers in order to perform critical tasks and function correctly. Examples of configuration can be the connection string to your SQL database or a boolean flag which decides if a feature will be available to your customers or not.

.NET Core gives us a way to store our configuration in a json file and access its properties programmatically.

This way of coding gives us the advantage of not having to redeploy our application, every time we update a value in our configuration (in our case the json file). We simply have to recycle the application pool that hosts our application and we are set.

Lets see an example of how to parse and use the values of a configuration json file inside an API controller.

We first create a new .NET Core web API application. The application is going to contain only one API function which does a HTTP request to a configured website and returns its content length.

The loaded project already contains an appsettings.json file (the naming of the file is up to you). Do not remove the contents of this file, just update it to look like following:

{
  "Logging": {
    "IncludeScopes": false,
    "Debug": {
      "LogLevel": {
        "Default": "Warning"
      }
    },
    "Console": {
      "LogLevel": {
        "Default": "Warning"
      }
    }
  },
  "AppSettings": {
    "KnownWebsites": {
      "USA": {
        "Website1": "https://www.facebook.com/"
      },
      "Europe": {
        "Website1": "https://www.theguardian.com/international"
      }
    }
  }
}

As you can see the structure of the json file contains a hierarchy of objects with properties.

We have to hook the json file with .NET Core. We do that in the Startup class of our project. If you renamed the json file, then change also the name of the file:

public IConfiguration Configuration { get; }

public Startup(IHostingEnvironment env)
{
    // Set up configuration sources.
    var builder = new ConfigurationBuilder()
        .SetBasePath(env.ContentRootPath)
        .AddJsonFile("appsettings.json", true, true);

    Configuration = builder.Build();
}

In the Startup constructor we added the contents of the json file to a variable of type ConfigurationBuilder.

Now lets define a new file and call it AppSettings (the filename does not play any role). This file is going to contain the structure of our json file but expressed as C# POCO classes. As you can see in the following code, we converted a part of the json file into C# objects and we referenced them in a top-down approach:

public class AppSettings
{
    public KnownWebsites KnownWebsites { get; set; } = new KnownWebsites();
}

public class KnownWebsites
{
    public USA USA { get; set; } = new USA();

    public Europe Europe { get; set; } = new Europe();
}

public class USA
{
    public string Website1 { get; set; }
}

public class Europe
{
    public string Website1 { get; set; }
}

We return to the Startup class and update the ConfigureServices method to look like following:

// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
    // Add framework services.
    services.AddMvc();

    services.Configure<AppSettings>(Configuration.GetSection("AppSettings"));
}

We wired the AppSettings class to the AppSettings section of the json file, and we are now ready to use an instance of the AppSettings class in our code.

We open the default .NET Core API controller (ValuesController), rename it and update the constructor to look like that:

private readonly AppSettings _appSettings;

public WebsiteCallerController(IOptions<AppSettings> appSettings)
{
    _appSettings = appSettings.Value;
}

The IOptions interface is hooked with the instance of the AppSettings class, which contains our configuration. We store the Value property into a field and we are now ready to use the configuration in our action methods.

The only action of our API is calling the first website of a region based on the region given by the user. Here is the code:

[HttpGet]
public long Get(string region)
{
    var url = "";

    if (region == "europe")
    {
        url = _appSettings.KnownWebsites.Europe.Website1;
    }
    else if (region == "usa")
    {
        url = _appSettings.KnownWebsites.USA.Website1;
    }

    WebRequest webRequest = WebRequest.Create(url);
    WebResponse webResp = webRequest.GetResponse();

    return webResp.ContentLength;
}

The url variable contains now the URL defined in the json file, which we use to make the HTTP call.

Like that you can use the properties of your AppSettings class everywhere you need them.

You can find more information about the IOptions interface here.

Conclusion

I personally like the described approach of accessing configuration from my code, since I can update the values of the appsettings.json file at run time. However, it has to be clear that if we want to add new configuration, then we have to update accordingly our AppSettings class and redeploy our application.

Other approaches of reading configuration are storing key-value pairs into a DB table and loading them when needed, or load the configuration into your application’s cache (Redis, AppFabric, etc.) and retrieve it from there any time they are needed.

comments powered by Disqus