Razor Pages in ASP.NET Core
Razor Pages is a page-centric programming model for building web UIs with ASP.NET Core. It simplifies building Razor-based applications by enabling developers to bring together HTML, CSS, JavaScript, and server-side code into a single unit. This model is ideal for scenarios where you want to focus on individual pages rather than the controller-action structure of MVC.
Introduction
Razor Pages offers a clear and organized way to develop web applications. Each page consists of a Razor file (.cshtml
) for the UI and an optional C# code-behind file (.cshtml.cs
) for handling logic. This separation of concerns makes it easier to manage and maintain your web application.
Components of a Razor Page
A typical Razor Page consists of the following components:
- Razor View (
.cshtml
): This file contains the HTML markup, Razor syntax for rendering dynamic content, and references to CSS and JavaScript files. - Page Model (
.cshtml.cs
): This C# class contains the logic for the page, including data retrieval, form processing, and model binding. It is linked to the Razor View via the@model
directive.
The Page Model
The Page Model is a C# class that inherits from PageModel
. It acts as a backend for your Razor Page, providing properties and methods to support the UI. Key features include:
- Properties: Used for binding data to UI elements and for passing data from the server to the client.
- Event Handlers: Methods like
OnGet()
andOnPost()
handle HTTP GET and POST requests respectively. - Model Binding: Automatically maps incoming request data (query strings, form data, route data) to properties in the Page Model.
@functions
block or top-level statements, though a separate code-behind is generally recommended for better organization and testability.
The Razor View
The Razor View (.cshtml
) uses Razor syntax to embed server-side code within HTML. This allows you to dynamically generate HTML content based on data from the Page Model.
The @model
directive at the top of the Razor file specifies the Page Model type it's associated with:
@page
@model MyWebApp.Pages.IndexModel
@{
ViewData["Title"] = "Home page";
}
@Model.Message
Welcome to our ASP.NET Core application!
Routing for Razor Pages
Razor Pages use a convention-based routing system. By default, the route for a Razor Page is determined by its file path relative to the Pages
folder. For example, a file named Pages/About.cshtml
will be accessible at the /About
URL.
You can customize routing using the @page
directive with route templates or by defining routes in the Startup.cs
(or Program.cs
in .NET 6+) file.
@page "{id:int}"
@model MyWebApp.Pages.Products.DetailsModel
Product Details
Product ID: @Model.Product.Id
Data Binding
Model binding simplifies the process of mapping incoming request data to properties on your Page Model. ASP.NET Core automatically handles binding for form fields, query strings, and route parameters to properties marked with [BindProperty]
.
// In ProductDetails.cshtml.cs
public class ProductDetailsModel : PageModel
{
[BindProperty(SupportsGet = true)]
public int ProductId { get; set; }
public Product Product { get; set; }
public void OnGet()
{
// Load product details based on ProductId
Product = GetProductById(ProductId);
}
}
Form Handling
Handling form submissions in Razor Pages is straightforward. Use HTTP POST methods to process form data. The OnPost()
method in your Page Model is called when a form is submitted using the POST method.
// In Create.cshtml.cs
public class CreateModel : PageModel
{
[BindProperty]
public Product NewProduct { get; set; }
public IActionResult OnPost()
{
if (!ModelState.IsValid)
{
return Page(); // Re-render the page with validation errors
}
// Add NewProduct to your data store
// ...
return RedirectToPage("./Index"); // Redirect to the index page
}
}
In the Razor View (Create.cshtml
):
@page
@model CreateModel
@{
ViewData["Title"] = "Create Product";
}
Layouts and Partial Views
Razor Pages leverage the layout system defined in ASP.NET Core. A default layout file (usually _Layout.cshtml
in the Pages/Shared
folder) is applied to all pages, providing consistent headers, footers, and navigation.
You can use _ViewImports.cshtml
to import common directives and namespaces across all Razor Pages within a directory or the entire application.
Partial Views
Partial views are reusable chunks of UI that can be rendered within Razor Pages or other partial views. They are useful for breaking down complex UIs into smaller, manageable components.
// In Index.cshtml
<partial name="_ProductSummary" model="Model.FeaturedProduct" />
Tag Helpers
Tag Helpers allow you to write server-side code in Razor files using the familiar syntax of HTML attributes. They transform HTML tags into .NET objects that can render server-side markup. Common Tag Helpers include <form>
, <input>
, <label>
, and <a>
.
Dependency Injection
Razor Pages fully support dependency injection. You can inject services into your Page Model constructors or properties using the [FromServices]
attribute to access services like database contexts, logging, or configuration.
// In Index.cshtml.cs
public class IndexModel : PageModel
{
private readonly IProductService _productService;
public IndexModel(IProductService productService)
{
_productService = productService;
}
public void OnGet()
{
Products = _productService.GetAllProducts();
}
}
Security Considerations
Razor Pages integrate with ASP.NET Core's authentication and authorization mechanisms. You can protect pages or specific handlers using the [Authorize]
attribute.
// In Admin/Index.cshtml.cs
[Authorize]
public class AdminIndexModel : PageModel
{
public void OnGet() { ... }
}
Testing Razor Pages
The page-centric model of Razor Pages makes unit and integration testing more straightforward. You can test your Page Models independently of the web server and use test hosts to simulate HTTP requests.