Skip to content
32 changes: 25 additions & 7 deletions aspnetcore/blazor/fundamentals/signalr.md
Original file line number Diff line number Diff line change
Expand Up @@ -316,25 +316,43 @@ app.MapBlazorHub(options =>
});
```

<!-- UPDATE 10.0 The following is scheduled for a fix in .NET 10 -->
<!-- UPDATE 10.0 - The following is scheduled for a fix in .NET 10.
Tracked by: https://github.com/dotnet/aspnetcore/issues/63520 -->

Configuring the hub used by <xref:Microsoft.AspNetCore.Builder.ServerRazorComponentsEndpointConventionBuilderExtensions.AddInteractiveServerRenderMode%2A> with <xref:Microsoft.AspNetCore.Builder.ComponentEndpointRouteBuilderExtensions.MapBlazorHub%2A> fails with an `AmbiguousMatchException`:
Configuring the hub used by <xref:Microsoft.AspNetCore.Builder.ServerRazorComponentsEndpointConventionBuilderExtensions.AddInteractiveServerRenderMode%2A> with <xref:Microsoft.AspNetCore.Builder.ComponentEndpointRouteBuilderExtensions.MapBlazorHub%2A> fails with an <xref:System.Reflection.AmbiguousMatchException>:

> :::no-loc text="Microsoft.AspNetCore.Routing.Matching.AmbiguousMatchException: The request matched multiple endpoints.":::

To workaround the problem for apps targeting .NET 8, give the custom-configured Blazor hub higher precedence using the <xref:Microsoft.AspNetCore.Builder.RoutingEndpointConventionBuilderExtensions.WithOrder%2A> method:
To workaround the problem for apps targeting .NET 8/9, take the following approach.

At the top of the `Program` file, add a `using` statement for <xref:Microsoft.AspNetCore.Http.Connections?displayProperty=fullName>:

```csharp
app.MapBlazorHub(options =>
{
options.CloseOnAuthenticationExpiration = true;
}).WithOrder(-1);
using Microsoft.AspNetCore.Http.Connections;
```

Where <xref:Microsoft.AspNetCore.Builder.RazorComponentsEndpointRouteBuilderExtensions.MapRazorComponents%2A> is called, chain the following endpoint convention to the <xref:Microsoft.AspNetCore.Builder.RazorComponentsEndpointConventionBuilder>:

```csharp
app.MapRazorComponents<App>()
.AddInteractiveServerRenderMode()
.Add(e =>
{
var metadata = e.Metadata;
var dispatcherOptions = metadata.OfType<HttpConnectionDispatcherOptions>().FirstOrDefault();

if (dispatcherOptions != null)
{
dispatcherOptions.CloseOnAuthenticationExpiration = true;
}
});
```

For more information, see the following resources:

* [MapBlazorHub configuration in NET8 throws a The request matched multiple endpoints exception (`dotnet/aspnetcore` #51698)](https://github.com/dotnet/aspnetcore/issues/51698#issuecomment-1984340954)
* [Attempts to map multiple blazor entry points with MapBlazorHub causes Ambiguous Route Error. This worked with net7 (`dotnet/aspnetcore` #52156)](https://github.com/dotnet/aspnetcore/issues/52156#issuecomment-1984503178)
* [[Blazor] Provide access to the underlying SignalR HttpConnectionDispatcherOptions in AddInteractiveServerRenderMode (`dotnet/aspnetcore` #63520)](https://github.com/dotnet/aspnetcore/issues/63520)

:::moniker-end

Expand Down
25 changes: 25 additions & 0 deletions aspnetcore/blazor/security/includes/redirecttologin-component.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,29 @@ The `RedirectToLogin` component (`RedirectToLogin.razor`):

Inspect the `RedirectToLogin` component in [reference source](https://github.com/dotnet/aspnetcore/tree/main/src/ProjectTemplates/Web.ProjectTemplates/content/ComponentsWebAssembly-CSharp). The location of the component changed over time, so use GitHub search tools to locate the component.

The login path can be customized by the app (<xref:Microsoft.AspNetCore.Components.WebAssembly.Authentication.RemoteAuthenticationApplicationPathsOptions.LogInPath%2A?displayProperty=nameWithType>, [framework defaults (`dotnet/aspnetcore` reference source)](https://github.com/dotnet/aspnetcore/blob/main/src/Components/WebAssembly/WebAssembly.Authentication/src/RemoteAuthenticationDefaults.cs)). The project template's `RedirectToLogin` component uses the default login path of `authentication/login`.

[!INCLUDE[](~/includes/aspnetcore-repo-ref-source-links.md)]

If an app [customizes the login path](xref:blazor/security/webassembly/additional-scenarios#customize-app-routes), take either of the following approaches:

* Match the path in the hard-coded string in the `RedirectToLogin` component.
* Inject <xref:Microsoft.AspNetCore.Builder.RemoteAuthenticationOptions> to obtain the configured value. For example, take this approach when you customize the path with <xref:Microsoft.Extensions.DependencyInjection.WebAssemblyAuthenticationServiceCollectionExtensions.AddApiAuthorization%2A>.
Add the following directives at the top of the `RedirectToLogin` component:

```razor
@using Microsoft.Extensions.Options
@inject IOptionsSnapshot<RemoteAuthenticationOptions<ApiAuthorizationProviderOptions>> RemoteOptions
```

Modify the component's redirect in the `OnInitialized` method:

```diff
- Navigation.NavigateToLogin("authentication/login");
+ Navigation.NavigateToLogin(RemoteOptions.Get(Options.DefaultName)
+ .AuthenticationPaths.LogInPath);
```

> [!NOTE]
> If other paths differ from the project template's paths or [framework's default paths](https://github.com/dotnet/aspnetcore/blob/main/src/Components/WebAssembly/WebAssembly.Authentication/src/RemoteAuthenticationDefaults.cs), they should managed in the same fashion.

4 changes: 3 additions & 1 deletion aspnetcore/fundamentals/error-handling.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ uid: fundamentals/error-handling

[!INCLUDE[](~/includes/not-latest-version.md)]

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

This article covers common approaches to handling errors in ASP.NET Core web apps. See also <xref:fundamentals/error-handling-api>.

Expand Down Expand Up @@ -343,8 +343,10 @@ An alternative approach to generate problem details is to use the third-party Nu
* <xref:test/troubleshoot-azure-iis>
* <xref:host-and-deploy/azure-iis-errors-reference>
* <xref:fundamentals/error-handling-api>
* [Breaking change: Exception diagnostics are suppressed when `IExceptionHandler.TryHandleAsync` returns true](https://github.com/aspnet/Announcements/issues/524)

:::moniker-end

[!INCLUDE[](~/fundamentals/error-handling/includes/error-handling9.md)]
[!INCLUDE[](~/fundamentals/error-handling/includes/error-handling8.md)]
[!INCLUDE[](~/fundamentals/error-handling/includes/error-handling3-7.md)]
Loading
Loading