top of page

Razor Pages: A Beginner's Guide to ASP.NET Core Web Development

Razor Pages, introduced in ASP.NET Core 2.0, offer a page-based programming model (paradigm) that simplifies web UI development within the ASP.NET Core MVC framework. They provide a more concise approach to the traditional MVC pattern with concerns about Models, Views, and Controllers.


What are Razor Pages?

Razor Pages are a modern approach (coding paradigm) to web development within the ASP.NET Core framework. They offer a streamlined development experience compared to traditional ASP.NET MVC, aiming for simplicity and developer productivity.


Think of Razor Pages as a hybrid between MVC Views and Controllers. They combine the UI (user interface) elements from Views with the processing logic typically found in Controllers. This unique approach results in self-contained .cshtml files housing all the necessary code for a specific page, making them easier to manage and reason about.


Benefits of Razor Pages:

  • Simplicity: Razor Pages boast a clear and concise syntax, making them ideal for building basic CRUD (Create, Read, Update, Delete) operations and data-driven web pages.

  • Increased Productivity: The streamlined structure of Razor Pages allows for faster development and easier testing compared to the more granular separation of concerns in MVC.

  • Flexibility: As part of the ASP.NET Core ecosystem, Razor Pages integrates seamlessly with existing MVC controllers and views, allowing developers to choose the most suitable approach for each project section.

  • Enhanced Testability: The core logic of a Razor Page resides within the PageModel class, which can be unit-tested independently from the UI components, promoting robust and maintainable code.


Razor Pages Architecture

Consider the below image that describes key components to render a razor page:

Razor Pages in ASP.NET

Model: This section represents the data model associated with the Razor Page. It typically consists of a class file (.cs) containing properties that hold the data used by the page.


Action: This refers to the methods within the page model class (often named OnGet, OnPost, or similar) that handle user requests. These methods execute server-side code to process data, interact with databases, or perform any necessary logic before generating the response.


HTTP Requests: This signifies incoming requests from the user's browser to the web server. The type of request (GET, POST, etc.) determines which action method is invoked in the page model.


Model Properties: The individual data fields defined within the model class. They provide the foundation for storing and manipulating data associated with the Razor Page.


HTTP Responses: This represents the HTML content sent back to the user's browser after processing the request on the server side. The Razor Page leverages Razor syntax to dynamically generate the HTML response based on the model data and any actions performed within the page model.


Corresponding Model Class: This highlights the association between the Razor Page and its corresponding model class. The model class serves as the data layer for the Razor Page, encapsulating the data it works with.


Razor Pages in ASP.NET Core combine HTML templates with server-side code to generate dynamic web content. The model acts as the data layer, while the page model methods handle user interactions and logic processing. This architecture promotes separation of concerns, making Razor Pages a productive approach for web development.


How do Razor Pages work?

Razor Pages offers a streamlined approach to web development within ASP.NET Core. Let's delve into the mechanics of how Razor Pages function:


Each Razor Page comprises two essential files:

  • .cshtml file: This file holds the HTML structure and Razor syntax for crafting the user interface (UI).

  • .cshtml.cs file (Page Model): This C# code file acts as the brain of the Razor Page, housing the application logic and data access functionalities. It's often referred to as the "page model."


When a user requests a Razor Page, ASP.NET Core springs into action:

  1. Page Model Execution: The ASP.NET Core runtime initiates by executing the relevant method within the page model's .cshtml.cs file. These methods typically have names like OnGet, and OnPost, or follow similar naming conventions, corresponding to the HTTP verb used in the request (GET, POST, etc.).

  2. Data Processing and Logic: Within the page model method, any necessary server-side operations occur, such as database interactions, user input validation, or calculations.

  3. Dynamic HTML Generation: Leveraging Razor syntax within the .cshtml file, the processed data and logic from the page model are dynamically woven into the HTML structure, generating the final response sent to the user's browser.


Razor Pages syntax

Razor Pages leverage Razor syntax, a powerful server-side markup language that seamlessly integrates C# or VB.NET code within your web pages. This approach enables the creation of dynamic content on the fly, enhancing user experiences.


When a Razor Page is requested, the ASP.NET Core server executes any embedded server-side code. This code can perform various tasks, including:

  • Accessing databases to retrieve data

  • Processing user input from forms

  • Performing complex calculations


Once the server-side code finishes execution, the resulting HTML content is sent to the user's browser for rendering. This separation between server-side processing and UI display ensures efficient and secure web development.


Here's a basic example demonstrating Razor syntax within a Razor Page:

@{  var greeting = "Hello, World!";
}

