1

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

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

这不会转化为简单的注射器。基本上,我们使用该过滤器来记录用户活动,并且将 UserActivityFilter 指定为需要记录的控制器的属性。

4

1 回答 1

0

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

我希望这是有道理的。

于 2013-07-17T11:53:58.593 回答