Один и тот же фильтр действий для разных действий
Я реализую пользовательский фильтр авторизации, который наследуется от AuthorizeAttribute. После моего исследования я обнаружил, что фильтры действий кэшируются, поэтому они создаются только один раз.
Вот мой вопрос Если я реализую и использую фильтр пользовательских действий, как показано ниже, он не должен работать правильно, потому что он будет создан один раз и никогда больше не вызовет конструктор. Но когда я тестировал, это работало хорошо, так что я думаю, что есть кое-что, чего я не знаю.
Кто-нибудь может объяснить это (жизненный цикл фильтра действий?) Ясно?
public class CustomAuthorizeAttribute : AuthorizeAttribute
{
private readonly string value = string.Empty;
public CustomAuthorizeAttribute(string value)
{
this.value = value;
}
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
// Do something with this.value
}
}
public class HomeController : Controller
{
[CustomAuthorize("ACCESS_INDEX")]
public ActionResult Index()
{
}
[CustomAuthorize("ACCESS_LOGIN")]
public ActionResult Login()
{
}
}
2 ответа
Не делай этого.
По моему опыту, использование частных переменных в действии ненадежно, даже если иногда кажется, что оно работает, вы, скорее всего, в конечном итоге получите что-то недетерминированное.
Видите, ваш код может нормально работать с 1 запросом, но не работать вообще, когда несколько запросов обрабатываются одновременно.
Проблема этого пользователя требует совершенно противоположного опыта: как использовать ActionFilterAttribute для регистрации времени выполнения?
Мое единственное объяснение состоит в том, что Action Invoker создает экземпляр фильтра действий, и это либо: он не держит его слишком долго, либо что он создает пул экземпляров (или оба).
У меня был прототип, который содержал контекст как свойство частного действия, и он иногда (не каждый раз) генерировал ошибки EF, связанные с одновременным использованием (что было проблемой для EF).
Это говорит мне о том, что мое действие использовалось более одного раза и одновременно.
Я бы рекомендовал сосредоточить свои действия на работе с контекстом фильтра. Контекст фильтра содержит все, что происходит сейчас, для этого запроса. В MVC вы можете использовать filterContext.HttpContext.Items для хранения элементов, которые используются для этого конкретного запроса. (См. Доступ к данным фильтра действий в действии контроллера)
Наконец, может также оказаться, что разные версии инфраструктуры MVC по-разному оптимизируют жизненный цикл фильтров действий.
Пара полезных ссылок по теме:
Некоторые подробности об общем жизненном цикле MVC http://blog.christopheargento.net/2012/06/11/detailed-life-cycle-of-an-asp-net-mvc-request/
Говоря о том, как создавать фильтры динамического действия (программно вставляются и меняются на лету), Дино Эспозито рассматривает некоторые проблемы, связанные с работой https://msdn.microsoft.com/en-us/magazine/gg309182.aspx
Фильтры настраиваемых действий и порядок фильтров при множественном представлении http://www.asp.net/mvc/overview/older-versions/hands-on-labs/aspnet-mvc-4-custom-action-filters
Этот сайт имеет действительно хороший обзор жизненного цикла страницы в MVC
http://blogs.msdn.com/b/varunm/archive/2013/10/03/understanding-of-mvc-page-life-cycle.aspx
Причина, по которой ваше тестирование показало, что фильтр работает постоянно, заключается в том, что когда когда-либо вызывается маршрут из URL, MVC сопоставляет его с контроллером, то действие в этом контроллере. Когда действие найдено, MVC видит, что на нем есть фильтр действий, и сначала выполнит фильтр действий. Если два действия вызываются одновременно (от двух разных веб-пользователей) в одном контроллере, то вызываются два уникальных экземпляра контроллера, поэтому один экземпляр не знает, что другой экземпляр запустил фильтр.