C# 简单注入器,我可以在运行时注入不同的 类
C# Simple Injector, Can I inject different classes at runtime
目前我有一个网站的所有用户都要经历的过程。 (进程涵盖多个控制器和视图)。
我请求对不同类型的客户使用整体相同的流程(但有变化)。我可以看到我有两个选项之一,而不是用 if thens
填充受影响的控制器。
1) 在控制器上创建变体(由通用抽象 class 支持的通用功能),并弄清楚如何根据客户类型调用特定控制器,或保持控制器结构简单,并传入包含不同功能的依赖项。
我倾向于第二个选项,但这意味着我需要能够告诉简单的注入器使用相同的接口注册不同的 classes,然后,取决于一个参数,它不会'直到客户登录才知道,实例化正确的 class.
即(我知道这段代码不会按原样工作)
//in Simple Injector Initialize
container.Register<ICustomerProcess, RetailCustomer>(Lifestyle.Scoped);
container.Register<ICustomerProcess, CommercialCustomer>(Lifestyle.Scoped);
然后,当加载和验证客户时,然后将其定向到需要 ICustomerProcess 的控制器,Simple Injector 将传入适当的 class、RetailCustomer 或 CommercialCustomer
我从 Simple Injector 文档中看不到这是如何实现的。那么这是否可能(如果是的话,有人可以解释一下我对 Simple Injector 的了解是有限的,现在我一直在兜圈子!
在我看来,Proxy pattern 是您问题的解决方案,因为:
- 您不希望消费者(控制器)知道任何关于多个实现的存在。
- 您不想引入额外的界面,例如
ICustomerProcessStrategy
、ICustomerProcessFactory
或类似的东西。
代理模式可以提供帮助,因为它允许创建相同抽象的实现 (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;
}
现在您所要做的就是注册您的 CustomerProcessProxy
和 ICustomerContext
实现,然后您就完成了。
container.Register<ICustomerProcess, CustomerProcessProxy>();
container.Register<ICustomerContext, AspNetCustomerContext>();
显然你必须实现一个 ICustomerContext
并且如何实现取决于你如何检索有关客户的信息,但我可以想象 ASP.NET 的实现使用 Session 来存储用户是否是零售客户。这样的实现可能如下所示:
public class AspNetCustomerContext : ICustomerContext
{
public bool IsRetailCustomer => HttpContext.Current.Session["IsRetail"] != null;
}
这就是您所需要的。现在,当控制器在注入的 ICustomerProcess
上调用 DoSomething
时,它最终会调用 CustomerProcessProxy
,这会将调用分派给 RetailCustomer
或 CommercialCustomer
。
目前我有一个网站的所有用户都要经历的过程。 (进程涵盖多个控制器和视图)。
我请求对不同类型的客户使用整体相同的流程(但有变化)。我可以看到我有两个选项之一,而不是用 if thens
填充受影响的控制器。
1) 在控制器上创建变体(由通用抽象 class 支持的通用功能),并弄清楚如何根据客户类型调用特定控制器,或保持控制器结构简单,并传入包含不同功能的依赖项。
我倾向于第二个选项,但这意味着我需要能够告诉简单的注入器使用相同的接口注册不同的 classes,然后,取决于一个参数,它不会'直到客户登录才知道,实例化正确的 class.
即(我知道这段代码不会按原样工作)
//in Simple Injector Initialize
container.Register<ICustomerProcess, RetailCustomer>(Lifestyle.Scoped);
container.Register<ICustomerProcess, CommercialCustomer>(Lifestyle.Scoped);
然后,当加载和验证客户时,然后将其定向到需要 ICustomerProcess 的控制器,Simple Injector 将传入适当的 class、RetailCustomer 或 CommercialCustomer
我从 Simple Injector 文档中看不到这是如何实现的。那么这是否可能(如果是的话,有人可以解释一下我对 Simple Injector 的了解是有限的,现在我一直在兜圈子!
在我看来,Proxy pattern 是您问题的解决方案,因为:
- 您不希望消费者(控制器)知道任何关于多个实现的存在。
- 您不想引入额外的界面,例如
ICustomerProcessStrategy
、ICustomerProcessFactory
或类似的东西。
代理模式可以提供帮助,因为它允许创建相同抽象的实现 (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;
}
现在您所要做的就是注册您的 CustomerProcessProxy
和 ICustomerContext
实现,然后您就完成了。
container.Register<ICustomerProcess, CustomerProcessProxy>();
container.Register<ICustomerContext, AspNetCustomerContext>();
显然你必须实现一个 ICustomerContext
并且如何实现取决于你如何检索有关客户的信息,但我可以想象 ASP.NET 的实现使用 Session 来存储用户是否是零售客户。这样的实现可能如下所示:
public class AspNetCustomerContext : ICustomerContext
{
public bool IsRetailCustomer => HttpContext.Current.Session["IsRetail"] != null;
}
这就是您所需要的。现在,当控制器在注入的 ICustomerProcess
上调用 DoSomething
时,它最终会调用 CustomerProcessProxy
,这会将调用分派给 RetailCustomer
或 CommercialCustomer
。