В 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>()
или Bind<HomeController>().ToSelf()
Ninject, мы теперь регистрируем их как коллекцию. Пользовательский 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
}
}
Я надеюсь это имеет смысл.
person
Steven
schedule
17.07.2013