Skip to content

Commit ca5329b

Browse files
authored
[10.0] Update the Blazor movie dB tutorial (#36344)
1 parent 7fa37ec commit ca5329b

File tree

4 files changed

+112
-6
lines changed

4 files changed

+112
-6
lines changed

aspnetcore/blazor/project-structure.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ Based on the interactive render mode selected at app creation, the `Layout` fold
4242
* The `NavMenu.razor.css` is the collocated stylesheet for the app's navigation menu.
4343
* The `ReconnectModal` component reflects the server-side connection state in the UI and is included when the app's interactive render mode is either Interactive Server or Interactive Auto. For more information, see <xref:blazor/fundamentals/signalr#reflect-the-server-side-connection-state-in-the-ui>.
4444
* The `ReconnectModal.razor.css` is the collocated stylesheet for the `ReconnectModal` component.
45-
* The `ReconnectModal.razor.css` is the collocated JavaScript file for the `ReconnectModal` component.
45+
* The `ReconnectModal.razor.js` is the collocated JavaScript file for the `ReconnectModal` component.
4646

4747
:::moniker-end
4848

aspnetcore/blazor/tutorials/movie-database-app/part-1.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,9 @@ The `Components/Layout` folder contains the following layout components and styl
231231
* `MainLayout.razor.css`: Stylesheet for the app's main layout.
232232
* `NavMenu` component (`NavMenu.razor`): Implements sidebar navigation. This component uses several `NavLink` components to render navigation links to other Razor components.
233233
* `NavMenu.razor.css`: Stylesheet for the app's navigation menu.
234+
* `ReconnectModal` component (`ReconnectModal.razor`): Reflects the server-side connection state in the UI.
235+
* `ReconnectModal.razor.css`: Stylesheet for the `ReconnectModal` component.
236+
* `ReconnectModal.razor.js`: JavaScript file for the `ReconnectModal` component.
234237

235238
### `Components/_Imports.razor` file
236239

aspnetcore/blazor/tutorials/movie-database-app/part-3.md

Lines changed: 65 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -421,13 +421,31 @@ The `movie` variable is a private field of type `Movie`, which is a null-referen
421421

422422
The `Id` is a *component parameter* supplied from the component's query string due to the presence of the [`[SupplyParameterFromQuery]` attribute](xref:Microsoft.AspNetCore.Components.SupplyParameterFromQueryAttribute). If the identifier is missing, `Id` defaults to zero (`0`).
423423

424-
`OnInitializedAsync` is the first component lifecycle method that we've seen. This method is executed when the component loads. <xref:Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.FirstOrDefaultAsync%2A> is called on the database set (`DbSet<Movie>`) to retrieve the movie entity with and `Id` equal to the `Id` parameter that was set by the query string. If `movie` is `null`, <xref:Microsoft.AspNetCore.Components.NavigationManager.NavigateTo%2A?displayProperty=nameWithType> is used to navigate to a `notfound` endpoint.
424+
`OnInitializedAsync` is the first component lifecycle method that we've seen. This method is executed when the component loads. <xref:Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.FirstOrDefaultAsync%2A> is called on the database set (`DbSet<Movie>`) to retrieve the movie entity with an `Id` equal to the `Id` parameter that was set by the query string. If `movie` is `null`, <xref:Microsoft.AspNetCore.Components.NavigationManager.NavigateTo%2A?displayProperty=nameWithType> is used to navigate to a `notfound` endpoint.
425425

426-
<!-- UPDATE 10.0 - See https://github.com/dotnet/aspnetcore/issues/45654
427-
for .NET 10 work on handling a 404 with static SSR without \
428-
having to navigate to a non-existent endpoint. -->
426+
<!-- UPDATE 10.0 - Update for scaffolder changes when they
427+
appear: https://github.com/dotnet/Scaffolding/issues/3177 -->
429428

430-
There isn't an actual `notfound` endpoint (Razor component) in the app. When adopting server-side rendering (SSR), Blazor doesn't have a mechanism to return a 404 (Not Found) status code. As a temporary workaround, a 404 is generated by navigating to a non-existent endpoint. This scaffolded code is for your further implementation of a suitable result when not finding an entity. For example, you could have the component direct the user to a page where they can file an inquiry with your support team, or you could remove the injected <xref:Microsoft.AspNetCore.Components.NavigationManager> and <xref:Microsoft.AspNetCore.Components.NavigationManager.NavigateTo%2A?displayProperty=nameWithType> code and replace it with Razor markup and code that displays a message to the user that the entity wasn't found.
429+
:::moniker range=">= aspnetcore-10.0"
430+
431+
The .NET scaffolder currently doesn't implement .NET 10's Not Found feature, but it can be implemented manually.
432+
433+
Update the line that navigates to a non-existent `notfound` endpoint. Change the line to call <xref:Microsoft.AspNetCore.Components.NavigationManager.NotFound%2A?displayProperty=nameWithType>:
434+
435+
```diff
436+
- NavigationManager.NavigateTo("notfound");
437+
+ NavigationManager.NotFound();
438+
```
439+
440+
When a movie isn't found, this line change results in rendering the `NotFound` component, which produces a Not Found page in the browser with a 404 (Not Found) status code.
441+
442+
:::moniker-end
443+
444+
:::moniker range="< aspnetcore-10.0"
445+
446+
There isn't an actual `notfound` endpoint (Razor component) in the app. When adopting server-side rendering (SSR) in .NET 8 or .NET 9, the app doesn't have a mechanism to return a 404 (Not Found) status code. A 404 is generated by navigating to a non-existent endpoint. This scaffolded code is for your further implementation of a suitable result when not finding an entity in .NET 8/9. For example, you could have the component direct the user to a page where they can file an inquiry with your support team, or you could remove the injected <xref:Microsoft.AspNetCore.Components.NavigationManager> and <xref:Microsoft.AspNetCore.Components.NavigationManager.NavigateTo%2A?displayProperty=nameWithType> code and replace it with Razor markup and code that displays a message to the user that the entity wasn't found. In .NET 10 or later, Blazor has a built-in Not Found feature. For more information, see the [.NET 10 version of this section](?view=aspnetcore-10.0&pivots=vs&preserve-view=true#details-component).
447+
448+
:::moniker-end
431449

432450
### `Create` component
433451

@@ -540,6 +558,24 @@ private async Task DeleteMovie()
540558
}
541559
```
542560

561+
<!-- UPDATE 10.0 - Update for scaffolder changes when they
562+
appear: https://github.com/dotnet/Scaffolding/issues/3177 -->
563+
564+
:::moniker range=">= aspnetcore-10.0"
565+
566+
The .NET scaffolder currently doesn't implement .NET 10's Not Found feature, but it can be implemented manually.
567+
568+
Update the line that navigates to a non-existent `notfound` endpoint. Change the line to call <xref:Microsoft.AspNetCore.Components.NavigationManager.NotFound%2A?displayProperty=nameWithType>:
569+
570+
```diff
571+
- NavigationManager.NavigateTo("notfound");
572+
+ NavigationManager.NotFound();
573+
```
574+
575+
When a movie isn't found, this line change results in rendering the `NotFound` component, which produces a Not Found page in the browser with a 404 (Not Found) status code.
576+
577+
:::moniker-end
578+
543579
### `Edit` component
544580

545581
Open the `Edit` component definition file (`Components/Pages/Movies/Edit.razor`).
@@ -595,8 +631,32 @@ private bool MovieExists(int id)
595631

596632
The movie entity's <xref:Microsoft.EntityFrameworkCore.EntityState> is set to <xref:Microsoft.EntityFrameworkCore.EntityState.Modified>, which signifies that the entity is tracked by the context, exists in the database, and that some or all of its property values are modified.
597633

634+
<!-- UPDATE 10.0 - Update for scaffolder changes when they
635+
appear: https://github.com/dotnet/Scaffolding/issues/3177 -->
636+
637+
:::moniker range=">= aspnetcore-10.0"
638+
639+
The .NET scaffolder currently doesn't implement .NET 10's Not Found feature, but it can be implemented manually.
640+
641+
Update the line that navigates to a non-existent `notfound` endpoint. Change the line to call <xref:Microsoft.AspNetCore.Components.NavigationManager.NotFound%2A?displayProperty=nameWithType>:
642+
643+
```diff
644+
- NavigationManager.NavigateTo("notfound");
645+
+ NavigationManager.NotFound();
646+
```
647+
648+
When a movie isn't found, this line change results in rendering the `NotFound` component, which produces a Not Found page in the browser with a 404 (Not Found) status code.
649+
650+
If there's a concurrency exception and the movie entity no longer exists at the time that changes are saved, the component redirects to the Not Found page, which results in returning a 404 (Not Found) status code. If the movie exists and a concurrency exception is thrown, for example when another user has already modified the entity, the exception is rethrown by the component with the [`throw` statement (C# Language Reference)](/dotnet/csharp/language-reference/statements/exception-handling-statements#the-throw-statement). Additional guidance on handling concurrency with EF Core in Blazor apps is provided by the Blazor documentation.
651+
652+
:::moniker-end
653+
654+
:::moniker range="< aspnetcore-10.0"
655+
598656
If there's a concurrency exception and the movie entity no longer exists at the time that changes are saved, the component redirects to the non-existent endpoint (`notfound`), which results in returning a 404 (Not Found) status code. You could change this code to notify the user that the movie no longer exists in the database or create a dedicated *Not Found* component and navigate the user to that endpoint. If the movie exists and a concurrency exception is thrown, for example when another user has already modified the entity, the exception is rethrown by the component with the [`throw` statement (C# Language Reference)](/dotnet/csharp/language-reference/statements/exception-handling-statements#the-throw-statement). Additional guidance on handling concurrency with EF Core in Blazor apps is provided by the Blazor documentation.
599657

658+
:::moniker-end
659+
600660
> [!WARNING]
601661
> Although it isn't a concern for the app in this tutorial, binding form data to entity data models can be susceptible to overposting attacks. Additional information on this subject appears in the next section.
602662

aspnetcore/blazor/tutorials/movie-database-app/part-4.md

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,47 @@ If the model state has errors when the form is posted, for example if `ReleaseDa
286286

