Один и тот же фильтр действий для разных действий

Я реализую пользовательский фильтр авторизации, который наследуется от 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 видит, что на нем есть фильтр действий, и сначала выполнит фильтр действий. Если два действия вызываются одновременно (от двух разных веб-пользователей) в одном контроллере, то вызываются два уникальных экземпляра контроллера, поэтому один экземпляр не знает, что другой экземпляр запустил фильтр.

Другие вопросы по тегам