Inside ASP.NET MVC: All begins here - MvcHanlder
Last time we explored a way of HTTP request from the IIS up to MvcHanlder
. Then UrlRouting
module match URL we registered in Application_Start()
, it gets corresponding IRouteHandler
class and calls for GetHttpHandler
method. In ASP.NET MVC URL IRouteHandler
interface is implemented by MvcRouteHandler
class which return MvcHanlder
instance. The actual MVC story begins exactly in MvcHanlder
internals.
Generic overview
We know that HttpHandlers are special objects that handles requests and produce a response. MvcHanlder
produce nothing by itself. Instead, it uses ControllerBuilder
object for creating Controller
and call controller Execute
method. It is Execute
method responsibility to find corresponding action, call action and wrap action return result it HTTP response.
As you can see, it implements 3 interfaces: IHttpHandler
, IHttpAsyncHandler
and IRequiresSessionState
. The handler could operate in 2 modes: sync and async, depending on caller. ASP.NET frameworks ProcessRequestInternal
method try to utilize asynchronous mode of work first.
The constructor of MvcHanlder
receives RequestContext
class, that is part of System.Web.Routing and contains information about HttpContext
.
Synchronous and Asynchronous modes
Of course, the details of operation in synchronous and asynchronous modes are differ from each other, but main algorithm of work is exactly the same.. Let’s first see how it operates in sync mode.
Process the request
Due to IHttpHandler
interface, MvcHanlder
expected to support one property and one method:
IsReusable
is always false, meaning that for each request the runtime would create new instance of handler. ProcessRequest
receives HttpContext
and basically delegates call to internal ProcessRequest
method.
Notice to the first line.. HttpContext
is being wrapped with HttpContextWrapper
and casted to HttpContexBase
. Rest of code never (mostly) using HttpContext
directly, but through HttpContexBase
. The HttpContexBase
have been introduced to improve testability of ASP.NET applications, since HttpContext
is unable to be mocked.
ControllerBuilder, ControllerFactory, Controller
Let’s see inside the ProcessRequest
method to see how exactly the controller is being constructed and called.
The call is wrapped with a little security handler, that would do perform the check for Trust settings, before calling internal action. Inside the action IController
and IControllerFactory
are being declared and initialized in ProcessRequestInit
method.
First, it puts MVC version information into HTTP response header, removes optional parameters from routes (one we mark with UrlParameter.Optional
) and gets the name of controller from RequestContext
. Remember, in global.asax we define URL pattern like “{controller}/{action}/{index}”, so in case of such URL products/search/122
the GetRequiredString
will return “products”.
ControllerBuilder
is a singleton and factory method that creates IControllerFactory
instance.
ControllerFactory
is responsible for creation of controller by given name.
The ProcessRequestInit
gets the factory from ControllerBuilder
, ask factory to create controller by the name from URL and returns results back to ProcessRequest
.
Here we also could see good example of comments that lies.. “// Instantiate the controller and call Execute” - maybe sometime ago that was true, but not its false since Execute is not called here.
Execution
As soon as controller factory and controller are successfully created, ProcessRequest
calls for controller Execute
method. Now, it is controller responsibility to produce the output and we will see how it does that in next “Inside MVC” posts. Execution is wrapped inside try / finally
block and finalize code will release the controller by calling ReleaseContoller
method of factory.
Meanwhile in Asynchronous…
In async world the things are bit more complex. There are no one single method, but 2 instead. BeginProcessRequest
and EndProcessRequest
.
The request initialization and creation of factory and controller is exactly the same. The difference in execution, for async controller 2 delegates are being created,
In fact, that than the request execution begins, beginDelegate
is called that would call BeginExecute
of the controller. At the end of request endDelegate
called that would call EndExecute
of controller.
What about tests?
That was a great surprise to me that MvcHandler
is well unit tested. All aspects of its work are covered with corresponding tests.. I’ve heard a lot of developers complains like, “oh, it is so low-level code.. could not test it”. But MVC team, proof it is wrong. HttpContexBase
could be easy mocked, so no excuse of not writing unit tests for modules/handlers. As I said in into, test code is really clean, following AAA principle’s, so I got a lot of pleasure of looking inside.
BTW, they are using Moq framework for mocking, that I personally like as well :).
Previous: Inside ASP.NET MVC: Route to MvcHandler
Next: Inside ASP.NET MVC: ControllerBuilder class
Last time we explored a way of HTTP request from the IIS up to MvcHanlder
. Then UrlRouting
module match URL we registered in Application_Start()
, it gets corresponding IRouteHandler
class and calls for GetHttpHandler
method. In ASP.NET MVC URL IRouteHandler
interface is implemented by MvcRouteHandler
class which return MvcHanlder
instance. The actual MVC story begins exactly in MvcHanlder
internals.
Generic overview
We know that HttpHandlers are special objects that handles requests and produce a response. MvcHanlder
produce nothing by itself. Instead, it uses ControllerBuilder
object for creating Controller
and call controller Execute
method. It is Execute
method responsibility to find corresponding action, call action and wrap action return result it HTTP response.
As you can see, it implements 3 interfaces: IHttpHandler
, IHttpAsyncHandler
and IRequiresSessionState
. The handler could operate in 2 modes: sync and async, depending on caller. ASP.NET frameworks ProcessRequestInternal
method try to utilize asynchronous mode of work first.
The constructor of MvcHanlder
receives RequestContext
class, that is part of System.Web.Routing and contains information about HttpContext
.
Synchronous and Asynchronous modes
Of course, the details of operation in synchronous and asynchronous modes are differ from each other, but main algorithm of work is exactly the same.. Let’s first see how it operates in sync mode.
Process the request
Due to IHttpHandler
interface, MvcHanlder
expected to support one property and one method:
IsReusable
is always false, meaning that for each request the runtime would create new instance of handler. ProcessRequest
receives HttpContext
and basically delegates call to internal ProcessRequest
method.
Notice to the first line.. HttpContext
is being wrapped with HttpContextWrapper
and casted to HttpContexBase
. Rest of code never (mostly) using HttpContext
directly, but through HttpContexBase
. The HttpContexBase
have been introduced to improve testability of ASP.NET applications, since HttpContext
is unable to be mocked.
ControllerBuilder, ControllerFactory, Controller
Let’s see inside the ProcessRequest
method to see how exactly the controller is being constructed and called.
The call is wrapped with a little security handler, that would do perform the check for Trust settings, before calling internal action. Inside the action IController
and IControllerFactory
are being declared and initialized in ProcessRequestInit
method.
First, it puts MVC version information into HTTP response header, removes optional parameters from routes (one we mark with UrlParameter.Optional
) and gets the name of controller from RequestContext
. Remember, in global.asax we define URL pattern like “{controller}/{action}/{index}”, so in case of such URL products/search/122
the GetRequiredString
will return “products”.
ControllerBuilder
is a singleton and factory method that creates IControllerFactory
instance.
ControllerFactory
is responsible for creation of controller by given name.
The ProcessRequestInit
gets the factory from ControllerBuilder
, ask factory to create controller by the name from URL and returns results back to ProcessRequest
.
Here we also could see good example of comments that lies.. “// Instantiate the controller and call Execute” - maybe sometime ago that was true, but not its false since Execute is not called here.
Execution
As soon as controller factory and controller are successfully created, ProcessRequest
calls for controller Execute
method. Now, it is controller responsibility to produce the output and we will see how it does that in next “Inside MVC” posts. Execution is wrapped inside try / finally
block and finalize code will release the controller by calling ReleaseContoller
method of factory.
Meanwhile in Asynchronous…
In async world the things are bit more complex. There are no one single method, but 2 instead. BeginProcessRequest
and EndProcessRequest
.
The request initialization and creation of factory and controller is exactly the same. The difference in execution, for async controller 2 delegates are being created,
In fact, that than the request execution begins, beginDelegate
is called that would call BeginExecute
of the controller. At the end of request endDelegate
called that would call EndExecute
of controller.
What about tests?
That was a great surprise to me that MvcHandler
is well unit tested. All aspects of its work are covered with corresponding tests.. I’ve heard a lot of developers complains like, “oh, it is so low-level code.. could not test it”. But MVC team, proof it is wrong. HttpContexBase
could be easy mocked, so no excuse of not writing unit tests for modules/handlers. As I said in into, test code is really clean, following AAA principle’s, so I got a lot of pleasure of looking inside.
BTW, they are using Moq framework for mocking, that I personally like as well :).
Previous: Inside ASP.NET MVC: Route to MvcHandler Next: Inside ASP.NET MVC: ControllerBuilder class