Back to Aspnetcore

Part 3, scaffolded Razor Pages

aspnetcore/tutorials/razor-pages/page.md

latest11.8 KB
Original Source

Part 3, scaffolded Razor Pages in ASP.NET Core

[!INCLUDE]

By Rick Anderson

This tutorial examines the Razor Pages created by scaffolding in the previous tutorial.

:::moniker range=">= aspnetcore-10.0"

The Create, Delete, Details, and Edit pages

Examine the Pages/Movies/Index.cshtml.cs Page Model:

[!code-csharp]

Razor Pages derive from xref:Microsoft.AspNetCore.Mvc.RazorPages.PageModel. By convention, the PageModel derived class is named PageNameModel. For example, the Index page is named IndexModel.

The constructor uses dependency injection to add the RazorPagesMovieContext to the page:

[!code-csharp]

For more information on asynchronous programming with Entity Framework, see Asynchronous code.

When a GET request is made for the page, the OnGetAsync method returns a list of movies to the Razor Page. On a Razor Page, OnGetAsync or OnGet is called to initialize the state of the page. In this case, OnGetAsync gets a list of movies and displays them.

When OnGet returns void or OnGetAsync returns Task, don't use a return statement. For example, examine the Privacy Page:

[!code-csharp]

When the return type is xref:Microsoft.AspNetCore.Mvc.IActionResult or Task<IActionResult>, you must provide a return statement. For example, the Pages/Movies/Create.cshtml.cs OnPostAsync method:

[!code-csharp]

Examine the Pages/Movies/Index.cshtml Razor Page:

[!code-cshtml]

Razor can transition from HTML into C# or into Razor-specific markup. When an @ symbol is followed by a Razor reserved keyword, it transitions into Razor-specific markup. Otherwise, it transitions into C#.

The @page directive

The @page Razor directive makes the file an MVC action, which means that it can handle requests. @page must be the first Razor directive on a page. @page and @model are examples of transitioning into Razor-specific markup. For more information, see Razor syntax.

The @model directive

[!code-cshtml]

The @model directive specifies the type of the model passed to the Razor Page. In the preceding example, the @model line makes the PageModel derived class available to the Razor Page. The model is used in the @Html.DisplayNameFor and @Html.DisplayFor HTML Helpers on the page.

Examine the lambda expression used in the following HTML Helper:

cshtml
@Html.DisplayNameFor(model => model.Movie[0].Title)

The xref:Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper%601.DisplayNameFor%2A HTML Helper inspects the Title property referenced in the lambda expression to determine the display name. The lambda expression is inspected rather than evaluated. That means there's no access violation when model, model.Movie, or model.Movie[0] is null or empty. When the lambda expression is evaluated, for example, by using @Html.DisplayFor(modelItem => item.Title), the model's property values are evaluated.

The layout page

Select the menu links RazorPagesMovie, Home, and Privacy. Each page shows the same menu layout. The Pages/Shared/_Layout.cshtml file implements the menu layout.

Open and examine the Pages/Shared/_Layout.cshtml file.

Layout templates let you:

  • Specify the HTML container layout in one place.
  • Apply the layout to multiple pages in the site.

Find the @RenderBody() line. RenderBody is a placeholder where all the page-specific views appear, wrapped in the layout page. For example, when you select the Privacy link, the Pages/Privacy.cshtml view renders inside the RenderBody method.

ViewData and layout

Consider the following markup from the Pages/Movies/Index.cshtml file:

[!code-cshtml]

The preceding highlighted markup is an example of Razor transitioning into C#. The { and } characters enclose a block of C# code.

The PageModel base class contains a ViewData dictionary property that you can use to pass data to a view. Add objects to the ViewData dictionary by using a key value pattern. In the preceding sample, the Title property is added to the ViewData dictionary.

The Title property is used in the Pages/Shared/_Layout.cshtml file. The following markup shows the first few lines of the _Layout.cshtml file.

<!-- We need a snapshot copy of layout because we are changing in the next step. -->

[!code-cshtml]

