title | author | description | ms.author | ms.date | uid |
---|---|---|---|---|---|
Part 5, update the generated pages |
wadepickett |
Part 5 of tutorial series on Razor Pages. |
wpickett |
06/23/2024 |
tutorials/razor-pages/da1 |
:::moniker range=">= aspnetcore-9.0"
The scaffolded movie app has a good start, but the presentation isn't ideal. ReleaseDate should be two words, Release Date.
Update Models/Movie.cs
with the following highlighted code:
[!code-csharpMain]
In the previous code:
- The
[Column(TypeName = "decimal(18, 2)")]
data annotation enables Entity Framework Core to correctly mapPrice
to currency in the database. For more information, see Data Types. - The [Display] attribute specifies the display name of a field. In the preceding code,
Release Date
instead ofReleaseDate
. - The [DataType] attribute specifies the type of the data (
Date
). The time information stored in the field isn't displayed.
DataAnnotations is covered in the next tutorial.
Browse to Pages/Movies and hover over an Edit link to see the target URL.
The Edit, Details, and Delete links are generated by the Anchor Tag Helper in the Pages/Movies/Index.cshtml
file.
Tag Helpers enable server-side code to participate in creating and rendering HTML elements in Razor files.
In the preceding code, the Anchor Tag Helper dynamically generates the HTML href
attribute value from the Razor Page (the route is relative), the asp-page
, and the route identifier (asp-route-id
). For more information, see URL generation for Pages.
Use View Source from a browser to examine the generated markup. A portion of the generated HTML is shown below:
<td>
<a href="/Movies/Edit?id=1">Edit</a> |
<a href="/Movies/Details?id=1">Details</a> |
<a href="/Movies/Delete?id=1">Delete</a>
</td>
The dynamically generated links pass the movie ID with a query string. For example, the ?id=1
in https://localhost:5001/Movies/Details?id=1
.
Update the Edit, Details, and Delete Razor Pages to use the {id:int}
route template. Change the page directive for each of these pages from @page
to @page "{id:int}"
. Run the app and then view source.
The generated HTML adds the ID to the path portion of the URL:
<td>
<a href="/Movies/Edit/1">Edit</a> |
<a href="/Movies/Details/1">Details</a> |
<a href="/Movies/Delete/1">Delete</a>
</td>
A request to the page with the {id:int}
route template that does not include the integer returns an HTTP 404 (not found) error. For example, https://localhost:5001/Movies/Details
returns a 404 error. To make the ID optional, append ?
to the route constraint:
@page "{id:int?}"
Test the behavior of @page "{id:int?}"
:
- Set the page directive in
Pages/Movies/Details.cshtml
to@page "{id:int?}"
. - Set a break point in
public async Task<IActionResult> OnGetAsync(int? id)
, inPages/Movies/Details.cshtml.cs
. - Navigate to
https://localhost:5001/Movies/Details/
.
With the @page "{id:int}"
directive, the break point is never hit. The routing engine returns HTTP 404. Using @page "{id:int?}"
, the OnGetAsync
method returns NotFound
(HTTP 404):
Review the OnPostAsync
method in the Pages/Movies/Edit.cshtml.cs
file:
The previous code detects concurrency exceptions when one client deletes the movie and the other client posts changes to the movie.
To test the catch
block:
- Set a breakpoint on
catch (DbUpdateConcurrencyException)
. - Select Edit for a movie, make changes, but don't enter Save.
- In another browser window, select the Delete link for the same movie, and then delete the movie.
- In the previous browser window, post changes to the movie.
Production code may want to detect concurrency conflicts. See Handle concurrency conflicts for more information.
Examine the Pages/Movies/Edit.cshtml.cs
file:
When an HTTP GET request is made to the Movies/Edit page, for example, https://localhost:5001/Movies/Edit/3
:
- The
OnGetAsync
method fetches the movie from the database and returns thePage
method. - The
Page
method renders thePages/Movies/Edit.cshtml
Razor Page. ThePages/Movies/Edit.cshtml
file contains the model directive@model RazorPagesMovie.Pages.Movies.EditModel
, which makes the movie model available on the page. - The Edit form is displayed with the values from the movie.
When the Movies/Edit page is posted:
-
The form values on the page are bound to the
Movie
property. The[BindProperty]
attribute enables Model binding.[BindProperty] public Movie Movie { get; set; }
-
If there are errors in the model state, for example,
ReleaseDate
cannot be converted to a date, the form is redisplayed with the submitted values. -
If there are no model errors, the movie is saved.
The HTTP GET methods in the Index, Create, and Delete Razor pages follow a similar pattern. The HTTP POST OnPostAsync
method in the Create Razor Page follows a similar pattern to the OnPostAsync
method in the Edit Razor Page.
[!div class="step-by-step"] Previous: Work with a database Next: Add search
:::moniker-end