Skip to content

Commit d25d66b

Browse files
authored
Enhance Blazor Not Found responses documentation (#36224)
1 parent a215a83 commit d25d66b

File tree

1 file changed

+47
-40
lines changed
  • aspnetcore/release-notes/aspnetcore-10/includes

1 file changed

+47
-40
lines changed

aspnetcore/release-notes/aspnetcore-10/includes/blazor.md

Lines changed: 47 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -437,49 +437,56 @@ For more information and examples, see <xref:blazor/fundamentals/routing?view=as
437437

438438
### Support for Not Found responses in apps without Blazor's router
439439

440-
Apps that implement a custom router can use `NavigationManager.NotFound`. The custom router can render Not Found content from two sources, depending on the state of the response:
440+
Apps that implement a custom router can use `NavigationManager.NotFound`. There are two ways to inform the renderer what page should be rendered when `NavigationManager.NotFound` is called:
441441

442-
* Regardless of the response state, the re-execution path to the page can used by passing it to <xref:Microsoft.AspNetCore.Builder.StatusCodePagesExtensions.UseStatusCodePagesWithReExecute%2A>:
442+
The recommended approach that works regardless of the response state is to call <xref:Microsoft.AspNetCore.Builder.StatusCodePagesExtensions.UseStatusCodePagesWithReExecute%2A>. When `NavigationManager.NotFound` is called, the middleware renders the path passed to the method:
443443

444-
```csharp
445-
app.UseStatusCodePagesWithReExecute(
446-
"/not-found", createScopeForStatusCodePages: true);
447-
```
444+
```csharp
445+
app.UseStatusCodePagesWithReExecute(
446+
"/not-found", createScopeForStatusCodePages: true);
447+
```
448448

449-
* When the response has started, the <xref:Microsoft.AspNetCore.Components.Routing.NotFoundEventArgs.Path%2A?displayProperty=nameWithType> can be used by subscribing to the `OnNotFoundEvent` in the router:
450-
451-
```razor
452-
@code {
453-
[CascadingParameter]
454-
public HttpContext? HttpContext { get; set; }
455-
456-
private void OnNotFoundEvent(object sender, NotFoundEventArgs e)
457-
{
458-
// Only execute the logic if HTTP response has started,
459-
// because setting NotFoundEventArgs.Path blocks re-execution
460-
if (HttpContext?.Response.HasStarted == false)
461-
{
462-
return;
463-
}
464-
465-
var type = typeof(CustomNotFoundPage);
466-
var routeAttributes = type.GetCustomAttributes<RouteAttribute>(inherit: true);
467-
468-
if (routeAttributes.Length == 0)
469-
{
470-
throw new InvalidOperationException($"The type {type.FullName} " +
471-
$"doesn't have a {typeof(RouteAttribute).FullName} applied.");
472-
}
473-
474-
var routeAttribute = (RouteAttribute)routeAttributes[0];
475-
476-
if (routeAttribute.Template != null)
477-
{
478-
e.Path = routeAttribute.Template;
479-
}
480-
}
481-
}
482-
```
449+
If you don't want to use <xref:Microsoft.AspNetCore.Builder.StatusCodePagesExtensions.UseStatusCodePagesWithReExecute%2A>, the app can still support `NavigationManager.NotFound` for responses that have already started. Subscribe to `OnNotFoundEvent` in the router and assign the Not Found page path to `NotFoundEventArgs.Path` to inform the renderer what content to render when `NavigationManager.NotFound` is called.
450+
451+
`CustomRouter.razor`:
452+
453+
```razor
454+
@using Microsoft.AspNetCore.Components
455+
@using Microsoft.AspNetCore.Components.Routing
456+
@using Microsoft.AspNetCore.Http
457+
@implements IDisposable
458+
@inject NavigationManager NavigationManager
459+
460+
@code {
461+
protected override void OnInitialized() =>
462+
NavigationManager.OnNotFound += OnNotFoundEvent;
463+
464+
[CascadingParameter]
465+
public HttpContext? HttpContext { get; set; }
466+
467+
private void OnNotFoundEvent(object sender, NotFoundEventArgs e)
468+
{
469+
// Only execute the logic if HTTP response has started
470+
// because setting NotFoundEventArgs.Path blocks re-execution
471+
if (HttpContext?.Response.HasStarted == false)
472+
{
473+
return;
474+
}
475+
476+
e.Path = GetNotFoundRoutePath();
477+
}
478+
479+
// Return the path of the Not Found page that you want to display
480+
private string GetNotFoundRoutePath()
481+
{
482+
...
483+
}
484+
485+
public void Dispose() => NavigationManager.OnNotFound -= OnNotFoundEvent;
486+
}
487+
```
488+
489+
If you use both approaches in your app, the Not Found path specified in the `OnNotFoundEvent` handler takes precedence over the path configured in the re-execution middleware.
483490

484491
### Metrics and tracing
485492

0 commit comments

Comments
 (0)