Registering Multiple Implementations of an Interface with Service Collection in ASP.NET Core

Full source code here.

This is a simplistic approach to the problem and assumes that the dependencies created by the factory do not in turn have their own dependencies. This deficiency could be mediated by passing those dependencies into the factory. Having said that it will be of use in some scenarios. I will publish a post in the future providing a better solution.

In a later post I will show how to use Autofac to do this properly.

The out-of-the-box dependency injection container provided by Microsoft as part of ASP.NET Core is fine for most scenarios, only in a few complicated cases have I needed to switch to Castle or AutoFac.

But there is one somewhat common case where the ServiceCollection feels a little deficient. There are times when you might have more than one implementation of an interface and you would like to choose between them at runtime.

There is no obvious way to do this.

You could try something like –

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddScoped<IValuesService, PositiveValuesService>();
            services.AddScoped<IValuesService, NegativeValuesService>();
	//snip...

But when you request an implementation of IValuesService in the constructor of a controller, the service collection will return the last registered service, in this case it will always return the NegativeValuesService.

But what if you wanted the PositiveValuesService in some controllers and the NegativeValuesService in other controllers. What if you needed to choose the service implementation based on the address of the request that the controller is handling.

Something like this –
localhost:5000/NegativeValues – should use the NegativeValuesService.
localhost:5000/PositiveValues – should use the PositiveValuesService.

Using a Factory
Instead of registering two implementations of the IValuesService, I’m going to create a ValuesServiceFactory that returns the right service based on the path of the request.

The ValuesServiceFactory has a method that looks like this –

public IValuesService GetValuesService()
{
    string path = _httpContextAccessor.HttpContext.Request.Path.Value.ToString().Trim('/').ToLower();
    switch (path)
    {
        case "positivevalues":
            return new PositiveValuesService(); // as mentioned above this only works if the values services have no dependencies
        case "negativevalues":
            return new NegativeValuesService();
        default:
            return new PositiveValuesService();
    }
}

_httpContextAccessor is what lets me access the Request from inside the factory.

A few weeks ago I wrote about post about accessing the HttpRequest from inside the constructor of a controller or from the constructor of a service the controller depends on.

That post had a contrived example, but this post has a more practical use of the technique.

The constructor of the ValuesServiceFactory needs to take an IHttpContextAccessor.

public ValuesServiceFactory(IHttpContextAccessor httpContextAccessor)
{
    _httpContextAccessor = httpContextAccessor;
}

Back in Startup.cs, remove the code registering the two services and replace with a line to register the factory and the HttpContextAccessor.

public void ConfigureServices(IServiceCollection services)
{
    services.AddScoped<IValuesServiceFactory, ValuesServiceFactory>();
    services.AddHttpContextAccessor();
    //snip…
}

The controllers now take the implementation of IValuesServiceFactory and request the an IValuesService from the factory.

private readonly IValuesService _valuesService;

public NegativeValuesController(IValuesServiceFactory valuesServiceFactory)
{
    _valuesService = valuesServiceFactory.GetValuesService();
}

Do the same in the other controller –

private readonly IValuesService _valuesService;

public PositiveValuesController(IValuesServiceFactory valuesServiceFactory)
{
    _valuesService = valuesServiceFactory.GetValuesService();
}

That’s it, now you can choose between implementation of an interface. As I was working on this post I came across a post by Steve Gordon on this topic, he solves the same problem in a different way.

Full source code here.

Accessing the HttpContext from the Constructor of a Controller or a Dependency

Full source code here.

There are times when you may need to access the HttpRequest from places that it is not normally available such as the constructor of a controller or the constructor of a service that is built by dependency injection.

Take the example of a ValuesController that relies on a NumberGeneratorService, where both need to know the Host used in the request.

But you can’t just access the Host via the Request in either case. It is not yet available in the lifetime of the controller and it will not be available at all in the life of the service. (By the time you reach the action method of the controller you will have access to it.)

Fortunately there is a way to get at it using the HttpContextAccessor.

In Startup.cs add the following –

public void ConfigureServices(IServiceCollection services)
{
    services.AddScoped<INumberGeneratorService, NumberGeneratorService>();
    services.AddHttpContextAccessor();
    //snip..
}

Pass IHttpContextAccessor to the constructor of the ValuesController

public ValuesController(IHttpContextAccessor httpContextAccessor, INumberGeneratorService numberGeneratorService)
{
    _numberGeneratorService = numberGeneratorService;
    Console.WriteLine($"Request.Host inside constructor of controller : {httpContextAccessor.HttpContext.Request.Host.Value}");
}

Do the same to the constructor of the the NumberGeneratorService

public NumberGeneratorService(IHttpContextAccessor httpContextAccessor)
{
    _httpContextAccessor = httpContextAccessor;
    Console.WriteLine($"Request.Host inside service : {httpContextAccessor.HttpContext.Request.Host.Value}");
}

Now you have full access to everything about the request in controller’s constructor and the services you depend on.

In another post I’ll show a more practical use of this when I want to use the dependency injection with two implementations of an interface, HttpContextAccessor will help me choose between them based on the request.

Full source code here.