【问题标题】:How to inject specific interface implementation using DI in ASP NET Core如何在 ASP NET Core 中使用 DI 注入特定的接口实现
【发布时间】:2020-08-22 23:45:40
【问题描述】:

我有以下问题。我有一个由 2 个类实现的接口。其中一个类执行实际工作,而另一个使用提到的第一个类。 在实例化一种类型的对象时,如何告诉框架使用接口的特定实现? 我希望控制器获得外观实现,而不是真正的实现:

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

}

正如您在上面的示例中看到的,我需要在我的Facade 中注入Real 类型的IDependency,而我需要在我的MyController 中注入Facade 类型的IDependency。 怎么可能呢?

【问题讨论】:

    标签: c# asp.net-core dependency-injection facade


    【解决方案1】:

    Microsoft.Extensions.DependencyInjection 没有任何方法可以做到这一点。你所能做的就是注入 all 实现,即通过List<IDependency>。然后,您可以从那里的可用选项中实现您想要挑选的任何手动逻辑。

    如果您对这些类有任何控制权,最好简单地实现一个不同的接口,以区分两者。例如,您可以创建一个继承自IDependencyIFacadeDependency 接口,然后让您的Facade 类实现它。然后,你可以注入IFacadeDependency,得到你想要的。

    【讨论】:

    • 我可以注入 serviceCollection 并使用 IServiceProvider 吗?
    • 可以,但它不会给你任何东西。您仍然只能拉出所有实现的列表。您只需手动完成,而不是让框架为您完成。
    • 所以要么我手动完成,要么我只是创建另一个派生接口。我想我更喜欢后者。
    • 你好,我也有同样的问题,如果他创建了两个接口,接口是空的吗?我正在尝试做同样的事情,但是有空的接口不是一个坏习惯吗?你知道如何解决问题吗? @ChrisPratt
    【解决方案2】:

    如下注册你的依赖:

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

    如果您有其他控制器需要不同的 IDependency 实现,您需要将控制器注册为服务,从而允许覆盖注册。例如,如果您希望大多数控制器将 IDependency 解析为 Real,但只有 MyController 将 IDependency 解析为 Facade,您可以这样做:

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

    【讨论】:

    • 但是我如何告诉框架用Facade 构建Controller 而另一个用Real。有没有办法为使用@ 的类创建构造配方987654326@ 在Startup 类中?
    • 我不确定您所说的“另一个”是什么意思。你是说你有其他想要接收 Real 依赖的控制器,而只有这个你想要接收 Facade 依赖的控制器?
    • 阅读我的原帖,代码sn-p后面的文字。
    • 是的,我的第一个代码 sn-p 涵盖了这一点。 Facade 从向 IServicesCollection 注册的工厂方法中获取它的 Real。
    猜你喜欢
    • 2017-04-28
    • 1970-01-01
    • 2021-12-08
    • 2016-03-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-28
    • 1970-01-01
    • 2023-03-17
    相关资源
    最近更新 更多