Habilite la compatibilidad de ASP.NET Core Blazor Server con Yarp en la migración incremental

Al añadir Yarp a una aplicación de Blazor Server, ambos intentan actuar como rutas alternativas para el enrutamiento de solicitudes de la aplicación. O Blazor o Yarp controlan el enrutamiento de forma arbitraria, lo que significa que escenarios como el de la vinculación en profundidad en Blazor pueden fallar. Esto se corregirá en la versión de .NET 8 más adelante este año. Para la migración a ASP.NET Core 6.0 y 7.0, asigne los puntos de conexión de Blazor para lograr un enrutamiento correcto de las solicitudes siguiendo las indicaciones de este artículo.

Agregue la siguiente clase de extensiones del generador de rutas al proyecto.

BlazorEndpointRouteBuilderExtensions.cs:

using System;
using System.Collections.Generic;
using System.Reflection;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Routing;

public static class BlazorEndpointRouteBuilderExtensions {
    public static IEndpointConventionBuilder MapBlazorPages(
        this IEndpointRouteBuilder endpoints, string page)
    {
        var assembly = Assembly.GetEntryAssembly();

        if (assembly is null)
        {
            throw new InvalidOperationException("No entry assembly available.");
        }

        return endpoints.MapBlazorPages(page, assembly);
    }

    public static IEndpointConventionBuilder MapBlazorPages(
        this IEndpointRouteBuilder endpoints, string page, 
        params Assembly[] assemblies)
    {
        ArgumentNullException.ThrowIfNull(assemblies);

        var builder = new BlazorEndpointConventionBuilder();

        foreach (var route in GetRoutes(assemblies))
        {
            var conventionBuilder = endpoints.MapFallbackToPage(route, page);

            conventionBuilder.Add(b =>
            {
                b.DisplayName = $"Blazor {route}";
                ((RouteEndpointBuilder)b).Order = -1;
            });

            builder.Add(conventionBuilder);
        }

        return builder;
    }

    private static IEnumerable<string> GetRoutes(Assembly[] assemblies)
    {
        foreach (var assembly in assemblies)
        {
            foreach (var type in assembly.GetTypes())
            {
                if (typeof(IComponent).IsAssignableFrom(type))
                {
                    foreach (var attribute in 
                        type.GetCustomAttributes(typeof(RouteAttribute)))
                    {
                        if (attribute is RouteAttribute { Template: { } route })
                        {
                            yield return route;
                        }
                    }
                }
            }
        }
    }

    private sealed class BlazorEndpointConventionBuilder : IEndpointConventionBuilder {
        private readonly List<IEndpointConventionBuilder> builders = new();

        public void Add(IEndpointConventionBuilder builder)
        {
            builders.Add(builder);
        }

        void IEndpointConventionBuilder.Add(Action<EndpointBuilder> convention)
        {
            foreach (var builder in builders)
            {
                builder.Add(convention);
            }
        }

#if NET7_0_OR_GREATER
        void IEndpointConventionBuilder.Finally(
            Action<EndpointBuilder> finalConvention)
        {
            foreach (var builder in builders)
            {
                builder.Finally(finalConvention);
            }
        }
#endif
    }
}

En el código anterior:

  • EndpointBuilder.DisplayName se establece de forma predeterminada en Fallback {route}. La línea que lo cambia a Blazor {route} (b.DisplayName = $"Blazor {route}";) identifica la ruta Blazor como registrada explícitamente.
  • Para la línea que establece el orden de ruta (((RouteEndpointBuilder)b).Order = -1;), {page} tiene un orden de ruta de 0 de forma predeterminada. Establecer el orden de ruta de Blazor en -1 asegura que se cambie el orden para dar preferencia a la ruta de Blazor.

Actualice el registro de la aplicación para usar Blazor en Program.cs:

- app.MapFallbackToPage("/_Host");
+ app.MapBlazorPages("/_Host");

En este momento, la aplicación debe enrutar las solicitudes correctamente para Blazor y Yarp, incluida la vinculación en profundidad a páginas.