Ninject to Simple Injector:注册过滤器

时间:2013-07-17 10:38:45

标签: asp.net-mvc-3 dependency-injection inversion-of-control ninject simple-injector

由于我的MVC 3应用程序具有更好的性能,我正在从Ninject迁移到Simple Injector。我可以很好地注册存储库和服务。但是有一个使用

在Ninject中注册的过滤器

kernel.BindFilter<UserActivityAttribute>(FilterScope.Controller, 0).WhenControllerHas<UserActivityFilter>();

不会转换为Simple Injector。基本上我们使用该过滤器来记录用户活动,并且UserActivityFilter被指定为需要记录的控制器的属性。

1 个答案:

答案 0 :(得分:0)

Simple Injector中没有BindFilter个等效项。由于我不熟悉Ninject功能,我不能告诉你如何模拟它(虽然它当然可能)。

您可以做的当然是使用过滤器属性标记您的控制器,但这可能是您首先想要阻止的(如果我理解Ninject的BindFilter功能的作用)。

就个人而言,我喜欢使用装饰器来应用横切关注点(例如日志记录)。您可以在服务层边界应用装饰器(例如this article显示)或在控制器级应用装饰器。

在控制器周围应用装饰器需要更多的工作。您需要更改为此注册控制器的方式。这可能是您目前的注册:

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      
    }
}

我希望这是有道理的。