You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Blazor中通过LazyAssemblyLoader动态注册路由替代@page指令

问题描述

目前我在OnNavigateAsync事件中加载包含带@page指令(如@page "/extrapage")的Razor页面程序集,运行正常。我希望以编程方式声明页面路由,不使用@page指令,而是通过Dictionary<string, string>(Key为页面完整路由,Value为页面类的全名)来注册。需求是支持动态加载页面,可通过数据库配置添加额外页面。

现有App.razor代码如下:

<Router AppAssembly="@typeof(App).Assembly"
        AdditionalAssemblies="@LazyLoadedAssemblies"
        OnNavigateAsync="@OnNavigateAsync">
    <Found Context="routeData">
        <RouteView RouteData="@routeData" />
        <FocusOnNavigate RouteData="@routeData" Selector="h1" />
    </Found>
    <NotFound>
        <PageTitle>Not found</PageTitle>
        <LayoutView Layout="@typeof(MainLayout)">
            <p role="alert">Sorry, there's nothing at this address.</p>
        </LayoutView>
    </NotFound>
</Router>
@code {
    private Dictionary<string, (string AssemblyName, string ClassName)> AssemblyNameAncClassNameByRoute = new Dictionary<string, (string AssemblyName, string ClassName)>();
    private List<Assembly> LazyLoadedAssemblies = new List<Assembly>();

    private async Task OnNavigateAsync(NavigationContext args)
    {
        try
        {
            if (AssemblyNameAncClassNameByRoute.TryGetValue(args.Path, out (string AssemblyName, string ClassName) tuple))
            {
                IEnumerable<Assembly> assemblies = await AssemblyLoader.LoadAssembliesAsync(new[] { tuple.AssemblyName });
                LazyLoadedAssemblies.AddRange(assemblies);
                
                RegisterRoute(args.Path, Type.GetType(tuple.ClassName));
                
            }
        }
        catch (Exception ex)
        {
            Logger.LogError("Error: {Message}", ex.Message);
        }
    }

    public void RegisterRoute(string pathRoute, Type pageType)
    {
        //需要实现的代码
    }
}
解决方案

要实现动态注册路由,需要操作Blazor内部的路由表。以下是具体实现步骤:

首先在App.razor的顶部注入路由服务:

@inject IEnumerable<IRouter> Routers

然后实现RegisterRoute方法:

private readonly object _routeLock = new object();

public void RegisterRoute(string pathRoute, Type pageType)
{
    // 验证页面类型是否为合法的Blazor组件
    if (!typeof(ComponentBase).IsAssignableFrom(pageType))
    {
        throw new ArgumentException("指定类型不是有效的Blazor组件", nameof(pageType));
    }

    lock (_routeLock)
    {
        // 获取Blazor内置的RouteDataRouter实例
        var routeDataRouter = Routers.OfType<RouteDataRouter>().FirstOrDefault();
        if (routeDataRouter == null)
        {
            throw new InvalidOperationException("无法获取路由处理器实例");
        }

        // 通过反射访问内部路由表
        var routeTableProperty = routeDataRouter.GetType().GetProperty("RouteTable", BindingFlags.Instance | BindingFlags.NonPublic);
        if (routeTableProperty == null)
        {
            throw new InvalidOperationException("无法访问路由表属性");
        }
        var routeTable = routeTableProperty.GetValue(routeDataRouter) as RouteTable;
        if (routeTable == null)
        {
            throw new InvalidOperationException("路由表实例为空");
        }

        // 创建并添加新路由条目
        var routeEntry = new RouteEntry(
            routeTemplate: pathRoute,
            handlerType: pageType,
            parameters: Array.Empty<RouteParameter>()
        );

        routeTable.Entries.Add(routeEntry);
    }
}

关键说明

  1. 线程安全:用lock包裹路由表操作,避免并发导航时出现修改冲突。
  2. 类型校验:确保传入的页面类型是ComponentBase的子类,保证是合法的Blazor页面组件。
  3. 反射操作:由于Blazor的路由管理组件属于内部实现,通过反射来访问路由表并添加自定义路由。
  4. 路由条目构造:RouteEntry包含路由路径、页面类型和参数列表,这里参数列表为空,适配固定路径的路由场景。

注意事项

  • 该实现依赖Blazor的内部细节,后续框架版本更新可能需要调整代码。
  • 若需要持久化动态路由,可在应用启动时从数据库加载配置并批量注册。

内容的提问来源于stack exchange,提问作者Asier Cayón Francisco

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 08:12:30