C#Simple Injector,我可以在运行时注入不同的类

时间:2018-03-07 12:30:53

标签: c# model-view-controller simple-injector

目前,我有一个网站的所有用户都要经历的流程。 (流程涵盖多个控制器和视图)。

我有一个请求,要求为一个单独的客户使用相同的流程(但有变化)。而不是用if thens填充受影响的控制器,我可以看到我有两个选项之一。

1)在控制器上创建变体(由公共特征的公共抽象类支持),并弄清楚如何根据客户类型调用特定控制器,或保持控制器结构简单,并传递依赖关系包含会有所不同的功能。

我倾向于第二个选项,但这意味着我需要能够告诉简单的注入器使用相同的接口注册不同的类,然后,根据一个不知道的参数,直到客户登录,实例化正确的类。

ie(我知道这段代码不会按原样运行)

//in Simple Injector Initialize
 container.Register<ICustomerProcess, RetailCustomer>(Lifestyle.Scoped);
 container.Register<ICustomerProcess, CommercialCustomer>(Lifestyle.Scoped);

然后,当客户被加载和验证,然后被定向到需要ICustomerProcess的控制器时,Simple Injector将传入适当的类,RetailCustomer或CommercialCustomer

我从Simple Injector文档中可以看到的是如何实现这一目标。所以它甚至是可能的(如果是这样,有人可以解释我对Simple Injector的了解是多么有限,现在我继续围成一圈!

1 个答案:

答案 0 :(得分:1)

正如我所看到的,Proxy pattern是您问题的解决方案,因为:

  • 您不希望消费者(控制者)知道有关多个实施的存在的任何信息。
  • 您不想引入其他界面,例如ICustomerProcessStrategyICustomerProcessFactory或类似内容。

代理模式可以提供帮助,因为它允许创建相同抽象(ICustomerProcess)的实现,并在运行时决定 它应该转发调用的实现。

此类CustomerProcessProxy可能如下所示:

public class CustomerProcessProxy : ICustomerProcess
{
    private readonly ICustomerProcess retail;
    private readonly ICustomerProcess commercial;
    private readonly ICustomerContext context;

    // This constructor requires the two original implementations, and an ICustomerContext.
    // The ICustomerContext allows requesting information about 
    public CustomerProcessProxy(
        RetailCustomer retail, CommercialCustomer commercial, ICustomerContext context)
    {
        this.retail = retail;
        this.commercial = commercial;

        // Important note: in the constructor you should ONLY store incoming dependencies,
        // but never use them. That's why we won't call context.IsRetailCustomer here.
        this.context = context;
    }

    // ICustomerProcess methods
    // Each method will request the ICustomerProcess and forward the call to the
    // returned implementation.
    public object DoSomething(object input) => GetProcess().DoSomething(input);

    // Allows returning the correct ICustomerProcess based on runtime conditions.
    private ICustomerProcess GetProcess()
        => this.context.IsRetailCustomer ? this.retail : this.commercial;
}

现在您所要做的就是注册CustomerProcessProxyICustomerContext实施,然后您就完成了。

container.Register<ICustomerProcess, CustomerProcessProxy>();
container.Register<ICustomerContext, AspNetCustomerContext>();

显然你必须实现一个ICustomerContext,如何做到这一点取决于你如何检索有关客户的信息,但我可以设想一个ASP.NET的实现,它使用Session来存储是否存在用户是零售客户。这种实现可能如下所示:

public class AspNetCustomerContext : ICustomerContext
{
    public bool IsRetailCustomer => HttpContext.Current.Session["IsRetail"] != null;
}

这就是你所需要的一切。现在,当控制器在注入的DoSomething上调用ICustomerProcess时,它最终会调用CustomerProcessProxy,这会将调用分派给RetailCustomerCommercialCustomer