Explain how Razor Pages work in ASP.NET Core

Razor Pages simplify the traditional MVC-based programming model by adopting a file-based routing. Razor Pages focus on page-based scenarios for building web applications rather than using controllers and views like a traditional ASP.NET MVC application.

Once the application receives an HTTP request, it moves through the middleware pipeline until it reaches a middleware component that can handle and process it. Typically, it's a routing middleware that matches a URL path to a configured route. This route defines which Razor page to invoke for this particular request.

Once the router has selected the Razor Page, the framework executes that Razor Page to generate the final HTML response. This response then makes its way back to the client browser that made the request.

A Razor Pages file is a .cshtml file in the Pages folder, similar to the View files in an ASP.NET MVC application. Each view has an associated C# object. This object is called the page model, and it models the behavior for the page. In general, the router maps a request URL to a single Razor Page by looking in the Pages folder for a Razor Page with the same path.


Live Demo

@model IndexModel
   ViewData["Title"] = "Home page";

<div class="text-center">
   <h1 class="display-4">Welcome</h1>
   <p>Learn about <a href="https://docs.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>

In the above code snippet, the @page directive indicates that the page is a Razor Page. The second line links the Razor page to a PageModel, IndexModel. Next, inside the @ block, we have C# code that executes without writing any HTML to the response. We can also have dynamic C# code to render HTML and plain old static HTML inside a Razor Page.

Razor Pages have layouts, base templates that define the common elements of the application, such as headers and footers. This layout HTML is added to the Razor Page HTML to generate the complete HTML response, preventing duplicate code.

A PageModel class is the "code-behind" for a Razor Page that performs the actual heavy lifting, e.g., processing business logic, making external requests, fetching data from the database, etc. All Page Model classes derive from the PageModel base class. They also provide one or more page handers, which are simply methods that define how to handle requests to the Razor Page.

For example, here is the PageModel for the above Razor Page.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Logging;

namespace Razor.Pages{
   public class IndexModel : PageModel{
      private readonly ILogger<IndexModel> _logger;

      public IndexModel(ILogger<IndexModel> logger){
         _logger = logger;

      public void OnGet(){


These page handlers use convention-based naming, i.e. names of the page handlers are based on the HTTP verb they respond to. Depending on the application logic, the handlers can return void, which tells the Razor Page to return the HTML view or return other data in the form of IActionResult.

The important thing that Razor Pages accomplish is that they separate the view generation logic from the actual data computation or business logic. This follows the separation-of-concerns principle and keeps the application maintainable. If you need to change the UI, you can do that without modifying the business logic and vice versa.