我想在Simple Injector中尝试一下Hybrid Lifestyle . 我希望有一个可选的显式定义的异步范围,如果没有定义异步范围,则回退到Web请求范围 .
我打算在ASP.NET MVC控制器中使用它,通常我想解决最外层Web请求范围的实例,但在某些情况下,我想在控制器的操作中显式创建一个异步范围并缩短范围内的实例的生活方式 .
要在控制器的操作中显式创建Async Scope,我必须这样做:
using (AsyncScopedLifestyle.BeginScope(container))
{
// ...
}
但是,我的控制器中没有 container
引用,因为它全部设置为 DependencyResolver
(我使用的是ASP.NET MVC 5) .
我的问题是: What is the best way of accessing Simple Injector container inside ASP.NET MVC controller?
我应该将容器实例本身注册为服务并通过控制器中的构造函数注入来获取它吗?或者我是否在它周围创建了一些包装(例如 ISimpleInjectorContainerProvider
)并通过那里获取它?或者有什么办法让它通过 DependencyResolver
?
对不起,如果这个问题有点愚蠢,我的目标只是避免做一些可能产生负面影响的不良做法 .
1 回答
在控制器中访问容器的最佳方法是不这样做 .
应用程序中唯一应该访问DI容器或其抽象(例如服务定位器或
DependencyResolver
)的地方是Composition Root .但是,MVC控制器不是组合根的一部分,它们是表示层的一部分 . 取决于DI容器或与其相关的任何构造是一个坏主意 .
相反,通过使用 Abstractions ,依赖注入为我们提供了一种使用decorators来拦截方法调用的方法 .
这允许您在组合根中定义装饰器,并在将调用转发到包装服务之前让它控制范围 .
比如你的
OrderController
取决于IOrderService
如下:如果
CancelOrder
操作需要在其自己的隔离范围内运行,而不是让OrderController
处理它,我们应该将此职责移至另一个类 . 由于将其移入OrderService
实现也是一个坏主意,我们可以将此行为放在装饰器中:通过使用装饰器,您可以保持控制器和实际业务逻辑不变,并允许您仅通过更改组合根来添加此行为 .
您可以在Simple Injector中注册,如下所示:
当Simple Injector看到
SimpleInjector.Container
类型的构造函数参数时,它会自动在构造函数中注入自身 . 您没有为此进行任何特殊注册 . 但是,如上所述,只有属于Composition Root的类才应依赖于Container
,因此不要在整个代码库中使用Container
. 这将导致代码难以维护,难以测试 .Simple Injector认为
Func<IOrderService>
是一种特殊的依赖 . 通常,Simple Injector不会自动注入Func<T>
依赖项,但装饰器是此规则的例外 . Simple Injector确保注入的Func<T>
可以解析'real'实现 .