In the previous part of the series, we looked at how MVC finds which action to invoke based on the name from the route data. Today, we are going to be looking at how ActionFilters are discovered and how they are applied as it’s the next part in the process of Invoking an action.
Getting the Filters
The ControllerActionInvoker contains a method GetFilters that will retrieve all the Action Filters.
It uses all the registered IFilterProviders with the dependency resolver.
Extension notification : You are able to provide your own implementation for the IFilterProvider as the dependency resolver is used to inject the provider. By default there are 3 providers that are registered. The GlobalFilterCollection which you might have noticed from the FilterConfig in the global.asax. The FilterAttributeFilterProvider and the ControllerInstanceFilterProvider
You can register your own FilterProvider by adding it to the FilterProviders.Providers collection
Once the filters are returned, you might notice that we have an unexpected guest. We get the HandleError action filter from the GlobalFilters and then we get the controller as the action filter.
The reason for this is the fact that System.Web.Mvc.Controller implements IActionFilter, which means that all your controllers are ActionFilters as well.
Invoking Authentication Filters
Once the filters are retrieved, the action filters are invoked by the ControllerActionInvoker.InvokeAuthenticationFilters method.
It will then loop through all of the authentication filters and call OnAuthenticationContext.
By default you will not have any authentication filters except for your Controller. The controller’s virtual OnAuthentication will get called with the AuthenticationContext passed in.
On the very first sign that the Result on the authentication context gets set, the method breaks out of it’s loop and returns the authentication context.
If the result on the authentication context has been set, an AuthenticationChallengeContext gets setup by supplying the result from the AuthenticationContext. It would then run the InvokeAuthenticationFiltersChallenge method.
If the AuthenticationContext’s Result is not null
Then the principal from the authentication context is pulled out and if that is not null, the principal would be set on Thread.CurrentPrincipal and current HttpContext.User.
Invoking Authorization Filters
Then a very similar pattern to the AuthenticationFilters is followed, where an AuthorizationContext gets setup. This context would then get passed to a method called InvokeAuthorizationFilters which would in turn call OnAuthorization on the authorization filters and at the first very first sign of a result, would break the loop and return. It would then setup an AuthorizationChallengeContext by giving the result of the AuthorizationContext to it and run InvokeAuthenticationFiltersChallenge. Like I mentioned, identical in structure to the Authentication.
We know that we can provider our own implementation of a IFilterProvider and register it by adding it to the FilterProviders providers collection.
2. We saw that our Controllers are also Action Filters and that they will get picked up by the ControllerInstanceFilterProvider as filters.
3. The very first set of Filters that are invoked are the Authentication filters and on the very first chance of a result when invoking OnAuthentication, the result would be returned and passed into another method whereby changes to the result can be made or used. If there is no result, the result of the AuthenticationContext gets passed into the InvokeActionResult.
4. The Principal is retrieved from the Authentication Context and if not null, gets set on the Thread as well as the current HttpContext.
5. The Authorization filters follow the exact same pattern as the Authentication filters
Next time we will dig into the Validation of the requestRead More