The ASP.NET Core MVC Request Life Cycle is a sequence of events, stages or components that interact with each other to process an HTTP request and generate a response that goes back to the client. In this article, we will discuss each and every stage of ASP.NET Core MVC Request Life Cycle in detail.
Middleware
Middleware component is the fundamental building element of the HTTP pipeline of an application. This is a collection of components that are combined to form a request pipeline that can process any incoming request.
Routing
Routing is a component of middleware that implements the MVC framework. With the aid of convention routes and attribute routes, the routing Middleware component determines how incoming requests are mapped to Controllers and action methods.
Controller Initialization
During this phase of the ASP.NET MVC Core Request Life Cycle, controller initialization and execution occur. Controllers are in charge of processing inbound requests. The controller chooses the appropriate action methods based on the supplied route templates.
Method call implementation
After the controllers have been initialized, the action methods are executed and a view containing an HTML document that will be returned to the browser is returned.
Result Execution
During this phase of the ASP.NET MVC Core Request Life Cycle, the response to the initial HTTP request is executed. The MVC view engine renders a view and returns the HTML response if an action method returns a view result. If the result is not of type view, the action method will generate its own response.
Now, we will briefly discuss each phase of Middleware
Middleware component is the fundamental building element of the HTTP pipeline of an application. These are a series of components that comprise a request pipeline to handle any incoming request. Each new request is forwarded to the initial middleware component. After processing an incoming request, the component determines whether to generate a response or pass it on to the next component. Once the request has been processed, the response is sent back via these components.
The majority of middleware components are implemented as isolated classes that generate content. Adding the ContentComponent.cs class will allow us to create a content-generating middleware component.
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
namespace WebApplication
{
public class ContentComponent
{
private RequestDelegate nextComponent;
public ContentComponent(RequestDelegate nextMiddleware) => nextComponent = nextMiddleware;
public async Task Invoke(HttpContext httpContext)
{
if (httpContext.Request.Path.ToString().ToLower() == "/edit")
{
await httpContext.Response.WriteAsync("This is edit URL component", Encoding.UTF8);
}
else
{
await nextComponent.Invoke(httpContext);
}
}
}
}
This ContentComponent middleware component is defining a constructor, and inside constructor its taking RequestDelegate object. This RequestDelegate object represents the next middleware component. ContentComponent component also defines an Invoke method. When ASP.NET Core application receives an incoming request, the Invoke method is called.
The HttpContext argument of the Invoke method provides information about the incoming HTTP request and the generated response that will be sent back to the client. The invoke method of ContentComponent class checks whether incoming request is sent to /edit URL or not. If the request has been sent to /edit url then, in response a text message is sent.
Routing
Routing is a middleware component that implements MVC framework. In ASP.NET Core, the routing system is used to handle MVC URLs. The routing Middleware component decides how an incoming request can be mapped to Controllers and actions methods, with the help of convention routes and attribute routes. Routing bridges middleware and MVC framework by mapping incoming request to controller action methods.
In a particular application, MVC registers one or more routes using MapRoute method. MVC provides default routes that are given a name and a template to match incoming request URLs. The Controllers and action variables are placeholders that are replaced by matching segments of the URL.
These routes are passed into and consumed by routing middleware.
The MVC routing pipeline
In ASP.NET Core, routing maps an incoming request to RouteHandler class, which is then passes as the collection of routes to the routing middleware. The routing middleware executes MVC RouteHandler for each route. If a matching controller and action method is found on a particular route, then the requested data is forwarded to the rest of the MVC framework which will generate a response.
There are two types of routing available in MVC which are:
Convention routing
This routing type uses application wide patterns to match a different URL to various controller action methods. Convention routes represent default possible routes that can be defined with the help of controller and action methods.
Attribute routing
This type of routing is implemented through attributes and applied directly to a specific controller or action method.
The convention routing methodology is implemented inside startup.cs file. In startup.cs, the UseMvc() method registers the routes, that are being supplied to it as a parameter inside MapRoute method.
public void Configure(IApplicationBuilder app, IHostingEnvironment env) {
app.UseMvc(routes => {
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
A route attribute is defined on top of an action method inside controller class.
public class MoviesController: Controller {
[Route(“movies / released / {year}/{month:regex(\\d{4})}”)]
public ActionResult ByReleaseYear(int year, int month) {
return Content(year + ”/”+month);
}
}
Controller Initialization
At this stage, the process of initialization and execution of controllers takes place. Controllers are responsible for handling incoming requests which is done by mapping request to appropriate action method. The controller selects the appropriate action methods (to generate response) on the basis of route templates provided. A controller class inherits from controller base class. A controller class suffix class name with the Controller keyword.
The MVC RouteHandler is responsible for selecting an action method candidate in the form of action descriptor. The RouteHandler then passes the action descriptor into a class called Controller action invoker. The class called Controller factory creates instance of a controller to be used by controller action method. The controller factory class depends on controller activator for controller instantiation.
After action method is selected, instance of controller is created to handle request. Controller instance provides several features such as action methods, action filters and action result. The activator uses the controller type info property on action descriptor to instantiate the controller by name. once the controller is created, the rest of the action method execution pipeline can run.
The controller factory is the component that is responsible for creating controller instance. The controller factory implements an interface called IControllerFactory. This interface contains two methods which are called CreateController and ReleaseController.
Action Method Execution Process
Authorization Filters
Authorization filters authorize or deny any incoming request.
Controller Creation
Instantiate Controller object.
Model Binding
Model Binding bind incoming request to Action method parameters.
Action Filters
OnActionExecuting method is always called before the action method is invoked.
Action Method Execution
Action method inside controller classes executes logic to create Action Result. Action method returns action results to generate response.
Action Filters
OnActionExecuted method called is always called after the action method has been invoked.
Authorization Filters
In ASP.NET Core MVC, there is an attribute called Authorize. Authorize is a filter, which can be applied to an action and it will be called by a MVC Core framework before and after that action or its result are executed.
These filters are used to provide security to application, including user authorization. If authorize attribute is applied to an action method, before the action is executed, the attribute will check if the current user is logged in or not. If not it will redirect the user to the login page. Authorization filters authorize or deny any incoming request.
In the below code example, Authorize Authorization filter(predefined filter) has been used over Index action method.
[Authorize]
public ViewResult Index() {
return View();
}
The OnAuthorization method authorizes an HTTP request.
namespace WebApplication {
public interface IAuthorizationFilter: IFilterMetadata {
void OnAuthorization(AuthorizationFilterContext content);
}
Now I have demonstrated, how to create a custom Authorization filter. A class file called OnlyHttpsAttribute.cs has been created which defines the action filter.
using System;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
namespace WebApplication {
public class OnlyHttpsAttribute: IAuthorizationFilter {
public void OnAuthorization(AuthorizationFilterContext approve) {
if (!approve.HttpContext.Request.IsHttps) {
approve.Result =
new StatusCodeResult(StatusCodes.Status403Forbidden);
}
}
}
}
In the below example, OnlyHttps attribute has been applied to the Home controller
using Microsoft.AspNetCore.Mvc;
using WebApplication;
namespace Controllers {
[OnlyHttps]
public class HomeController: Controller {
public ViewResult Index() => View("Message",
"this URL is working fine");
}
}
Model Binding
Model binding maps incoming request to action method parameters. Action method parameters are inputs for an action method. Using data values acquired from HTTP request, model binding creates objects that an action method takes as an argument.
The model binders are the components which provide data values from incoming request to invoke action methods. The model binders search for these data values under three scenarios which are
Form data values
Routing variables
Query strings
Each of these sources are examined in sequence until and unless an argument value is found.
Let’s consider a controller class as follows
using System.Linq;
using System.Web.Mvc;
namespace project.Controllers {
public class CustomerController: Controller {
public ActionResult Edit(int id) {
return Content("id=", +id);
}
}
}
Now, suppose i requested an URL as /Customer/Edit/1
Here 1 is the value of id property. MVC translated that part of the URL and used it as the argument when it called the Edit method in the Customer controller class to service the request.To invoke the Edit method, MVC requires a certain type of value for the argument id, therefore model binding provide data values to invoke action methods.
Action Filters
Action filters are used to execute tasks instantly before and after action method execution is performed. In order to apply some logic to action methods, without having to add extra code to the controller class, action filters can be used either above the action method itself or above the Controller class.
Action filter implements two types of interfaces which are IActionFilter and IAsyncActionFilter.
The IActionFilter interface which defines action filter is as follows
public interface IActionFilter: IFilterMetadata {
void OnActionExecuting(ActionExecutingContext content);
void OnActionExecuted(ActionExecutedContext content);
}
The method OnActionExecuting is always called before the action method is invoked, and the method OnActionExecuted is always called after the action method has been invoked, whenever an action filter is applied to an action method.
Whenever an action filter is created, the data is provided using two different context classes, ActionExecutingContext and ActionExecutedContext.
Now I will demonstrate, how to create a custom action filter by deriving a class from the ActionFilterAttribute class. A class file called ActionAttribute.cs has been created which defines the action filter.
using Microsoft.AspNetCore.Mvc.Filters;
namespace WebApplication {
public class ActionAttribute: ActionFilterAttribute {
private Stopwatch a;
public override void OnActionExecuting(ActionExecutingContext content) {
a = Stopwatch.StartNew();
}
public override void OnActionExecuted(ActionExecutedContext content) {
a.Stop();
string output = "<div> calculated time is: " + $" {a.Elapsed.TotalMilliseconds} ms </div>";
byte[] bytes = Encoding.ASCII.GetBytes(output);
content.HttpContext.Response.Body.Write(bytes, 0, bytes.Length);
}
}
}
In the below example, Action attribute has been applied to the Home controller
using Microsoft.AspNetCore.Mvc;
using WebApplication;
namespace Controllers {
[Action]
public class HomeController: Controller {
public ViewResult Index() => View("Message",
"This index action is executed between action attribute");
}
}
Action Method Execution
Action methods return objects that implements the IActionResult interface from the Microsoft.AspNetCore.Mvc namespace. The various types of response from the controller such as rendering a view or redirecting the client to another URL, all these responses are handled by IActionResult object, commonly known as action result.
When an an action result is returned by a specific action method, MVC calls its ExecuteResultAsync method, which generates response on behalf of the action method. The ActionContext argument provides context data for generating the response, including the HttpResponse object.
Controllers contain Action methods whose responsibility is to generate a response to an incoming request. An action method is any public method inside a controller that responds to incoming requests.
Public class HomeController: Controller {
Public IActionResult Edit() {
Return View();
}
}
Here, Edit action method is defined inside Home controller.
using Microsoft.AspNetCore.Mvc;
using WebApplication23;
namespace WebApplication23.Controllers {
public class HomeController: Controller {
public ViewResult Index() => View("Form");
};
}
}
Here, Index method is defined inside Home controller, which is returning a view.
Result Execution
The action method returns action result. This action result is the base class for all action results in asp.net mvc. Depending on the result of an action method, it will return an instance of one of the classes that derive from action result.
Different types of action result are
TYPES |
HELPER METHOD |
DESCRIPTION |
ViewResult |
View() |
Renders a view and retun HTML content |
PartialViewResult |
PartialView() |
Returns partial view |
ContentResult |
Content() |
Returns simple text |
RedirectResult |
Rediect() |
Redirect result to URL |
RedirectToRouteResult |
RedirectToAction() |
Redirect to an action method |
JsonResult |
Json() |
Returns serialized json object |
FileResult |
File() |
Returs a file |
HttpNotFoundResult |
HttpNotFound() |
Returns not found or 404 error |
EmptyResult |
|
When action does not return values |
During this stage of ASP.NET MVC Core Request Life Cycle, result i.e. the response generated to the original HTTP request, is executed. If an action method returns a view result, the MVC view engine renders a view and returns the HTML response. If result is not of view type, then action method will generate its own response.
using Microsoft.AspNetCore.Mvc;
using WebApplication23.example;
namespace WebApplication23.Controllers {
public class HomeController: Controller {
public ViewResult Index() => View("Form");
public ViewResult ReceiveForm(string name, string state) => View("Details",$ "{name} lives in {state}");
}
In the above example Index action method is returning a view result, therefore the MVC view engine renders a view and returns the HTML response, which is a simple form.
In this article, we have discussed each and every stage of ASP.NET Core MVC Request Life Cycle in detail. All of the stages have been described with proper coding examples and life cycle diagrams.