Inject Multiple Service Implementations in ASP.NET Core

Most people are familiar using an IOC container to facilitate dependency injection in their applications.  But have you come across a situation where you wanted to inject multiple implementations of an interface?  I have!  Using your IOC container when this need arises leads to a nice clean implementation.  Lets take a look at how this is done using the ASP.NET Core IOC Container.

Imagine we have the following IValidator interface.  We plan on having several classes that will implement this interface in order to validate some user input.  Our goal is to make managing these implementations simple and adding new ones as convenient as possible.

public interface IValidator
{
ValidationResult Validate(string input);
}

We can now wire our validators up like we would with any other service.  Note lines 13-15 below.

public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddTransient<IValidator, RequiredFieldValidator>();
services.AddTransient<IValidator, DateValidator>();
services.AddTransient<IValidator, NumericValidator>();
services.AddMvc();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseMvc();
}
}

With everything registered, we can now use the magic of dependency injection to provide us with an IEnumerable containing each of our validators.  This allows us to easily loop through each implementation.

public class InputProcessor
{
private readonly IEnumerable<IValidator> _validators;
public InputProcessor(IEnumerable<IValidator> validators)
{
_validators = validators;
}
public void Process(string input)
{
foreach (var validator in _validators)
{
var result = validator.Validate(input);
if (result.IsValid == false)
{
// Removed for brevity
}
}
// Removed for brevity
}
}

The best part is going forward adding (or removing) a validator is as simple as altering which implementations of IValidator are registered during startup.