Pieter Germishuys

Trying to be a better software craftsman

Navigation Menu

ASP.NET MVC under the hood part 6

Posted by on May 08, 2013 3:23 PM in aspnet,mvc | 0 comments

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.

image

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.

The very first thing in this method is to actually create an AuthenticationContext with the ActionDescriptor passed in.

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.

image

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.

Let’s recap

1. We looked at how filters are retrieved from 3 separate providers. The GlobalFilterCollection the FilterAttributeFilterProvider and the ControllerInstanceFilterProvider

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 request

Read More

ASP.NET MVC under the hood part 5

Posted by on Apr 27, 2013 1:33 PM in aspnet,mvc | 0 comments

In the previous part of the series, we started digging into the internals of BeginExecuteCore which is the async part of ExecuteCore on the Controller. We had a look at how TempData was loaded and in this part we are going to start digging into the ActionInvoker

Extension notification : You are able to provide your own implementation of the IActionInvoker as the dependency resolver is used to inject the invoker. By default, the AsyncControllerActionInvoker is used

image

Getting ready to call the ActionInvoker

What happens after loading temp data is we get the action name from the route data and we grab a reference to an ActionInvoker on the controller.

Note : With most of the calls to methods in MVC, you will find that there are 1 of 2 paths that can be taken, an async and sync route. Let’s assume that we are going to be taking the asynchronous route.

Before calling InvokeAction on the action invoker. An instance of ExecuteCoreState is created that will hold onto the reference of the controller, the async invoker and the action name.

image

An internal helper class called the AsyncResultWrapper is used to facilitate async operation. This object is utilized to call the action invoker.

Finding the Action

When the BeginInvokeAction is called on the default Action Invoker, which is the AsyncControllerActioninvoker, we ensure that the controllerContext as well as the action name is not null or empty.

After the 2 checks, we retrieve a controller descriptor. This descriptor contains the type of the controller, a ReflectedAsyncControllerDescriptor as well as a state object, which is set to the controller type. This descriptor is retrieved from a descriptor cache.

The next part of the method attempts to find the action.

The FindAction on the ControllerActionInvoker gets called. This will in turn call the FindAction method on the ControllerDescriptor (ReflectedAsyncControllerDescriptor) which will in turn call a FindAction method on an AsyncActionMethodSelector

image

As you can see, the way the method lookup works is that we have a collection of AliasedMethods and NonAliasedMethods. The aliased methods are those methods that are decorated with the ActionNameSelectorAttribute

Once a list of methods are determined, we go through a similar set of logic as what we did with the controllers.

If there are no methods found, then return null, if there is 1 method found, an action descriptor (ReflectedActionDescriptor) is created and returned.

Let’s recap

1. The IActionInvoker interface is one that we can implement ourselves and provide via registering it with the dependency resolver.

2. The default action invoker, is the AsyncControllerActionInvoker

3. The Action Invoker is responsible for finding the actions on a controller, getting filters, invoking the action itself and a whole lot more. We will dig into it’s responsibilities more as the series goes on.

4. The Action Invoker uses the Controller Descriptor to facilitate in the discovery of the methods for the action requested.

5. The ReflectedAsyncControllerDescriptor internally uses the AsyncActionMethodSelector who’s real responsibility is to find the methods for the action and return the only correct as an action descriptor.

 

In the next part of the series we will dig a bit deeper into the Action Invoker. Hopefully we’ll get to the filters and how they are applied and so on.

Until next time! Happy MVCing

Read More

ASP.NET MVC under the hood part 4

Posted by on Apr 22, 2013 3:07 AM in aspnet,mvc | 0 comments

In the previous part of the series, we took a look at how the MvcHandler gets tasked with handling the request and how it uses a set of objects to create a controller.

Now that we have our controller, a series of calls happens, which I don’t want to get into. I might expand this particular post as time permits, but for now would like to get to the BeginExecuteCore method on the Controller that starts the magic of finding the action method that needs to be invoked.

image

But first is to PossiblyLoadTempData. What does this do and where does it load the TempData From?

 

Possibly Load Temp Data?

If the particular controller context is part of a child action, TempData would not be loaded. What does this mean?

If we want to have a menu, like in our Layout, when we hit Home/Index, the menu partial will be a child action and thus, when hitting the server for the menu action, the controller context would have the IsChildAction set to true.

How is IsChildAction set? The value is actually a check for the existence of a key named “ParentActionViewContext” in the Route Data tokens.

image

Let’s take a moment and see if we can cause TempData not to load, by setting this value ourselves.

The idea about TempData is to pass data from one request to the next. If we have the following scenario, you would see that when setting TempData values in one action method, that it would survive until the next request.

image

but the very next request, the value would not exist

image

Let’s go ahead and add the route data token called “ParentActionViewContext” and see what happens. It falls over in a spectacular way because the ParentActionViewContext is not a real ViewContext and if you did set it, it would probably not contain the TempData that you’d expect.

image

 

Where does it load TempData from though?

TempData is a dictionary of string and object.  When the PossiblyLoadTempData is called, the TempDataDictionary uses the ControllerContext as well as the ITempDataProvider to load the data.

 

Extension notification : You are able to provide your own implementation for the ITempDataProvider as the dependency resolver is used to inject the provider. By default the SessionStateTempDataProvider is used.

 

The data is stored and retrieved in session using the “__ControllerTempData” as the key. If the data is retrieved, it will get removed so that no other request can get the data.

image

Let’s recap

In this part of the series we had a look at how TempData gets loaded . It uses an implementation of the ITempDataProvider and if the dependency resolver cannot get an implementation, the SessionStateTempDataProvider is used.

We know that we can implement our own TempDataProvider through implementing the ITempDataProvider interface and registering it with the dependency resolver.

