简体   繁体   English

如何在没有条件/上下文DI的情况下将不同的实现注入相同的接口?

[英]How to inject different implementations to same interface without conditional/context DI?

I have the following problem and I currently have a solution using conditional dependency injection. 我有以下问题,目前有使用条件依赖注入的解决方案。 I have read that this is a bad idea, such as here in the SimpleInjector docs. 我已阅读,这是一个糟糕的主意,比如这里的SimpleInjector文档。 I have read a large number of posts now and have seen various things suggesting using Strategy, Factory patterns, etc. What I am really looking for is some specifics - ie an example of some code - about how to solve without conditional injection. 我现在已经阅读了大量文章,并且看到了各种建议使用策略,工厂模式等的内容。我真正要寻找的是一些有关如何进行无条件注入的解决方案的细节(即一些代码示例)。 I need more that "use a factory". 我需要更多“使用工厂”。 Here's a simplified version of my code. 这是我的代码的简化版本。 This is in an MVC web app, thus the controllers. 这在MVC Web应用程序中,因此在控制器中。

public abstract class QAControllerBase : Controller
{
    protected readonly QABusinessLayer _blQA;
    public QAControllerBase(QABusinessLayer bl) 
    {
        _blQA = bl;
    }

    [HttpGet]
    public ActionResult PPR(string accession, string site)
    {
        var m = _blQA.popPPRViewModel(accession);

        return View(m);
    }
}

public class QASouthController : QAControllerBase
{

    public QASouthController([QASouthBinding] QABusinessLayer bl) : base(bl)
    {

    }

    // some actions that are specific to South
}


public class QANorthController : QAControllerBase
{

    public QANorthController([QANorthBinding] QABusinessLayer bl) : base(bl)
    {

    }

    // some actions that are specific to North
}

public abstract class QABusinessLayer
{
    protected readonly IFullBaseRepo _repo;
    public QABusinessLayer(IFullBaseRepo repo)
    {
        _repo = repo;
    }

    public abstract PPRViewModel popPPRViewModel(string accession);

    protected PPRViewModel DoSomeCommonStuff(PPRViewModel model)
    {
        ...
        return model;
    }

}

public class SouthBusinessLayer: QABusinessLayer
{

    public SouthBusinessLayer([QASouthBinding] IFullBaseRepo repo) : base(repo)
    {

    }

    public override PPRViewModel popPPRViewModel(string accession)
    {
        var m = new PPRViewModel();
        // do some stuff that is specific to South
        DoSomeCommonStuff(m);

        return m;
    }
}

public class NorthBusinessLayer : QABusinessLayer
{


    public NorthBusinessLayer([QANorthBinding] IFullBaseRepo repo) : base(repo)
    {

    }
    public override PPRViewModel popPPRViewModel(string accession)
    {
        var m = new PPRViewModel();
        // do some stuff that is specific to North
        DoSomeCommonStuff(m);

        return m;
    }
}

and here is the Ninject binding code that is pertinent: 这是相关的Ninject绑定代码:

            kernel.Bind<QABusinessLayer>()
            .To<SouthBusinessLayer>()
            .WhenTargetHas<QASouthBinding>()
            .InRequestScope();

        kernel.Bind<QABusinessLayer>()
            .To<NorthBusinessLayer>()
            .WhenTargetHas<QANorthBinding>()
            .InRequestScope();

The QASouthBinding and QANorthBinding are just simple attributes. QASouthBinding和QANorthBinding只是简单的属性。 I am not asking for Ninject specific example. 我不是在问Ninject的具体例子。 Any code sample as to how this might be handled without using conditional or context based injection as I am now. 无需像现在这样使用条件注入或基于上下文注入的任何有关如何处理的代码示例。

Make your QABusinessLayer class abstract. 使您的QABusinessLayer类抽象。

Change your startup configuration to: 将启动配置更改为:

kernel
    .Bind<SouthBusinessLayer>()
    .To<SouthBusinessLayer>()
    .InRequestScope();

kernel
    .Bind<NorthBusinessLayer>()
    .To<NorthBusinessLayer>()
    .InRequestScope();

Change your controller constructors to accept a concrete business layer type: 更改控制器构造函数以接受具体的业务层类型:

public class QANorthController : QAControllerBase
{
    public QANorthController(NorthBusinessLayer businessLayer) : base(businessLayer)
    {
    }
}

public class QASouthController : QAControllerBase
{
    public QASouthController(SouthBusinessLayer businessLayer) : base(businessLayer)
    {
    }
}

Few things: 一些事情:

  1. If Ninject auto-binds concrete types to the same type, then you don't need to manually configure the dependencies during startup. 如果Ninject将具体类型自动绑定为相同类型,则在启动过程中无需手动配置依赖项。
  2. You may want to use an interface rather than just passing your concrete BusinessLayer type. 您可能要使用接口,而不只是传递具体的BusinessLayer类型。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 DI:不同控制器的相同接口的不同实现 - DI: Different implementations of the same interface for the different controllers IoC / DI:当存在同一接口的多个实现时,如何注入特定实例 - IoC/DI: How to inject specific instance when there are multiple implementations of same interface 在多个构造函数参数中注入具有相同接口的不同实现 - Inject different implementations that have same interface in multiple constructor parameters 在运行时将命令的不同实现注入命令 - Inject different implementations of an Interface to a command at runtime 将不同的实现注入相同的接口,然后在正确的项目/程序集中选择正确的实现 - Inject different implementations into same interface then pick up right implementation in right project / assembly 如何将一个接口的多个实现注入一个实现中 - How to Inject multiple Implementations of an Interface into one Implementation 一个接口与 DI 的多种实现 - Multiple implementations for one interface with DI 使用ninject绑定同一接口的不同实现 - Bind different implementations of same Interface using ninject 子类继承相同接口的不同实现 - Child classes inheriting different implementations of the same interface 如何在Asp.Net Core DI上注入具有不同生命周期的同一个类? - How can I inject same class with different Life Cycles on Asp.Net Core DI?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM