Simple Injector中没有BindFilter
等价物。由于我不熟悉 Ninject 功能,因此我无法告诉您如何模拟它(尽管当然可以)。
当然,您可以做的是用过滤器属性标记您的控制器,但这可能是您首先要防止的事情(如果我了解 Ninject 的BindFilter
功能的话)。
就个人而言,我喜欢使用装饰器来应用横切关注点(例如日志记录)。您可以在服务层边界应用装饰器(如本文所示)或在控制器级别应用装饰器。
在控制器周围应用装饰器需要更多的工作。您需要为此更改注册控制器的方式。这可能是您当前的注册:
container.RegisterMvcControllers(Assembly.GetExecutingAssembly());
为了能够应用装饰器,您必须按其基本类型(IController
在本例中)注册控制器。有多种方法可以做到这一点,但我喜欢这种方法:
// We get all controller types for the current assembly.
var controllerTypes = SimpleInjectorMvcExtensions
.GetControllerTypesToRegister(container,
Assembly.GetExecutingAssembly());
// Here we register a collection of controllers.
container.RegisterAll<IController>(controllerTypes);
// We register a custom IControllerActivator.
container.RegisterSingle<IControllerActivator>(() =>
new SimpleInjectorControllerActivator(
container.GetAllInstances<IController>(),
controllerTypes));
由于控制器是通过其IController
基本类型注册的,我们现在可以在控制器周围应用装饰器:
container.RegisterDecorator(typeof(IController),
typeof(UserActivityControllerDecorator), c =>
c.ImplementationType.GetCustomAttribute<UserActivityFilter>()
.Any());
我们现在将它们注册为集合,而不是将控制器映射到它们的具体类型(使用Register<HomeController>()
或 Ninject 的)。自定义现在可以从集合中获取特定项目:Bind<HomeController>().ToSelf()
IControllerActivator
// using System.Linq;
internal sealed class SimpleInjectorControllerActivator
: IControllerActivator
{
private readonly IEnumerable<IController> controllers;
private readonly Dictionary<Type, int> mapping;
public SimpleInjectorControllerActivator(
IEnumerable<IController> controllers,
Type[] controllerTypes)
{
this.controllers = controllers;
// Here we make a mapping from the controller type to
// the index in the controllers collection.
this.mapping = controllerTypes
.Select((type, index) => new { type, index })
.ToDictionary(i => i.type, i => i.index);
}
public IController Create(RequestContext requestContext,
Type controllerType)
{
int index = this.mapping[controllerType];
return controllers.ElementAt(index);
}
}
该Create
方法利用该Enumerable.ElementAt
方法通过其索引从集合中获取特定的(装饰的)控制器。Simple Injector 实现返回的集合IList<T>
,这允许ElementAt
使用IList<T>
索引器,该索引器允许此操作具有 O(1) 的性能特征。当控制器数量增加时,调用的性能ElementAt
不会降低。
有了这个,你可以编写你的装饰器如下:
class UserActivityControllerDecorator : IController
{
private readonly IController decoratee;
private readonly ILogger logger;
public UserActivityControllerDecorator(IController decoratee,
ILogger logger)
{
this.decoratee = decoratee;
this.logger = logger; }
public void Execute(RequestContext requestContext)
{
// do something before executing the controller
this.decoratee.Execute(requestContext);
// do something after executing the controller
}
}
我希望这是有道理的。