Hola, tengo el siguiente problema. Tengo una interfaz implementada por 2 clases. Una de estas clases hace el trabajo real mientras que la otra usa la primera mencionada. ¿Cómo puedo decirle al framework que use una implementación específica de una interfaz al crear instancias de un tipo de objeto? Quiero que el controlador obtenga la implementación en fachadas y no la real:

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

}

Como puede ver en el ejemplo anterior, necesito un tipo Real de IDependency inyectado dentro de mi Facade, mientras que necesito un tipo Facade de IDependency inyectado en mi MyController. ¿Cómo podría hacerse eso?

0
Bercovici Adrian 7 may. 2020 a las 18:37

2 respuestas

La mejor respuesta

Microsoft.Extensions.DependencyInjection no tiene ningún medio para hacer esto. Todo lo que puede hacer es inyectar todas implementaciones, es decir, a través de List<IDependency>. Luego, puede implementar cualquier lógica manual que desee elegir y elegir entre las opciones disponibles allí.

Si tiene algún control sobre estas clases, sería mejor simplemente implementar una interfaz diferente, para distinguir las dos. Por ejemplo, podría crear una interfaz IFacadeDependency que herede de IDependency, y luego hacer que su clase Facade implemente eso en su lugar. Luego, puede inyectar IFacadeDependency y obtener exactamente lo que desea.

0
Chris Pratt 7 may. 2020 a las 15:43

Registre su dependencia de la siguiente manera:

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

Si tiene otros controladores que necesitan una implementación diferente de IDependency, querrá registrar sus controladores como servicios, permitiendo que se sobrescriban los registros. Por ejemplo, si desea que la mayoría de los controladores se resuelvan con IDependency como Real, pero solo MyController resuelva IDependency como Facade, puede hacer esto:

    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>())));
    }
1
Sanity Challenged 7 may. 2020 a las 16:31