ASP.NET Core Configuration

I have seen this common pattern to get connection strings, application configuration settings and logger in ASP.NET core application;

public class HomeController 
{
   private IUnitOfWork _unitOfWork;
   private IConfiguration _configuration;        
   private AppConfig _appConfiguration;
   private readonly ILogger _logger;

   public HomeController(IUnitOfWork unitOfWork, IConfiguration configuration, IOptions<AppConfig> appConfiguration, ILogger<ProjectController> logger)
   {
        _unitOfWork = unitOfWork;
	_configuration = configuration;
        _appConfiguration = appConfiguration.Value;
        _logger = logger;
   }

This works fine but it’s reparative for configurations and logger and violates DRY principal. A good alternative is this;

Register these assemblies in your startup (startup.cs) to take advantage of dependency feature;

public void ConfigureServices(IServiceCollection services)
        {
            //Add functionality to inject IOptions<T>
            services.AddOptions();

            //Add our Config object so it can be injected
            services.Configure<ConnectionString>(Configuration.GetSection("ConnectionStrings"));
            services.Configure<AppConfig>(Configuration.GetSection("AppConfig"));
        }

UPDATE @10/18/2022
For .NET 6, the configuration is;
builder.Services.AddOptions();

builder.Services.Configure<ConnectionString>(builder.Configuration.GetSection("ConnectionStrings"));

builder.Services.Configure<AppConfig>(builder.Configuration.GetSection("AppConfig"));

Create AppConfig POCO class;

public class AppConfig
{
   public string ApplicationName { get; set; }
   public string Version { get; set; }
}

Create a base class and declare these services as properties.

using System;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;

using ConfigDemo.Models;

   public abstract class BaseController<T> : Controller where T : BaseController<T>
    {
        private ILogger<T> _logger;
        private IConfiguration _configuration;
        private IOptions<ConnectionString> _appConnectionString;
        private IOptions<AppConfig> _appConfiguration;

        protected ILogger<T> Logger => _logger ?? (_logger = HttpContext?.RequestServices.GetService<ILogger<T>>());
        protected IConfiguration Configuration => _configuration ?? (_configuration = HttpContext?.RequestServices.GetService<IConfiguration>());
        protected IOptions<ConnectionString> AppConnectionString => _appConnectionString ?? (_appConnectionString = (HttpContext?.RequestServices.GetService<IOptions<ConnectionString>>()));
        protected IOptions<AppConfig> AppConfiguration => _appConfiguration ?? (_appConfiguration = (HttpContext?.RequestServices.GetService<IOptions<AppConfig>>()));

        protected string DisplayMessage
        {
            get { return TempData["DisplayMessage"] == null ? String.Empty : TempData["DisplayMessage"].ToString(); }
            set { TempData["DisplayMessage"] = value; }
        }
    }

We have these values in our appsettings.json file that we would like to use in our application;

{
  "ConnectionStrings": {
    "DBConnection1": "Data Source=(local);Initial Catalog=MyDb1;Persist Security Info=True;Integrated Security=True",
    "DBConnection2": "Data Source=(local);Initial Catalog=MyDb2;Persist Security Info=True;Integrated Security=True"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Warning"
    }
  },
  "AllowedHosts": "*",
  //application configratuion here
  "AppConfig": {
    "ApplicationName": "MyApp",
    "Version": "1.0.0"
  }
}

Let’s create a demo view to display output values;

@model String
@{
    Layout = null;
}
<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Result</title>
</head>
<body>
    <div>
        @Model
    </div>
</body>
</html>

Finally create our first HomeController by inheriting from base controller to read config values;

       public class HomeController : BaseController<HomeController>
    {
        //Navigate to URL, for example https://localhost:44320/home/simpleconfig
        public string Index()
        {
            Logger.LogInformation("I am using dependency injection created in the base cotroller");
            return "Navigate to URL to show an example";
        }

        //using configuration
        public ViewResult SimpleConfig()
        {
            var configValue = Configuration.GetSection("AppConfig").GetChildren();
            string result = configValue.Select(i => i.Value).Aggregate((i, j) => i + "," + j );
            // generate the view
            return View("Result",
            (object)String.Format("Simple Config value: {0}", result));
        }

        //using strong type
        public ViewResult ConfigValueFromConfig()
        {
            string configValue = AppConfiguration.Value.ApplicationName;
            // generate the view
            return View("Result",
            (object)String.Format("App Config value: {0}", configValue));
        }

Run your application and navigate to action method like this;

You can download sample project from GitHub;

https://github.com/shahzy1/ConfigDemoApplication/tree/main

Resources

https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-5.0

https://stackoverflow.com/questions/47433027/configuration-getsection-in-asp-net-core-2-0-getting-all-settings

FavoriteLoadingAdd to favorites
Spread the love

Author: Shahzad Khan

Software developer / Architect