We saw that TempData does not get loaded if a controller context gets invoked by a child action. The child action would be able to access to parent action’s TempData.

 

In the next part of the series, we will start digging deeper in how the action method gets located on a controller.

Read More

ASP.NET MVC under the hood part 3

Posted by on Apr 15, 2013 7:48 PM in aspnet,mvc | 0 comments

In the previous part of the series, we had a look at the MvcRouteHandler and how it determined the session state behavior for the requested controller. After setting the session state behavior of the controller, it then returns the MvcHandler.

image

When the MvcHandler comes to life and gets asked to start handling the request, it will add the MVC “X-AspNetMvc-Version” header for the current version of ASP.NET MVC to the request.

It will remove the optional parameters from the route data, and proceed to get the controller (name) from RouteData.Values.

Finding the Controller Type

To get the type so that it can be instantiated, it uses the currently configured controller factory on the controller builder. You can substitute the default controller factory for your own.

The MvcHandler will ask the controller factory to create a controller and the following section explains how it does just that.

 

If the route that matched the request specified any namespaces, it will first attempt to find the controller within the namespaces specified.

If the controller is not found in the namespace and the “UseNamespaceFallback” data token is not set to false explicitly, the controller will be found without using any namespaces.

image

How does it find the Contoller?

One question is itching to be answered though and that is…

We have an url such as http://localhost/Home/Index and we’ve just seen “home” being retrieved as the controller name, where and when does the “Controller” bit get added to get the actual controller type? That actually happens in the very next part of this article.

Populating the ControllerTypeCache

Before asking something called the ControllerTypeCache to get the controller type, a called to EnsureInitialized is made.

EnsureInitialized checks if the cache is null and if it is, it will make a call to get the controllers via reflection using a predicate IsControllerType.

It is a controller type if

1. The type is public

2. The type name ends with “Controller”

3. The type is not abstract

4. The type is assignable from IController.

What gets stored in the cache is the name of the controller without the “Controller” string as well as a lookup for all the namespaces that a controller with that name was found in.

Note : If more than 1 controller is found, an ambiguous controller exception will be thrown with the names of all the controllers that was found.

Creating an instance of the Controller

Once a controller type is found, the DefaultControllerFactory will use a private class of the DefaultControllerFactory called the DefaultControllerActivator to create an instance of the controller type. The following logic used is, if the currently set dependency resolver cannot create a type, then use the Activator.CreateInstance method.

Let’s recap

1. MvcHandler gets asked to handle a particular request.

2. The controller name is retrieved from the Route Data Values

i.e. http://localhost/Home/Index will get “Home” as the controller name

3. The DefaultControllerFactory then is asked to create a controller.

4. If there are namespaces specified in the route that matched the request, the controller factory will attempt to find the controller in the set of namespaces.

5. If the controller was not found and the UseNamespaceFallback is not explicitly set to false, then DefaultNamespaces on the ControllerBuilder will be used.

6. if all else fails, the controller will be searched for without taking any namespaces into consideration.

7. The ControllerTypeCache is then checked for a matching controller by passing it a controller name as well as a list of namespaces to search in.

8. The DefaultControllerActivator is then used to create the type, attempting to the use dependency resolver. If that fails, Activator.CreateInstance is used to create the controller.

 

In the next part of the series, we will see what happens to the controller after it has been created.

Read More

ASP.NET MVC under the hood part 2

Posted by on Apr 13, 2013 3:04 AM in aspnet,mvc | 0 comments

In the first part of the series, we looked at where the life of an MVC application starts.

In this post, we are going to start digging deeper into the MvcHandler, the object responsible for handling a request for ASP.NET MVC.

Starting from the beginning again to build up some context.

In our ASP.NET MVC application, we have wired up  the MvcRouteHandler to be responsible for handling requests that match a particular pattern. That pattern being http://somedomain/{controller}/{action} (with default controller of home and action of index). (More information on routing and url patterns can be found here).

When we open our favorite browser, enter an address at in the address bar and hit “go”.

image

If the particular requested url matches the pattern that we asked the MvcRouteHandler to handle, it will be asked to return an HttpHandler that will be tasked with handling the request. So what now?

The first thing that happens in the MvcRouteHandler is to check that the RouteData contains a value for “controller”.

The MvcRouteHandler will use the currently configured ControllerFactory on the ControllerBuilder to get the controller type using the controller value from RouteData.

 

Extensibility notification : You are able to set the controller factory via ControllerBuilder.Instance.SetControllerFactory. Your Controller Factory should implement the IControllerFactory interface.

 

The session state behavior for the controller will then be determined. This session state behavior can be set on a controller via an attribute called SessionStateAttribute

For a particular controller, session state can be set to disabled, readonly, required (i.e. full read and write access), or default, which means that the default logic ASP.NET logic for determining the session state behavior is used.

Let’s recap

image

1. Browser makes a request to a particular url (http://somedomain/{controller}/{action})

2. The configured MvcRouteHandler is tasked to return an HttpHandler that can handle the request

3. Before returning an HttpHandler, the controller type is retrieved via the ControllerBuilder, which internally uses the currently set ControllerFactory.

4. The controller type is used to determine the session state behavior. The session state behavior is then set on the request’s http context.

 

To get a better understanding of how the puzzle pieces fit together, attempt to create your own RouteHandler by implementing the IRouteHandler interface. Register your RouteHandler, by adding it to the RouteCollection.

Implement your own IHttpHandler and let your RouteHandler return it when asked for it.

Furthermore, you can attempt to build your own IControllerFactory and set it to be the Controller Factory used by the ControllerBuilder.

In the next part of the series, we will travel further down the rabbit hole. We will see where our concrete controller gets created, and possibly look at how our action method is found.

Read More