在 Blazor 中以编程方式注册页面,而不是使用 LazyAssemblyLoader 使用 @page 指令

2024-05-08

目前我加载程序集OnNavigateAsync包含带有 @page 指令的 Razor 页面的事件,例如@page "/extrapage",并且工作正常。

例如,我想以编程方式声明路由页面,而不声明@page并且,代替这个,使用Dictionary<string, string> where 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)
    {
        //THE CODE I NEED
    }
}

Thanks.


不奇怪,我以前也这么做过。

您也不需要构建新的路由器。您可以将自定义路由器添加到NotFound标准路由器的部分。

以下是具体操作方法。

我用过一个<string, Type>字典。

首先是准系统定制路线服务

public class CustomRouteService
{
    private List<CustomRouteData> _pages = new();

    public IEnumerable<CustomRouteData> Pages => _pages.AsEnumerable();

    public bool TryAddRoute(CustomRouteData data)
    {
        var isComponent = typeof(IComponent).IsAssignableFrom(data.Page);
        var newRoute = !_pages.Any(item => item.Route.Equals(data.Route, StringComparison.CurrentCultureIgnoreCase));

        if (isComponent && newRoute)
        {
            _pages.Add(data);
            return true;
        }

        return false;
    }

    public bool TryAddRoute(string route, string className)
    {
        var page = Type.GetType(className);
        if (page is null)
            return false;

        return this.TryAddRoute(new CustomRouteData(route, page));
    }

    public bool TryGetRoute(string route, out Type? page)
    {
        page = null;
        var data = _pages.FirstOrDefault(item => item.Route.Equals(route, StringComparison.CurrentCultureIgnoreCase));
        if (data is not null)
            page = data.Page;

        return page != null;
    }
}

public record CustomRouteData(string Route, Type Page);

注册为单例服务

Next a CustomRouteLoader剃刀组件。

@if (_isRoute)
{
    <RouteView RouteData=_routeData DefaultLayout="@typeof(MainLayout)" />
}
else
{
    @this.NotFound
}

@code {
    [Parameter] public RenderFragment? NotFound { get; set; }

    [Inject] public NavigationManager NavManager { get; set; } = default!;
    [Inject] public CustomRouteService PageService { get; set; } = default!;

    private Type? _component;
    private bool _isRoute;
    private RouteData? _routeData;

    protected override void OnParametersSet()
    {
        _routeData = null;
 
        // Get rhe route Uri
        var url = this.NavManager.Uri.Replace(NavManager.BaseUri, "/");
        
        // Try to get the component associated with the route
        PageService.TryGetRoute(url, out _component);

        // Check we have a type and it implements IComponent
        _isRoute = _component is not null && typeof(IComponent).IsAssignableFrom(_component);

        // Create the RouteData
        if (_isRoute &&  _component is not null)
            _routeData = new RouteData(_component, new Dictionary<string, object>());
    }

}

将其添加到App:

Router AppAssembly="@typeof(App).Assembly">
    <Found Context="routeData">
        <RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
        <FocusOnNavigate RouteData="@routeData" Selector="h1" />
    </Found>
    <NotFound>
        <CustomRouteLoader>
            <NotFound>
                <PageTitle>Not found</PageTitle>
                <LayoutView Layout="@typeof(MainLayout)">
                    <p role="alert">Sorry, there's nothing at this address.</p>
                </LayoutView>
            </NotFound>
        </CustomRouteLoader>
    </NotFound>
</Router>

以及一个用于添加并导航到自定义路线的测试页面

@page "/"
@inject CustomRouteService customRouteService
@inject NavigationManager navManager

<PageTitle>Index</PageTitle>

<h1>Hello, world!</h1>

Welcome to your new app.

<SurveyPrompt Title="How is Blazor working for you?" />

<button class="btn btn-success" @onclick=this.AddRoute>Add Fred Route</button>
<button class="btn btn-dark" @onclick=this.Navigate>Navigate to Fred</button>

<button class="btn btn-success" @onclick=this.AddJonRoute>Add Jon Route</button>
<button class="btn btn-dark" @onclick=this.NavigateJon>Navigate to Jon</button>

@code {

    private void AddRoute()
        => customRouteService.TryAddRoute( new CustomRouteData("/Fred", typeof(Counter) ));

    private void AddJonRoute()
        => customRouteService.TryAddRoute("/Jon", "SO76159043.Pages.FetchData");

    private void Navigate()
        => navManager.NavigateTo("/Fred");

    private void NavigateJon()
        => navManager.NavigateTo("/Jon");
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 Blazor 中以编程方式注册页面,而不是使用 LazyAssemblyLoader 使用 @page 指令 的相关文章

随机推荐