ASP.NET Core MVC Request Life Cycle

Introduction

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.

ASP.NET Core MVC Request Life Cycle

The request life cycle consists of various stages which are:

Middleware

Middleware component forms the basic building block of application HTTP pipeline. These are a series of components that are combined to form a request pipeline in order to handle any incoming request.

Routing

Routing is a middleware component that implements MVC framework. 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.

Controller Initialization

At this stage of ASP.NET MVC Core Request Life Cycle, the process of initialization and execution of controllers takes place. Controllers are responsible for handling incoming requests. The controller selects the appropriate action methods on the basis of route templates provided.

Action method execution

After the controllers are initialized, the action methods are executed and returns a view which contains Html document to be returned as response to the browser.

Result Execution

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.

Now, we will discuss each stage briefly

Middleware

Middleware component forms the basic building block of the application'a HTTP pipeline. These are aseries of components that are combined to form a request pipeline in order to handle any incoming request. Whenever a new request comes, it is passed to the first middleware component. The component then decides, whether to generate a response after handling that incoming request or to pass it to the next component. The response is sent back along these components, once the request has been handled.

Most middleware components are implemented as standalone classes, which are content generating middleware. Now, we will be creating a content generating middleware component by adding ContentComponent.cs class.

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

 ASP.NET Core MVC Request Life Cycle

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.

ASP.NET Core MVC Request Life Cycle

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.

Summary

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.