If you’ve been using ASP.NET for any length of time you’ve probably had to build your own implementation of the CustomConfiguration class or had to implement the IConfigurationSectionHandler. This usually included writing out each configuration element and how to read it from the XML (Including conversions/casts). What a pain!
DotNetCore takes a much simpler approach to custom configurations. There are two main ways to use it, one that uses an Options class from .net Core, and one that uses simple POCOs.
Method 1 : The Options Class
This way is the most common example you’ll see out there. It uses the Options class built into .net core and is pretty easy to get going. Because it drags around the “options” class, it actually isn’t my preferred method. I much prefer simple POCO’s. If you do too, then skip to Option 2 below. Otherwise read on!
Imagine you have an appSettings.json like so :
{ "myConfiguration": { "myProperty": true } }
You would create a simple configuration class like the following in your project :
public class MyConfiguration { public bool MyProperty { get; set; } }
Notice how in the above we don’t have to inherit or implement any interfaces/classes. It’s a simple POCO that doesn’t require any additional references.
Now in your startup.cs, you have the following :
public class Startup { public Startup(IHostingEnvironment env) { var builder = new ConfigurationBuilder() .SetBasePath(env.ContentRootPath) .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true) .AddEnvironmentVariables(); Configuration = builder.Build(); } public IConfigurationRoot Configuration { get; } public void ConfigureServices(IServiceCollection services) { services.Configure<MyConfiguration>(Configuration.GetSection("myConfiguration")); } }
Notice in the ConfigureServices method we add a configuration to our services. This is all it takes
Next we go to any controller and we can reference IOptions<MyConfiguration> to access our custom configuration.
public class ValuesController : Controller { private readonly MyConfiguration _myConfiguration; public ValuesController(IOptions<MyConfiguration> myConfiguration) { _myConfiguration = myConfiguration.Value; } }
Simple right? But from the above you can probably pick why this isn’t my preferred method. We drag along this IOptions interface but pull the value from it immediately. If we could inject our POCO class that holds our configuration then we don’t need to drag around the IOptions interface. Let’s take a look at that.
Method 2 : Get Configuration Poco
Utilizing what we already have above, we just need to change a couple of lines. In our startup.cs we need to change the call to configure to one that just binds a POCO :
public void ConfigureServices(IServiceCollection services) { //services.Configure<MyConfiguration>(Configuration.GetSection("myConfiguration")); services.AddSingleton(Configuration.GetSection("myConfiguration").Get<MyConfiguration>()); }
A couple of notes :
- You previously were able to call “AddInstance” on an IServiceCollection. This was removed to just allow “AddSingleton”, which really is one and the same anyway.
- Previous versions of .net Core (Pre 1.1) did not allow a call to “Get”, instead you had to do a call to “bind”. This was an added annoyance as you had to instantiate an empty class first. If you are on an early version and unable to upgrade, do the below.
Bind option (Pre ASP.NET core 1.1) :
public void ConfigureServices(IServiceCollection services) { //services.Configure<MyConfiguration>(Configuration.GetSection("myConfiguration")); MyConfiguration configuration = new MyConfiguration(); Configuration.GetSection("myConfiguration").Bind(configuration); services.AddSingleton(configuration); }
Then if you go to your class, you only need to ask for your POCO, not the IOptions. Like so :
public class ValuesController : Controller { private readonly MyConfiguration _myConfiguration; public ValuesController(MyConfiguration myConfiguration) { _myConfiguration = myConfiguration; } }
Best Practice
If you go with Method 2. A good habit to get into is to always inject in an interface instead of your concrete class. This allows for easier mocking when doing unit testing, and it better follows the Dependency Inversion principle which is that you depend on abstractions.
This is exactly what I was looking for, thank you!!!
Great! “Method 2 : Get Configuration Poco” was exactly what I was looking for. Everywhere else they just write about injecting IOptions. I was looking to inject the poco. 🙂