25

I am learning DI in .Net Core and I do not get the idea about the benefit of using IOptions.

Why do we need IOptions if we can do without it?

With IOptions

interface IService
{
    void Print(string str);
}

class Service : IService
{
    readonly ServiceOption options;
    public Service(IOptions<ServiceOption> options) => this.options = options.Value;
    void Print(string str) => Console.WriteLine($"{str} with color : {options.Color}");
}

class ServiceOption
{
    public bool Color { get; set; }
} 

class Program
{
    static void Main()
    {
        using (ServiceProvider sp = RegisterServices())
        {
            //
        }
    }


    static ServiceProvider RegisterServices()
    {
        IServiceCollection isc = new ServiceCollection();

        isc.Configure<ServiceOption>(_ => _.Color = true);
        isc.AddTransient<IService, Service>();
        return isc.BuildServiceProvider();
    }
}

Without IOptions

interface IService
{
    void Print(string str);
}

class Service : IService
{
    readonly ServiceOption options;
    public Service(ServiceOption options) => this.options = options;
    public void Print(string str) => Console.WriteLine($"{str} with color : {options.Color}");
}

class ServiceOption
{
    public bool Color { get; set; }
}

class Program
{
    static void Main()
    {
        using (ServiceProvider sp = RegisterServices())
        {
            //
        }
    }

    static ServiceProvider RegisterServices()
    {
        IServiceCollection isc = new ServiceCollection();

        isc.AddSingleton(_ => new ServiceOption { Color = true });
        isc.AddTransient<IService, Service>();
        return isc.BuildServiceProvider();
    }
}
Second Person Shooter
  • 14,188
  • 21
  • 90
  • 165
  • 5
    The options pattern adds a few features. For example, named options, reloading of options at runtime and a delegate-based pipeline that allows for multiple actors to contribute to how a "settings" class gets configured. The [docs](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/configuration/options?view=aspnetcore-2.2) explain a lot of this in great detail. Ultimately, if you don't need any of those features, you don't *need* to use `IOptions`. – Kirk Larkin Feb 23 '19 at 17:18
  • 1
    I have an answer [here](https://stackoverflow.com/questions/54147660/why-addmvc-expects-actionmvcoptions-instead-of-mvcoptions/54148525#54148525) that digs into the configuration pipeline a little bit more that *might* help. – Kirk Larkin Feb 23 '19 at 17:20
  • 1
    "When do we need IOptions?" => whenever the pattern suits what you want to do? It doesn't seem like you have done any kind of research and an answer could be outdated quite fast with the moving speed of ASP.NET Core – Camilo Terevinto Feb 23 '19 at 17:25

3 Answers3

14

In .Net core, it is recommended that all your configurations should be strongly typed based on their use cases. This will help you to achieve separate of concerns.

Practically, you can achieve the same thing without using IOptions as you stated. So, if I go back one step and if we have a look at all the available options in .net core configuration:

1. Raw Configuration[path:key]

You can directly access IConfiguration instance and provide path of JSON key in the accessor part, and the configuration value would be returned.

This is not good approach because there is no strong typing here while reading the configuration.

2. IOptions binding to a Config Section

You can use IOptions implementation (which you already know). This is better because you can have a single class with all related configurations. The IOptions interface provides you additional benefits.

As far as I understood, this IOptions interface decouples your configuration from the actors who are reading the configuration and thereby you can use some additional services from .net core framework.

Please refer MSDN article for details about the benefits.

You can also refer to the twitter conversation at this blog. In that blog, Rick also explains that he could not find any practical case on how this approach is different from the 3rd approach below - as generally the configurations are not dynamic and they are done only once before the application startup.

3. Configuration.Bind() to bind to a Config Section

You can use .Bind call to bind a configuration section to a POCO class. You get strongly typed object. Here if multiple actors are using the configurations, they will not get additional services provided by IOptions interface.

I know this is not exactly pointing out the difference. But I am sure this will bring little more clarity on deciding your preference.

Manoj Choudhari
  • 5,277
  • 2
  • 26
  • 37
  • I don't see how this answers the question. You *bind* options to a POCO and still inject just that in your service; that's exactly his 'Without IOptions' example. This answer doesn't address the advantages of using IOptions over using the POCO directly. – Vincent Sels Feb 02 '23 at 08:43
1

Short answer: yes, you can do without it and access your setting directly from ConfigurationManager.AppSettings, like in this answer.

Slightly longer answer: especially when you want to test your (Console) Application, it might be nice to inject services and settings.

ASP.NET Core comes with DI included and it will be set up in your Startup.cs. DI can be used in Console Applications, but it might be hard(er) to set it up, as the default application has no plumbing for it. I wrote a small blog on how to setup DI with IOptions configuration for .NET Core Console Applications.

Kees C. Bakker
  • 32,294
  • 27
  • 115
  • 203
  • 3
    That wasn't the question though. He asked about the benefits of using IOptions when we could also inject an instance of ConfigClass directly. – TravelingFox Sep 02 '22 at 09:29
1

By itself IOptions<TOptions> doesn't add anything, in your examples. However, it allows you to use the OptionsBuilder API, should you need any of its features:

  • Configuring your Options objects using other services;
  • Validate your Options object;
  • Add post-configuration to your Options object.

From my experience, all of these use cases are quite exotic, though. For the basic use case, where you want to bind a section of your IConfiguration to an Options object, you can just inject the Options object directly, as per your second example. Not using the IOptions<T> interface has the benefit of being less cumbersome to unit test - you don't need to mock it.

However, if you want your Options values to automatically update at runtime as the configuration sources change, you will need to make use of a wrapper interface. But IOptions<T> itself doesn't do that - you'll need to use either IOptionsSnapshot<T> or IOptionsMonitor<T> for that.

Vincent Sels
  • 2,711
  • 1
  • 24
  • 31