我想对我的MVC控制器应用一些横切关注点.目前,这是通过抽象基类实现的,但是当我们重构更多的代码库以利用依赖注入时,我想知道这是否是Simple Injector可以帮助我通过它的装饰或拦截设施.
所以我试图创建一个非常基本的装饰器:
public class ControllerDecorator : IController { private readonly IController _controller; public ControllerDecorator(IController controller) { _controller = controller; } public void Execute(RequestContext requestContext) { // Do something of a cross-cutting nature here... _controller.Execute(requestContext); } }
在我的作文根:container.RegisterDecorator< IController,ControllerDecorator>()
但是,我的装饰器的Execute方法中的代码似乎永远不会被调用.是因为MVC框架直接解析我的控制器类而不是通过IController吗?在那种情况下,我该怎么办?我在这里想念的是什么?
解决方法
在默认配置中,您无法将装饰器应用于控制器.原因是MVC的DefaultControllerFactory按其具体类型请求控制器.因为它请求具体类型,Simple Injector无法应用装饰器;它必须假设调用者需要这种具体类型,因此必须返回这种确切的类型(或子类型).
要解决此问题,您必须使用自定义的DefaultControllerFactory替换默认的DefaultControllerFactory:
public class SimpleInjectorControllerFactory : DefaultControllerFactory { public IDictionary<Type,InstanceProducer> Producers { get; set; } protected override IController GetControllerInstance(RequestContext rc,Type type) { return (IController)this.Producers[type].GetInstance(); } }
接下来,在您的引导程序中,您必须使用以下内容替换对RegisterMvcControllers的调用:
var controllerTypes = SimpleInjectorMvcExtensions.GetControllerTypesToRegister( container,Assembly.GetExecutingAssembly()); var controllerProducers = controllerTypes .ToDictionary(type => type,type => CreateControllerProducer(container,type)); // Verify after creating the controller producers. container.Verify(); ControllerBuilder.Current.SetControllerFactory( new SimpleInjectorControllerFactory { Producers = controllerProducers });
CreateControllerProducer方法如下所示:
private static InstanceProducer CreateControllerProducer(Container c,Type type) { var producer = Lifestyle.Transient.CreateProducer(typeof(IController),type,c); producer.Registration.SuppressDiagnosticWarning( DiagnosticType.DisposableTransientComponent,"MVC disposes the controller when the web request ends."); return producer; }
关键部分是对CreateProducer的调用提供了typeof(IController);这允许Simple Injector为IController应用装饰器.
就是这个;现在您可以为IController注册装饰器.
但是有一个警告:使用Web API和新的ASP.NET核心,不可能将装饰器应用于控制器.两个框架都期望具体类型;如果你包装真正的控制器它们会破裂.这些框架装饰控制器的首选方法是通过OWIN管道.所以这个答案仅适用于MVC 3,4和5.