Skip to content
Merged
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 45 additions & 40 deletions aspnetcore/release-notes/aspnetcore-10/includes/blazor.md
Original file line number Diff line number Diff line change
Expand Up @@ -437,49 +437,54 @@ For more information and examples, see <xref:blazor/fundamentals/routing?view=as

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

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:
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:

* 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>:
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:

```csharp
app.UseStatusCodePagesWithReExecute(
"/not-found", createScopeForStatusCodePages: true);
```
```csharp
app.UseStatusCodePagesWithReExecute(
"/not-found", createScopeForStatusCodePages: true);
```

* 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:

```razor
@code {
[CascadingParameter]
public HttpContext? HttpContext { get; set; }

private void OnNotFoundEvent(object sender, NotFoundEventArgs e)
{
// Only execute the logic if HTTP response has started,
// because setting NotFoundEventArgs.Path blocks re-execution
if (HttpContext?.Response.HasStarted == false)
{
return;
}

var type = typeof(CustomNotFoundPage);
var routeAttributes = type.GetCustomAttributes<RouteAttribute>(inherit: true);

if (routeAttributes.Length == 0)
{
throw new InvalidOperationException($"The type {type.FullName} " +
$"doesn't have a {typeof(RouteAttribute).FullName} applied.");
}

var routeAttribute = (RouteAttribute)routeAttributes[0];

if (routeAttribute.Template != null)
{
e.Path = routeAttribute.Template;
}
}
}
```
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.

`CustomRouter.razor`:

```razor
@using Microsoft.AspNetCore.Components
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Http
@implements IDisposable
@inject NavigationManager NavigationManager

@code {
protected override void OnInitialized() =>
NavigationManager.OnNotFound += OnNotFoundEvent;

[CascadingParameter]
public HttpContext? HttpContext { get; set; }

private void OnNotFoundEvent(object sender, NotFoundEventArgs e)
{
// Only execute the logic if HTTP response has started
// because setting NotFoundEventArgs.Path blocks re-execution
if (HttpContext?.Response.HasStarted == false)
{
return;
}

e.Path = GetNotFoundRoutePath();
}

// Return the path of the Not Found page that you want to display
private string GetNotFoundRoutePath()
{
...
}

public void Dispose() => NavigationManager.OnNotFound -= OnNotFoundEvent;
}
```

### Metrics and tracing

Expand Down