2010-11-12 2 views
13

У меня есть собственный класс атрибутов, полученный из AuthorizationAttribute, который выполняет пользовательскую безопасность действий контроллера. Метод OnAuthorizationCore зависит от различных других компонентов (например, DAL), чтобы судить, может ли пользователь вызывать действие.Как разрешить впрыскивание зависимостей в атрибутах фильтра MVC

Я использую Autofac для инъекций зависимости. ExtensibleActionInvoker утверждает, что может выполнять инъекцию свойств в фильтрах действий. Настройка свойств атрибута во время выполнения (что кажется плохой идеей) будет работать в простом модульном тесте, но на занятом многопоточном веб-сервере он обязательно пойдет не так, и поэтому эта идея кажется анти-шаблоном. Следовательно, этот вопрос:

Если мой атрибут AuthorizationAttribute зависит от других компонентов, чтобы работать правильно, что это правильный шаблон [архитектура], чтобы достичь этого?

i.e АвторизацияAttribute зависит от IUserRepository ... как должно решить эту взаимосвязь?

ответ

17

ExtensibleActionInvoker утверждает, что способен выполнять впрыскивание свойств в фильтрах действий.

Исправить - но не путайте фильтры действий с атрибутами, которые могут их не реализовывать. Самый чистый способ приблизиться к этому в ASP.NET MVC состоит в разделении обязанностей, хотя структура MVC позволяет объединить их.

Например, используйте пару классов - класс атрибута, который содержит только данные:

// Just a regular old attribute with data values 
class SomeAttribute : Attribute { ... } 

и фильтр, который зависит впрыскивается:

// Gets dependencies injected 
class SomeFilter : IActionFilter { ... } 

SomeFilter просто использует типичный подход получения атрибут SomeAttribute от контроллера или метод действия через GetCustomAttributes() для выполнения любой работы.

Вы можете использовать ExtensibleActionInvoker телеграфировать фильтр:

builder.RegisterControllers(...).InjectActionInvoker(); 
builder.RegisterType<ExtensibleActionInvoker>().As<IActionInvoker>(); 
builder.RegisterType<SomeFilter>().As<IActionFilter>(); 

Это может быть немного больше кода, чем можно было бы написать с помощью атрибута как-фильтра подход, но качество кода будет быть лучше в долгосрочной перспективе (например, избегая ограничений атрибутов и неловкости решений Service Locator.)

+0

Спасибо, Ник - и для тщательного ответа, и для блестящей рамки! – Mark

2

Нет прямого способа сделать это до MVC2. Здесь есть интересная техника: http://www.mattlong.com.au/?p=154. Я бы предложил использовать Common Service Locator для абстракции над этим и найти ваш контейнер DI.

Если вы используете MVC 3, то вы можете использовать MVC Service Location

+2

Какой смысл использовать CSL, если это локатор сервисов? CSL обычно используется, когда вы знаете, что ваш код будет повторно использован кем-то другим, кто может предпочесть другой контейнер. Не думайте, что есть еще одна причина для его абстрагирования. –

+0

Это было доведено до смерти - это всегда сводится к идеологической точке зрения, –

2

я, казалось бы, самый простой способ для достижения этой цели является стиснуть зубы и принять зависимость от самого autofac. Хотя зависимость от IoC сама по себе является анти-шаблоном, она несколько более привлекательна. Вы можете реализовать свойство следующим образом:

public class UserAuthorizeAttribute : AuthorizeAttribute 
{    
    public IUserRepository CurrentUserService 
    { 
     get 
     { 
      var cpa = (IContainerProviderAccessor)HttpContext.Current.ApplicationInstance; 
      var cp = cpa.ContainerProvider; 
      return cp.RequestLifetime.Resolve<IUserRepository>(); 
     } 
    } 
} 
    ... 
0

Встраивание конструктора, по-видимому, невозможно без изменения способа регистрации фильтра.

Даже in Asp.Net Mvc3:

Одно место, где инъекции зависимостей были трудны в прошлом, внутри фильтра атрибутов сам. Поскольку среда выполнения .NET Framework фактически отвечает за создание этих экземпляров атрибутов, мы не можем использовать традиционную стратегию инъекций зависимостей.

Итак - следующая лучшая вещь - инъекция свойств (Mvc3 обеспечивает некоторую поддержку для этого из коробки).

Для этого это how to.

Я лично использую MvcExtensions. Я в порядке, зарегистрировав их в different way. Вот usage.

Еще одна вещь, которую вы можете изучить, - это проект MvcTurbine. В отличие от проекта MvcExtensions, который является более общим - MvcTurbine предназначен в первую очередь для поддержки поддержки инъекций.

Смежные вопросы