aspnetcore/razor-pages/index/includes/index35.md
:::moniker range="= aspnetcore-3.1"
:::moniker-end
:::moniker range="= aspnetcore-5.0"
:::moniker-end
:::moniker range="< aspnetcore-6.0"
<a name="rpvs17"></a>
See Get started with Razor Pages for detailed instructions on how to create a Razor Pages project.
Run dotnet new webapp from the command line.
See Get started with Razor Pages for detailed instructions on how to create a Razor Pages project.
Razor Pages is enabled in Startup.cs:
Consider a basic page: <a name="OnGet"></a>
The preceding code looks a lot like a Razor view file used in an ASP.NET Core app with controllers and views. What makes it different is the @page directive. @page makes the file into an MVC action - which means that it handles requests directly, without going through a controller. @page must be the first Razor directive on a page. @page affects the behavior of other Razor constructs. Razor Pages file names have a .cshtml suffix.
A similar page, using a PageModel class, is shown in the following two files. The Pages/Index2.cshtml file:
The Pages/Index2.cshtml.cs page model:
By convention, the PageModel class file has the same name as the Razor Page file with .cs appended. For example, the previous Razor Page is Pages/Index2.cshtml. The file containing the PageModel class is named Pages/Index2.cshtml.cs.
The associations of URL paths to pages are determined by the page's location in the file system. The following table shows a Razor Page path and the matching URL:
| File name and path | matching URL |
|---|---|
/Pages/Index.cshtml | / or /Index |
/Pages/Contact.cshtml | /Contact |
/Pages/Store/Contact.cshtml | /Store/Contact |
/Pages/Store/Index.cshtml | /Store or /Store/Index |
Notes:
Index is the default page when a URL doesn't include a page.Razor Pages is designed to make common patterns used with web browsers easy to implement when building an app. Model binding, Tag Helpers, and HTML helpers all just work with the properties defined in a Razor Page class. Consider a page that implements a basic "contact us" form for the Contact model:
For the samples in this document, the DbContext is initialized in the Startup.cs file.
The in memory database requires the Microsoft.EntityFrameworkCore.InMemory NuGet package.
The data model:
The db context:
The Pages/Create.cshtml view file:
The Pages/Create.cshtml.cs page model:
By convention, the PageModel class is called <PageName>Model and is in the same namespace as the page.
The PageModel class allows separation of the logic of a page from its presentation. It defines page handlers for requests sent to the page and the data used to render the page. This separation allows:
The page has an OnPostAsync handler method, which runs on POST requests (when a user posts the form). Handler methods for any HTTP verb can be added. The most common handlers are:
OnGet to initialize state needed for the page. In the preceding code, the OnGet method displays the CreateModel.cshtml Razor Page.OnPost to handle form submissions.The Async naming suffix is optional but is often used by convention for asynchronous functions. The preceding code is typical for Razor Pages.
If you're familiar with ASP.NET apps using controllers and views:
OnPostAsync code in the preceding example looks similar to typical controller code.The previous OnPostAsync method:
The basic flow of OnPostAsync:
Check for validation errors.
The Pages/Create.cshtml view file:
The rendered HTML from Pages/Create.cshtml:
In the previous code, posting the form:
With valid data:
The OnPostAsync handler method calls the xref:Microsoft.AspNetCore.Mvc.RazorPages.PageModel.RedirectToPage%2A helper method. RedirectToPage returns an instance of xref:Microsoft.AspNetCore.Mvc.RedirectToPageResult. RedirectToPage:
RedirectToAction or RedirectToRoute (used in controllers and views)./Index). RedirectToPage is detailed in the URL generation for Pages section.With validation errors that are passed to the server:
OnPostAsync handler method calls the xref:Microsoft.AspNetCore.Mvc.RazorPages.PageBase.Page%2A helper method. Page returns an instance of xref:Microsoft.AspNetCore.Mvc.RazorPages.PageResult. Returning Page is similar to how actions in controllers return View. PageResult is the default return type for a handler method. A handler method that returns void renders the page.With validation errors detected by client side validation:
The Customer property uses [BindProperty] attribute to opt in to model binding:
[BindProperty] should not be used on models containing properties that should not be changed by the client. For more information, see Overposting.
Razor Pages, by default, bind properties only with non-GET verbs. Binding to properties removes the need to writing code to convert HTTP data to the model type. Binding reduces code by using the same property to render form fields (<input asp-for="Customer.Name">) and accept the input.
Reviewing the Pages/Create.cshtml view file:
<input asp-for="Customer.Name" /> binds the HTML <input> element to the Customer.Name model expression.@addTagHelper makes Tag Helpers available.Index.cshtml is the home page:
The associated PageModel class (Index.cshtml.cs):
The Index.cshtml file contains the following markup:
The <a /a> Anchor Tag Helper used the asp-route-{value} attribute to generate a link to the Edit page. The link contains route data with the contact ID. For example, https://localhost:5001/Edit/1. Tag Helpers enable server-side code to participate in creating and rendering HTML elements in Razor files.
The Index.cshtml file contains markup to create a delete button for each customer contact:
The rendered HTML:
<button type="submit" formaction="/Customers?id=1&handler=delete">delete</button>
When the delete button is rendered in HTML, its formaction includes parameters for:
asp-route-id attribute.handler, specified by the asp-page-handler attribute.When the button is selected, a form POST request is sent to the server. By convention, the name of the handler method is selected based on the value of the handler parameter according to the scheme OnPost[handler]Async.
Because the handler is delete in this example, the OnPostDeleteAsync handler method is used to process the POST request. If the asp-page-handler is set to a different value, such as remove, a handler method with the name OnPostRemoveAsync is selected.
The OnPostDeleteAsync method:
id from the query string.FindAsync./Index).The first line contains the @page "{id:int}" directive. The routing constraint "{id:int}" tells the page to accept requests to the page that contain int route data. If a request to the page doesn't contain route data that can be converted to an int, the runtime returns an HTTP 404 (not found) error. To make the ID optional, append ? to the route constraint:
@page "{id:int?}"
The Edit.cshtml.cs file:
Validation rules:
The xref:System.ComponentModel.DataAnnotations namespace provides a set of built-in validation attributes that are applied declaratively to a class or property. DataAnnotations also contains formatting attributes like [DataType] that help with formatting and don't provide any validation.
Consider the Customer model:
Using the following Create.cshtml view file:
The preceding code:
Includes jQuery and jQuery validation scripts.
Uses the <div /> and <span /> Tag Helpers to enable:
Generates the following HTML:
Posting the Create form without a name value displays the error message "The Name field is required." on the form. If JavaScript is enabled on the client, the browser displays the error without posting to the server.
The [StringLength(10)] attribute generates data-val-length-max="10" on the rendered HTML. data-val-length-max prevents browsers from entering more than the maximum length specified. If a tool such as Fiddler is used to edit and replay the post:
Consider the following Movie model:
The validation attributes specify behavior to enforce on the model properties they're applied to:
The Required and MinimumLength attributes indicate that a property must have a value, but nothing prevents a user from entering white space to satisfy this validation.
The RegularExpression attribute is used to limit what characters can be input. In the preceding code, "Genre":
The RegularExpression "Rating":
The Range attribute constrains a value to within a specified range.
The StringLength attribute sets the maximum length of a string property, and optionally its minimum length.
Value types (such as decimal, int, float, DateTime) are inherently required and don't need the [Required] attribute.
The Create page for the Movie model shows displays errors with invalid values:
For more information, see:
HEAD requests allow retrieving the headers for a specific resource. Unlike GET requests, HEAD requests don't return a response body.
Ordinarily, an OnHead handler is created and called for HEAD requests:
Razor Pages falls back to calling the OnGet handler if no OnHead handler is defined.
<a name="xsrf"></a>
Razor Pages are protected by Antiforgery validation. The FormTagHelper injects antiforgery tokens into HTML form elements.
<a name="layout"></a>
Pages work with all the capabilities of the Razor view engine. Layouts, partials, templates, Tag Helpers, _ViewStart.cshtml, and _ViewImports.cshtml work in the same way they do for conventional Razor views.
Let's declutter this page by taking advantage of some of those capabilities.
Add a layout page to Pages/Shared/_Layout.cshtml:
The Layout:
@RenderBody() is called.For more information, see layout page.
The Layout property is set in Pages/_ViewStart.cshtml:
The layout is in the Pages/Shared folder. Pages look for other views (layouts, templates, partials) hierarchically, starting in the same folder as the current page. A layout in the Pages/Shared folder can be used from any Razor page under the Pages folder.
The layout file should go in the Pages/Shared folder.
We recommend you not put the layout file in the Views/Shared folder. Views/Shared is an MVC views pattern. Razor Pages are meant to rely on folder hierarchy, not path conventions.
View search from a Razor Page includes the Pages folder. The layouts, templates, and partials used with MVC controllers and conventional Razor views just work.
Add a Pages/_ViewImports.cshtml file:
@namespace is explained later in the tutorial. The @addTagHelper directive brings in the built-in Tag Helpers to all the pages in the Pages folder.
<a name="namespace"></a>
The @namespace directive set on a page:
The @namespace directive sets the namespace for the page. The @model directive doesn't need to include the namespace.
When the @namespace directive is contained in _ViewImports.cshtml, the specified namespace supplies the prefix for the generated namespace in the Page that imports the @namespace directive. The rest of the generated namespace (the suffix portion) is the dot-separated relative path between the folder containing _ViewImports.cshtml and the folder containing the page.
For example, the PageModel class Pages/Customers/Edit.cshtml.cs explicitly sets the namespace:
The Pages/_ViewImports.cshtml file sets the following namespace:
The generated namespace for the Pages/Customers/Edit.cshtml Razor Page is the same as the PageModel class.
@namespace also works with conventional Razor views.
Consider the Pages/Create.cshtml view file:
The updated Pages/Create.cshtml view file with _ViewImports.cshtml and the preceding layout file:
In the preceding code, the _ViewImports.cshtml imported the namespace and Tag Helpers. The layout file imported the JavaScript files.
The Razor Pages starter project contains the Pages/_ValidationScriptsPartial.cshtml, which hooks up client-side validation.
For more information on partial views, see xref:mvc/views/partial.
<a name="url_gen"></a>
The Create page, shown previously, uses RedirectToPage:
The app has the following file/folder structure:
/Pages
Index.cshtml
Privacy.cshtml
/Customers
Create.cshtmlEdit.cshtmlIndex.cshtmlThe Pages/Customers/Create.cshtml and Pages/Customers/Edit.cshtml pages redirect to Pages/Customers/Index.cshtml after success. The string ./Index is a relative page name used to access the preceding page. It is used to generate URLs to the Pages/Customers/Index.cshtml page. For example:
Url.Page("./Index", ...)<a asp-page="./Index">Customers Index Page</a>RedirectToPage("./Index")The absolute page name /Index is used to generate URLs to the Pages/Index.cshtml page. For example:
Url.Page("/Index", ...)<a asp-page="/Index">Home Index Page</a>RedirectToPage("/Index")The page name is the path to the page from the root /Pages folder including a leading / (for example, /Index). The preceding URL generation samples offer enhanced options and functional capabilities over hard-coding a URL. URL generation uses routing and can generate and encode parameters according to how the route is defined in the destination path.
URL generation for pages supports relative names. The following table shows which Index page is selected using different RedirectToPage parameters in Pages/Customers/Create.cshtml.
| RedirectToPage(x) | Page |
|---|---|
| RedirectToPage("/Index") | Pages/Index |
| RedirectToPage("./Index"); | Pages/Customers/Index |
| RedirectToPage("../Index") | Pages/Index |
| RedirectToPage("Index") | Pages/Customers/Index |
RedirectToPage("Index"), RedirectToPage("./Index"), and RedirectToPage("../Index") are relative names. The RedirectToPage parameter is combined with the path of the current page to compute the name of the destination page.
Relative name linking is useful when building sites with a complex structure. When relative names are used to link between pages in a folder:
To redirect to a page in a different Area, specify the area:
RedirectToPage("/Index", new { area = "Services" });
For more information, see xref:mvc/controllers/areas and xref:razor-pages/razor-pages-conventions.
Data can be passed to a page with xref:Microsoft.AspNetCore.Mvc.ViewDataAttribute. Properties with the [ViewData] attribute have their values stored and loaded from the xref:Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary.
In the following example, the AboutModel applies the [ViewData] attribute to the Title property:
public class AboutModel : PageModel
{
[ViewData]
public string Title { get; } = "About";
public void OnGet()
{
}
}
In the About page, access the Title property as a model property:
<h1>@Model.Title</h1>
In the layout, the title is read from the ViewData dictionary:
<!DOCTYPE html>
<html lang="en">
<head>
<title>@ViewData["Title"] - WebApplication</title>
...
ASP.NET Core exposes the xref:Microsoft.AspNetCore.Mvc.Controller.TempData. This property stores data until it's read. The xref:Microsoft.AspNetCore.Mvc.ViewFeatures.TempDataDictionary.Keep%2A and xref:Microsoft.AspNetCore.Mvc.ViewFeatures.TempDataDictionary.Peek%2A methods can be used to examine the data without deletion. TempData is useful for redirection, when data is needed for more than a single request.
The following code sets the value of Message using TempData:
The following markup in the Pages/Customers/Index.cshtml file displays the value of Message using TempData.
<h3>Msg: @Model.Message</h3>
The Pages/Customers/Index.cshtml.cs page model applies the [TempData] attribute to the Message property.
[TempData]
public string Message { get; set; }
For more information, see TempData.
<a name="mhpp"></a>
The following page generates markup for two handlers using the asp-page-handler Tag Helper:
The form in the preceding example has two submit buttons, each using the FormActionTagHelper to submit to a different URL. The asp-page-handler attribute is a companion to asp-page. asp-page-handler generates URLs that submit to each of the handler methods defined by a page. asp-page isn't specified because the sample is linking to the current page.
The page model:
The preceding code uses named handler methods. Named handler methods are created by taking the text in the name after On<HTTP Verb> and before Async (if present). In the preceding example, the page methods are OnPostJoinListAsync and OnPostJoinListUCAsync. With OnPost and Async removed, the handler names are JoinList and JoinListUC.
Using the preceding code, the URL path that submits to OnPostJoinListAsync is https://localhost:5001/Customers/CreateFATH?handler=JoinList. The URL path that submits to OnPostJoinListUCAsync is https://localhost:5001/Customers/CreateFATH?handler=JoinListUC.
Use the @page directive to:
/Some/Other/Path with @page "/Some/Other/Path".@page "item".id, can be required for a page with @page "{id}".A root-relative path designated by a tilde (~) at the beginning of the path is supported. For example, @page "~/Some/Other/Path" is the same as @page "/Some/Other/Path".
If you don't like the query string ?handler=JoinList in the URL, change the route to put the handler name in the path portion of the URL. The route can be customized by adding a route template enclosed in double quotes after the @page directive.
Using the preceding code, the URL path that submits to OnPostJoinListAsync is https://localhost:5001/Customers/CreateFATH/JoinList. The URL path that submits to OnPostJoinListUCAsync is https://localhost:5001/Customers/CreateFATH/JoinListUC.
The ? following handler means the route parameter is optional.
The configuration and settings in following sections is not required by most apps.
To configure advanced options, use the xref:Microsoft.Extensions.DependencyInjection.MvcServiceCollectionExtensions.AddRazorPages%2A overload that configures xref:Microsoft.AspNetCore.Mvc.RazorPages.RazorPagesOptions:
Use the xref:Microsoft.AspNetCore.Mvc.RazorPages.RazorPagesOptions to set the root directory for pages, or add application model conventions for pages. For more information on conventions, see Razor Pages authorization conventions.
To precompile views, see Razor view compilation.
By default, Razor Pages are rooted in the /Pages directory. Add xref:Microsoft.Extensions.DependencyInjection.MvcRazorPagesMvcBuilderExtensions.WithRazorPagesAtContentRoot%2A to specify that your Razor Pages are at the content root (xref:Microsoft.AspNetCore.Hosting.IHostingEnvironment.ContentRootPath) of the app:
Add xref:Microsoft.Extensions.DependencyInjection.MvcRazorPagesMvcCoreBuilderExtensions.WithRazorPagesRoot%2A to specify that Razor Pages are at a custom root directory in the app (provide a relative path):
[Authorize] attribute in Razor Pages apps:::moniker-end