Razor Pages in ASP.NET Core
Razor Pages is a page-focused programming model for building web UIs with ASP.NET Core. It provides a clean separation of concerns, making it easier to build dynamic, data-driven web applications. This tutorial will guide you through the fundamental concepts and common scenarios when working with Razor Pages.
What are Razor Pages?
Razor Pages offers a streamlined way to build Razor-based web applications. Each page is represented by a Razor file (.cshtml) and an optional corresponding code-behind class (.cshtml.cs). This code-behind class, derived from PageModel, handles page logic, data binding, and event handlers.
Key benefits include:
- Simplicity: Less boilerplate code compared to MVC.
- Organization: Pages are organized logically in folders.
- Separation of Concerns: Clear separation between UI (
.cshtml) and logic (.cshtml.cs). - Data Binding: Easy binding of form data to page model properties.
Creating Your First Razor Page
To create a Razor Page, add a .cshtml file to the Pages folder in your ASP.NET Core project. Optionally, create a corresponding .cshtml.cs file for the page's logic.
Example: Pages/Index.cshtml
@page
@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>
<p>Message from the PageModel: @Model.Message</p>
</div>
Example: Pages/Index.cshtml.cs
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Logging;
namespace MyWebApp.Pages
{
public class IndexModel : PageModel
{
private readonly ILogger<IndexModel> _logger;
public IndexModel(ILogger<IndexModel> logger)
{
_logger = logger;
}
public string Message { get; set; } = "Hello from the PageModel!";
public void OnGet()
{
_logger.LogInformation("Index page loaded.");
}
}
}
The @page directive at the top of the .cshtml file indicates it's a Razor Page. The @model directive links the view to its PageModel. The OnGet() method in the PageModel handles GET requests for the page.
Handling Forms and Data Binding
Razor Pages simplifies form handling using model binding. You can bind form input directly to properties in your PageModel.
Example: A simple contact form
Pages/Contact.cshtml
@page
@model ContactModel
@{
ViewData["Title"] = "Contact Us";
}
<h1>@ViewData["Title"]</h1>
<form method="post">
<div class="form-group">
<label asp-for="Name"></label>
<input asp-for="Name" class="form-control" />
<span asp-validation-for="Name" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Email"></label>
<input asp-for="Email" class="form-control" />
<span asp-validation-for="Email" class="text-danger"></span>
</div>
<button type="submit" class="btn btn-primary">Send Message</button>
</form>
@if (!string.IsNullOrEmpty(Model.StatusMessage))
{
<div class="alert alert-success mt-3" role="alert">
@Model.StatusMessage
</div>
}
Pages/Contact.cshtml.cs
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using System.ComponentModel.DataAnnotations;
namespace MyWebApp.Pages
{
public class ContactModel : PageModel
{
[BindProperty]
[Required]
public string Name { get; set; }
[BindProperty]
[Required]
[EmailAddress]
public string Email { get; set; }
public string StatusMessage { get; set; }
public void OnGet()
{
// Page loaded initially
}
public IActionResult OnPost()
{
if (!ModelState.IsValid)
{
return Page(); // Re-render the page with validation errors
}
// Process the form data (e.g., send an email)
StatusMessage = $"Thank you, {Name}! Your message has been sent from {Email}.";
return Page(); // Re-render the page to show the status message
}
}
}
The [BindProperty] attribute on the model properties enables them to be bound from incoming requests. The OnPost() method handles POST requests. If the model state is valid, it processes the data and then re-renders the page.
Layouts and Partial Views
Razor Pages supports layouts and partial views, just like MVC, for sharing common UI elements like headers, footers, and navigation. The default layout is typically found in Pages/Shared/_Layout.cshtml.
You can render a partial view within a Razor Page using the <partial> tag helper:
<partial name="_MyPartialView" />
Or by rendering a view component.
Routing
By default, Razor Pages uses a file-based routing convention. The URL path maps directly to the file path within the Pages folder. For example, Pages/About.cshtml will be accessible at the /About URL.
You can customize routing using attributes like [Route] or [HttpGet], [HttpPost] on page handler methods.