简体   繁体   中英

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?

Microsoft.Extensions.DependencyInjection doesn't have any means to do this. All you can do is inject all implementations, ie 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.

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>())));
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM