10

Just recently, I have been trying out the new asp.net features and came across this issue. I know that we can read the configuration as strongly typed instance. but i have no idea how can i inject the configuration to my class in Microsoft dependency injection.

public interface IProvider
{
  IMyConfiguration Configuration {get;}
  Task Connect();
}

public abstract class Provider: IProvider
{
    private IMyConfiguration _myConfig;

    public Provider(IMyConfiguration config)
    {
        this._myConfig= config;
    }

    public IMyConfiguration Configuration => _myConfig;
    public abstract Task Connect();
}

public class ProviderOne:Provider
{
    public ProviderOne(IMyConfiguration  config) : base(config)
    {
    }

    public Task Connect()
    {
      //implementation
    }
}

configuration class:

public interface IMyConfiguration
{
     string TerminalId { get;set; }
     bool IsDefault {get;set;}
}
public class MyConfiguration : IMyConfiguration
{
     string TerminalId { get;set; }
     bool IsDefault {get;set;}
}

and then in startup.cs as i declared, it is required to pass the MyConfiguration. but i could not find a way to do so. please advice!

public void ConfigureServices(IServiceCollection services)
{
  services.Configure<MyConfiguration>(Configuration.GetSection("MyConfiguration"));
  services.AddSingleton<IProvider>(new ProviderOne(//configuration)); //here is the problem
}
Behzad
  • 857
  • 1
  • 8
  • 27

2 Answers2

13

Option 1

First of all, you don't need IMyConfiguration interface. .NET Core already uses own IOptions interface for abstraction. When you use

services.Configure<MyConfiguration>(Configuration.GetSection("MyConfiguration"));

you tell the DI how to resolve next dependency: IOptions<MyConfiguration>

So, instead of

public Provider(IMyConfiguration config)

use

private MyConfiguration _myConfig;

public Provider(IOptions<MyConfiguration> options)
{
    this._myConfig = options.Value;
}

The same for ProviderOne

public ProviderOne(IOptions<MyConfiguration> options) : base(options)

As .NET Core DI knows how to resolve dependencies that are registered, now you can simply use next version of the method:

services.AddSingleton<IProvider, ProviderOne>();

Option 2

You may leave your code as is; directly instantiate instance of MyConfiguration in ConfigureServices method and use for ypur Provider instance creation:

var myConfiguration = new MyConfiguration();
Configuration.GetSection("MyConfiguration").Bind(myConfiguration);

services.AddSingleton<IProvider>(new ProviderOne(myConfiguration));

The main difference is that in this case, you don't use the DI container for ProviderOne instantiation. And so the main disadvantage is that if you need to add more dependencies for your provider (and so extend number of constructor parameters) you should resolve those dependencies in ConfigureServices method as well. For more details, you may find next discussion useful: Best way to resolve during ConfigureServices.

In general, for situation when you have only one implementation of IMyConfiguration, it is possible to do even so:

services.AddSingleton<IMyConfiguration>(myConfiguration);
services.AddSingleton<IProvider, ProviderOne>();

and DI container will understand how to handle that. But as built-in DI container does not allow registering multiple services and then retrieving a specific one, this is not works for you. Some people solve that problem by using the Factory pattern. You will find more in next SO question: How to register multiple implementations of the same interface in Asp.Net Core?

Community
  • 1
  • 1
Set
  • 47,577
  • 22
  • 132
  • 150
  • Good but there is one problem, lets say we have different instances of MyConfiguration and Provider, how should each provider wire to its configuration. – Behzad Apr 19 '17 at 11:25
  • @Behzad ok, I have added option 2 – Set Apr 19 '17 at 12:07
  • is it good to do so ? i mean, i do really want to use the best practices in my app – Behzad Apr 19 '17 at 14:30
  • @Behzad if briefly, use DI as much as possible, instead of manual instantiation. The main problem in your case is that you have more than one implementation of `IMyConfiguration` interface, but built-in ASP.NET Core DI container does not support registering multiple services and then retrieving a specific one. I have updated answer and in case if you really have a lot of different `IMyConfiguration` implementations, I suggest looking into using some additional own factory class for configuration instantiation. – Set Apr 19 '17 at 15:02
  • 1
    @Behzad you also may use a non-default IoC in your app, which support namied dependencies. – VMAtm Apr 19 '17 at 16:30
2
  1. Create a class with properties that has to be read from appsettings

Appsettings.json

{
"DecoderClientOptions":
  {
     "url":"someurl@example.com",
     "key":"A90474-kGAAP1"
  }
}

1.Create a model class.

     public class DecoderClientOptions
        {
            public string url { get; set; }
            public int key { get; set; }
        }
  1. Inject dependency in Startup.cs

         services.Configure<DecoderClientOptions> 
         (Configuration.GetSection(nameof(DecoderClientOptions)));
    
  2. Use the properties in other classes

        public class DecoderClient : IDecoderClient
        {      
            private readonly IOptions<DecoderClientOptions> _ClientOptions;
    
            public DecoderClient(IOptions<DecoderClientOptions> ClientOptions)
            {
                _ClientOptions = ClientOptions;
            }
    
          var url = _ClientOptions.Value.url;
          var key = _ClientOptions.Value.key;
    
Dev-lop-er
  • 578
  • 1
  • 7
  • 16