Как разрешить внедрение зависимостей в атрибутах фильтра MVC - PullRequest
13 голосов
/ 12 ноября 2010

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

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

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

т.е. Атрибут AuthorizationAttribute зависит от IUserRepository ... как должно разрешить это отношение?

Ответы [ 4 ]

17 голосов
/ 13 ноября 2010

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.)

2 голосов
/ 12 ноября 2010

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

public class UserAuthorizeAttribute : AuthorizeAttribute
{            
    public IUserRepository CurrentUserService
    {
        get
        {
            var cpa = (IContainerProviderAccessor)HttpContext.Current.ApplicationInstance;
            var cp = cpa.ContainerProvider;
            return cp.RequestLifetime.Resolve<IUserRepository>();
        }
    }
}
     ...
2 голосов
/ 12 ноября 2010

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

Если вы используетеMVC 3, тогда вы можете использовать Расположение службы MVC

0 голосов
/ 12 ноября 2010

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

Даже в Asp.Net Mvc3 :

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

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

Вот как сделать это вручную.

Я лично использую MvcExtensions. Я в порядке с их регистрацией другим способом . Вот использование .

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...