Bercovici Adrian
Bercovici Adrian

Reputation: 9360

How to inject specific interface implementation using DI in ASP NET Core

I have the following problem. I have an interface that is implemented by 2 classes. One of these classes does the real work while the other uses the first one mentioned. How can I tell the framework to use a specific implementation of an interface when instantiating a type of object? I want the controller to get the facade implementation and not the real one:

public interface IDependency
{
   void Method();
}

public class Real : IDependency
{
   public void Method()
   {
   }
}

public class Facade : IDependency
{
   private IDependency dependency;
   Facade(IDependency dependency)  //I want a Real here
   {
     this.dependency=dependency;
   }
   public void Method()=>dependency.Method();
}


public MyController : Controller
{
   private IDependency dependency;
   MyController(IDependency dependency)   //I want the `Facade` here not the `Real`
   {
      this.dependency=dependency;
   }
   
   [HttpGet]
   [Route("[some route]")]
   public async Task CallMethod()
   {
      await this.dependency.Method();
   }

}

As you can see in the above example, I need a Real type of IDependency injected inside my Facade one, while I need a Facade type of IDependency injected in my MyController. How could that be done?

Upvotes: 2

Views: 4070

Answers (2)

Sanity Challenged
Sanity Challenged

Reputation: 495

Register your dependency as follows:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers();
    services.AddTransient<IDependency>(_ => new Facade(new Real()));
}

If you have other controllers that need a different implementation of IDependency, you'll want to register your controllers as services, allowing the registrations to be overwritten. For example, if you want most controllers to resolve with IDependency as Real, but only MyController to resolve IDependency as Facade, you could do this:

    public void ConfigureServices(IServiceCollection services)
    {
        // Adds controllers as services, allowing their registrations to be overwritten.
        services.AddMvc().AddControllersAsServices();  

        //services.AddControllers();  REMOVE THIS

        // Makes Real the default implementation of IDependency
        services.AddTransient<IDependency, Real>();               

        // Overwrite the default registration of MyController to instantiate using Facade.
        services.AddTransient<MyController>(sp => 
            new MyController(new Facade(sp.GetService<IDependency>())));
    }

Upvotes: 2

Chris Pratt
Chris Pratt

Reputation: 239290

Microsoft.Extensions.DependencyInjection doesn't have any means to do this. All you can do is inject all implementations, i.e. via List<IDependency>. Then, you can implement whatever manual logic you'd like to pick and choose from the available options there.

If you have any control over these classes, it would be better to simply implement a different interface, to distinguish the two. For example, you could create an IFacadeDependency interface that inherits from IDependency, and then have your Facade class implement that instead. Then, you can inject IFacadeDependency and get exactly what you want.

Upvotes: 1

Related Questions