Update the layout

  1. Change the <title> element in the Pages/Shared/_Layout.cshtml file to display Movie rather than RazorPagesMovie. [!code-cshtml]

  2. Find the following anchor element in the Pages/Shared/_Layout.cshtml file.

    cshtml
    <a class="navbar-brand" asp-area="" asp-page="/Index">RazorPagesMovie</a>
    
  3. Replace the preceding element with the following markup:

    cshtml
    <a class="navbar-brand" asp-page="/Movies/Index">RpMovie</a>
    

    The preceding anchor element is a Tag Helper. In this case, it's the Anchor Tag Helper. The asp-page="/Movies/Index" Tag Helper attribute and value creates a link to the /Movies/Index Razor Page. The asp-area attribute value is empty, so the area isn't used in the link. See Areas for more information.

  4. Save the changes and test the app by selecting the RpMovie link. See the _Layout.cshtml file in GitHub if you have any problems.

  5. Test the Home, RpMovie, Create, Edit, and Delete links. Each page sets the title, which you can see in the browser tab. When you bookmark a page, the title is used for the bookmark.

[!NOTE] You may not be able to enter decimal commas in the Price field. To support jQuery validation for non-English locales that use a comma (",") for a decimal point, and non US-English date formats, you must take steps to globalize the app. See this GitHub issue 4076 for instructions on adding decimal comma.

The Layout property is set in the Pages/_ViewStart.cshtml file:

[!code-cshtml]

The preceding markup sets the layout file to Pages/Shared/_Layout.cshtml for all Razor files under the Pages folder. See Layout for more information.

The Create page model

Examine the Pages/Movies/Create.cshtml.cs page model:

[!code-csharp]

The OnGet method initializes any state needed for the page. The Create page doesn't have any state to initialize, so Page is returned. Later in the tutorial, an example of OnGet initializing state is shown. The Page method creates a PageResult object that renders the Create.cshtml page.

The Movie property uses the [BindProperty] attribute to opt-in to model binding. When the Create form posts the form values, the ASP.NET Core runtime binds the posted values to the Movie model.

The OnPostAsync method runs when the page posts form data:

[!code-csharp]

If there are any model errors, the form is redisplayed, along with any form data posted. Most model errors are caught on the client before the form is posted. An example of a model error is posting a value for the date field that can't be converted to a date. Client-side validation and model validation are discussed later in the tutorial.

If there are no model errors:

  • The data is saved.
  • The browser is redirected to the Index page.

The Create Razor Page

Examine the Pages/Movies/Create.cshtml Razor Page file:

[!code-cshtml]

Visual Studio

Visual Studio displays the following tags in a distinctive bold font used for Tag Helpers:

  • <form method="post">
  • <div asp-validation-summary="ModelOnly" class="text-danger"></div>
  • <label asp-for="Movie.Title" class="control-label"></label>
  • <input asp-for="Movie.Title" class="form-control" />
  • <span asp-validation-for="Movie.Title" class="text-danger"></span>

:::image type="content" source="~/tutorials/razor-pages/page/media/tag-helpers-vs2026.png" alt-text="Visual Studio view of Create.cshtml page showing Tag Helper highlighting.":::


The <form method="post"> element is a Form Tag Helper. The Form Tag Helper automatically includes an antiforgery token.

The scaffolding engine creates Razor markup for each field in the model, except the ID, similar to the following code:

[!code-cshtml]

The Validation Tag Helpers (<div asp-validation-summary and <span asp-validation-for) display validation errors. Validation is covered in more detail later in this series.

The Label Tag Helper (<label asp-for="Movie.Title" class="control-label"></label>) generates the label caption and [for] attribute for the Title property.

The Input Tag Helper (<input asp-for="Movie.Title" class="form-control">) uses the DataAnnotations attributes and produces HTML attributes needed for jQuery Validation on the client side.

For more information on Tag Helpers such as <form method="post">, see Tag Helpers in ASP.NET Core.

Next steps

[!div class="step-by-step"] Previous: Add a model Next: Work with a database

:::moniker-end

[!INCLUDE]

[!INCLUDE]

[!INCLUDE]

[!INCLUDE]

[!INCLUDE]