same action filter on different action

2.1k views Asked by At

I'm implementing a custom authorize filter that inherits from AuthorizeAttribute. After my research I found out action filters are cached so they are instantiated only once.

Here is my question. If I implement and use a custom action filter like below, it shouldn't work correctly because it would be instantiated once and never call constructor again. But when I tested, it worked well so I'm thinking there is something I don't know.

Can anyone explain this(action filter life cycle?) clearly?

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

There are 2 answers

2
Matthew Verstraete On

This site has a really good overview of the page lifecycle in MVC

http://blogs.msdn.com/b/varunm/archive/2013/10/03/understanding-of-mvc-page-life-cycle.aspx

The reason your testing showed the filter running all the time is because when ever a route is called from the URL MVC matches it to a controller then an action in that controller. One the action is found MVC sees there is an action filter on it and will execute the action filter first. If two actions are called at the same time (from two different web users) in the same controller two unique instances of the controller is called up so one instance does not know that the other instance has ran the filter.

0
Greg On

Don't do it.

In my own experience, using private variables on the Action is not reliable, even if it sometimes appears to work, you'll likely end up with something non-determinant.

See, your code might work fine with 1 request, but not work at all when multiple request are handled simultaneously.

This user's problem is claiming the exact opposite experience as you: How to use ActionFilterAttribute to log running times?

My only explanation is if the Action Invoker instantiates the action filter, and that either: it doesn't keep it around very long, or that it create a pool of instances (or both).

I had a prototype that kept a context as a private action property, and it would occasionally (not every time) throw EF errors that were related to concurrent usage ( which was an issue for EF.)

This tells me that my action was being used more than once and at the same time.

I would recommend that one focus their actions as working with the filter context. The filter context contains everything that is going on right now, for this request. In MVC you can utilize the filterContext.HttpContext.Items to store items that are being utilized for this particular request. ( See Accessing Action Filter's data in Controller Action )

Lastly, it could also turn out that different version of the MVC framework optimize the lifecycle of action filters differently.

A couple useful links on the topic:

Some Details on the general MVC lifecycle http://blog.christopheargento.net/2012/06/11/detailed-life-cycle-of-an-asp-net-mvc-request/

In talking about how to create Dynamic Action filters (programmatically inserted and changed on the fly), Dino Esposito looks into some underworking of what's going on https://msdn.microsoft.com/en-us/magazine/gg309182.aspx

Custom Action Filters, and Filter Order when multiple present http://www.asp.net/mvc/overview/older-versions/hands-on-labs/aspnet-mvc-4-custom-action-filters