2

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?

2 Answers 2

2

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>())));
    }
Sign up to request clarification or add additional context in comments.

4 Comments

But how do i tell the framework to build the Controller with Facade and the other one with Real.Is there a way to create the construction recipe for the classes that use the IDependency in the Startup class ?
I'm not sure what you mean by "the other one." Are you saying you have other controllers that you want to receive the Real dependency, and just this one controller that you'd like to receive the Facade dependency?
Read my original post , the text after the code snippet.
Yeah, that was covered by my first code snippet. The Facade gets it's Real from the factory method registered with the IServicesCollection.
1

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.

4 Comments

I could inject the serviceCollection and use the IServiceProvider ?
You can, but it doesn't buy you anything. You still can only pull out a list of all implementations. You'd just be doing it manually instead of having the framework do it for you.
So its either i do it manually or i just create another derived interface.I think i prefer the latter.
Hi, I am having the same problem, if he created two interfaces, would be the interfaces empty? I am trying to do the same, but having empty interfaceces is not a bad pratice? Do you know how to solve the problem? @ChrisPratt

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.