As known there are two ways to get option classes in ASP.NET Core 2:
Using services.Configure<>()
like this:
services.AddOption();
services.Configure<ApplicationOptions>(Configuration.GetSection("applicationSettings"));
or using services.AddSingleton(Configuration.Get())
like this:
services.AddSingleton(Configuration.GetSection("applicationSettings")
.Get<ApplicationOptions>());
But what advantages or disadvantages do these different approaches have?
Using Configure<ApplicationOptions>
allows the options pattern. The options pattern is a nice way to configure things using various configuration sources. In your example, you are configuring the ApplicationOptions
using a Microsoft.Extensions.Configuration source. But you can also configure it through other sources at the same time:
// configure using configuration
services.Configure<ApplicationOptions>(Configuration.GetSection("applicationSettings"));
// then apply a configuration function
services.Configure<ApplicationOptions>(options =>
{
// overwrite previous values
options.Foo = "bar";
});
There are a few other ways to adjust the configuration as well, for example using post-configures which allows you to easily compose things that utilize options but may need to establish certain defaults or fallbacks.
Option objects will be configured at the time they are used, so when you call services.Configure()
, there is actually nothing being configured at that time. Instead, configurations are registered with the DI container. And then, when the options are resolved, all configurations for a certain type will be invoked (which allows for composition). This allows options to also support updating configuration; so when you update your appsettings.json
at run-time, options are able to receive the updated values.
In order to consume options, you need to inject IOptions<ApplicationOptions>
(or IOptionsSnapshot<ApplicationOptions>
if you need updating options). This is a wrapper around the options object which will invoke the options pattern.
On the other hand, calling AddSingleton<ApplicationOptions>
just registers a singleton instance as a fixed value. So what gets registered with the DI provider is whatever value Configuration.GetSection("applicationSettings").Get<ApplicationOptions>()
returns at that exact moment.
This has the benefit that you do not need to use the options pattern; instead of having to inject IOptions<ApplicationOptions>
into your types, you can just depend on ApplicationOptions
directly. So you don’t take a dependency on the Options framework. This is good for independent libraries that want to be used in different scenarios where the options pattern might not be available by default.
However, since this registers a fixed instance, you are also limited to those exact values. You cannot have those values update later when the configuration source is changed, and also cannot use that one configuration source in combination with other configurations.
Short answer : The 1st way adds an Options
, and the 2nd way registers a plain singleton service.
I always prefer Options Pattern if possible.
Behind the scenes , the Configure<TOptions>()
will invoke services.AddSingleton<>()
to register a singleton service to configure options. However, To configure options, we should always use the 1st way. As the Configure<TOptions>(config)
(and all kind of other configure<>()
methods) will do all the heavy-lifting for us. :
For example, if we would like to store two different instance for the same type, how can we do that with a plain singleton service ? In fact, that' exactly what named options does.
Also, it hard to auto reload a plain singleton service according to a file change to applicationSettings.json
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With