287287
Review the `UpdateMovie` method of the `Edit` component (`Components/Pages/MoviePages/Edit.razor`):
288288

289+
:::moniker range=">= aspnetcore-10.0"
290+
291+
```csharp
292+
private async Task UpdateMovie()
293+
{
294+
using var context = DbFactory.CreateDbContext();
295+
context.Attach(Movie!).State = EntityState.Modified;
296+
297+
try
298+
{
299+
await context.SaveChangesAsync();
300+
}
301+
catch (DbUpdateConcurrencyException)
302+
{
303+
if (!MovieExists(Movie!.Id))
304+
{
305+
NavigationManager.NotFound();
306+
}
307+
else
308+
{
309+
throw;
310+
}
311+
}
312+
313+
NavigationManager.NavigateTo("/movies");
314+
}
315+
```
316+
317+
Concurrency exceptions are detected when one client deletes the movie and a different client posts changes to the movie.
318+
319+
To test how concurrency is handled by the preceding code:
320+
321+
1. Select **:::no-loc text="Edit":::** for a movie, make changes, but don't select **:::no-loc text="Save":::**.
322+
1. In a different browser window, open the app to the movie `Index` page and select the **:::no-loc text="Delete":::** link for the same movie to delete the movie.
323+
1. In the previous browser window, post changes to the movie by selecting the **:::no-loc text="Save":::** button.
324+
1. The browser is navigated to the Not Found page with a 404 (Not Found) status code.
325+
326+
:::moniker-end
327+
328+
:::moniker range="< aspnetcore-10.0"
329+
289330
```csharp
290331
private async Task UpdateMovie()
291332
{
@@ -321,6 +362,8 @@ To test how concurrency is handled by the preceding code:
321362
1. In the previous browser window, post changes to the movie by selecting the **:::no-loc text="Save":::** button.
322363
1. The browser is navigated to the `notfound` endpoint, which doesn't exist and yields a 404 (Not Found) result.
323364

365+
:::moniker-end
366+
324367
Additional guidance on handling concurrency with EF Core in Blazor apps is available in the Blazor documentation.
325368

326369
## Stop the app

0 commit comments

Comments
 (0)