<p>@greeting</p>  ```

In this example:

  • `@{ ... }`: This syntax marks a block containing C# code.

  • `@greeting`: This syntax displays the value of the `greeting` variable within the HTML `<p>` tag.


Getting started with Razor Pages

Razor Pages offers a compelling development experience within ASP.NET Core.


Prerequisites:


Creating a new Razor Pages project

You can create a new Razor Pages project using the dotnet new command followed by the webapp template. Here’s how you can do it:

dotnet new webapp -o MyRazorPagesApp

This command utilizes the dotnet new command with the webapp template to generate a new Razor Pages project structure within the specified directory (MyRazorPagesApp).


Creating a Razor Page

Add a new .cshtml file in the Pages directory to create a new Razor Page. For example, to create a new page named About, you would create a new file at Pages/About.cshtml. Here’s an example of what the About.cshtml file could look like:

@page
@model AboutModel
@{
    ViewData["Title"] = "About";
}

<h2>@ViewData["Title"]</h2>

<p>Welcome to the About page!</p>

In this file,

  • @page is a directive that specifies this is a Razor Page.

  • @model AboutModel specifies the model for this page, which would be defined in a corresponding About.cshtml.cs file.


Running a Razor Page

Bring your Razor Page application to life using the dotnet run command:

  1. Navigate to the directory containing your project file (.csproj).

  2. Execute the following command:

dotnet run

This command builds the application and starts a web server. You can then navigate to https://localhost:5001 in your web browser to view your application.


Common Razor Pages tasks

Working with Razor Pages includes handling form submissions, validating user input, working with data, and managing user sessions. These tasks are often performed in the page model, the .cshtml.cs file associated with each Razor Page.


Handling requests

Razor Pages leverage methods within the page model (.cshtml.cs file) to handle user requests. These methods correspond to specific HTTP verbs, ensuring appropriate actions are taken based on the request type:

  • OnGet Method (GET Requests): This method executes when a user requests a Razor Page using a GET verb (typically by clicking a link or entering a URL in the browser). It's commonly used for retrieving and displaying data.

  • OnPost Method (POST Requests): This method handles form submissions, where data is sent from the user's browser to the server using a POST verb. It's often used for processing user input and updating data.

public class IndexModel : PageModel
{
    public void OnGet()
    {
        // Handle GET request
    }

    public void OnPost()
    {
        // Handle POST request
    }
}

Rendering HTML

Razor Pages empower you to generate HTML content. This is achieved using Razor syntax, which integrates C# code seamlessly within your HTML files:

  • Razor Directives: These directives control how Razor Pages process the code. For example, @page specifies that the current file is a Razor Page.

  • Code Blocks: Enclosed within @{ ... }, code blocks allow you to embed C# code directly within your HTML.

  • Razor Expressions: Prefixed with @, Razor expressions evaluate C# code and insert the result into the HTML output.

@page
@model IndexModel

<h1>Welcome, @Model.Username!</h1>

In this example, @Model.Username is a Razor expression that outputs the value of the Username property of the page model.


Working with data

Razor Pages integrates smoothly with Entity Framework Core (https://learn.microsoft.com/en-us/ef/core/), a popular Object-Relational Mapper (ORM) that simplifies databases. This empowers you to retrieve, create, update, and delete data from your database within your Razor Pages:

  • Entity Framework Core Setup: You will create a connection to your database and configure Entity Framework Core within your project.

  • Data Access in Page Model: The page model methods can interact with the database using Entity Framework Core functionalities.

public class IndexModel : PageModel
{
    private readonly ApplicationDbContext _db;

    public IndexModel(ApplicationDbContext db)
    {
        _db = db;
    }

    public IList<Customer> Customers { get; private set; }

    public async Task OnGetAsync()
    {
        Customers = await _db.Customers.ToListAsync();
    }
}

In this example, the OnGetAsync method retrieves a list of customers from the database and assigns it to the Customers property.


Validation

Razor Pages provide built-in mechanisms for data validation, ensuring the integrity of your data:

  • Data Annotations: You can decorate model properties with data annotations to specify validation rules. These rules define requirements for user input, such as required fields, minimum length, or specific data types.

  • Validation Messages: If user input fails validation, Razor Pages automatically display error messages on the page, guiding the user towards correcting their input.

public class IndexModel : PageModel
{
    [BindProperty]
    [Required]
    [StringLength(100)]
    public string Name { get; set; }

    public void OnPost()
    {
        if (!ModelState.IsValid)
        {
            // Handle validation errors
        }

        // Continue processing
    }
}

In this example, the Name property is required and must be no more than 100 characters long. If the form submission is invalid, the ModelState.IsValid property will be false.


Routing

Routing in Razor Pages establishes the connection between URLs and the corresponding Razor Page files. This mapping is determined by:

  • Page Location: The physical location of the Razor Page file within your project structure plays a role in routing.

  • @page Directive (Optional): An optional @page directive within the Razor Page file can further customize the URL mapping.


By default, a Razor Page located at Pages/Products/Details.cshtml would be accessible at the URL /Products/Details. However, you could add the following @page directive within the file to customize the URL:

@page "/products/{id}"

This directive would map the page to URLs like /products/123 or /products/abc (depending on the value of the id parameter).


Advanced Razor Pages Techniques

While the core functionalities of Razor Pages empower efficient web development, exploring its advanced features unlocks even greater possibilities:


1. Layout Pages

Layout pages act as reusable templates that define the overall structure of your web application. They house common elements like headers, navigation menus, and footers. Individual Razor Pages then inherit this layout, ensuring a consistent user experience across your application.


Benefits:

  • Reduced Code Duplication: Layout pages eliminate the need to repeat header and footer code in each Razor Page, promoting code maintainability.

  • Consistent Design: By leveraging a single layout, you enforce a uniform look and feel across your application, enhancing user experience.

  • Content Flexibility: Individual Razor Pages can customize specific content areas within the layout, allowing for tailored content on different pages.


Example:

Imagine a layout page defining a header with your application logo and a navigation bar. Each Razor Page within your application would inherit this layout, automatically displaying the header elements. Specific content areas can be customized on individual pages to display unique content.


2. Tag Helpers

Tag Helpers are server-side components extending the capabilities of HTML elements within Razor Pages. They offer a more concise and programmatic way to work with HTML, reducing boilerplate code and improving readability.


Benefits:

  • Simplified HTML Code: Tag Helpers encapsulate complex HTML logic, allowing you to express functionality with a concise syntax.

  • Improved Readability: Tag Helpers makes your Razor Pages code more readable and maintainable.

  • Extensibility: The Razor Pages framework provides built-in Tag Helpers and can create custom Tag Helpers for specialized functionalities.


Example:

A built-in AnchorTagHelper Tag Helper simplifies creating links that map to Razor Page URLs within your application. Instead of writing lengthy anchor tags with href attributes, you can use the AnchorTagHelper Tag Helper to achieve the same functionality with cleaner code.


3. Dependency Injection

Dependency Injection (DI) is a design pattern that promotes loose coupling and improves testability in your application. It involves registering dependencies (services and objects) within a central container and injecting them into your Razor Pages as needed. This approach separates the creation of objects (dependencies) from their usage, leading to more flexible and maintainable code.


Benefits:

  • Loose Coupling: Dependencies are not directly created within your Razor Pages, promoting code reusability and easier unit testing.

  • Testability: By injecting dependencies, you can mock or substitute them during unit tests, isolating the functionality of your Razor Pages for more reliable testing.

  • Improved Maintainability: Dependency Injection fosters a cleaner separation of concerns, making your code easier to understand and maintain.


Example:

Imagine a Razor Page that needs to interact with a database service. Instead of directly creating a database connection object within the Razor Page, you would register the database service within the DI container. The Razor Page could then request the database service through injection, promoting loose coupling and facilitating easier unit testing of the Razor Page logic.


4. Authentication and Authorization

Authentication verifies a user's identity, while authorization determines their access rights within your application. Razor Pages integrates seamlessly with various authentication and authorization mechanisms, allowing you to control user access to specific pages and functionalities.


Common Authentication Mechanisms:

  • Individual Accounts: Users create accounts and log in to access protected areas of your application.

  • External Providers: Authentication can be delegated to external providers like Google, Facebook, or Microsoft Azure AD.


Authorization Mechanisms:

  • Roles: Users are assigned roles, and access is granted based on those roles.

  • Claims-based Authorization: Users are granted access based on claims (statements about a user) associated with their identity.


Benefits:

  • Secure Applications: Authentication and authorization ensure that only authorized users can access sensitive data and functionalities within your application.

  •  Improved User Experience (continued): Users only see the content and features relevant to their roles, streamlining their navigation and interaction within the application.


Example:

Imagine an e-commerce application. Authentication allows users to log in and manage their accounts. Authorization can then be used to restrict access to administrative functionalities (e.g., product management) to users with the "Administrator" role.


Conclusion

Razor Pages in ASP.NET Core offer a compelling approach to web development. Their emphasis on simplicity and productivity makes them ideal for a variety of scenarios:

  • Rapid Prototyping: Quickly create basic web applications to test ideas and functionalities.

  • CRUD Applications: Efficiently build applications that focus on Create, Read, Update, and Delete (CRUD) operations on data.

  • Content-driven Websites: Develop content-rich websites where dynamic content generation is essential.


Server-side logic with HTML and Razor syntax fosters a productive development experience. You can build robust, secure, and user-friendly web applications by leveraging features like layout pages, Tag Helpers, Dependency Injection, and authentication/authorization.

bottom of page