blazorblazor-webassemblyrazor-class-library

How to make the Router load a page from a different assembly based on the country the user is in


I have an app that I would like to make country-specific such that different pages are shown based on country, for the same route.

For every country, I have an RCL that is lazy-loaded, with custom components. My goal is that when I go to domain.com/ or domain.com/shop, the country-specific component will load from a Razor Class Library. This means that multiple components have the same route across RCLs.

As an example:

  1. US: The router will load domain.com/shop from USApp.dll.
  2. Canada: The router will load domain.com/shop from CanadaApp.dll.

The country is stored in local storage in the browser and can be changed antime.

In what ways can I achieve this? There are no docs on custom routing for this case.


Solution

  • Turns out the solution is quite simple. As pointed out by @MisterMagoo you can just change the additional assemblies on the fly.

    This is what I ended up with:

    App.razor:

    @using System.Reflection
    @using Blazored.LocalStorage
    @using Microsoft.AspNetCore.Components.Routing
    @using Microsoft.AspNetCore.Components.WebAssembly.Services
    @using Microsoft.Extensions.Logging
    @inject LazyAssemblyLoader AssemblyLoader
    @inject ILogger<App> Logger
    @inject ILocalStorageService localStorageService
    
    <CascadingValue Value="AppCountry">
    <CascadingAuthenticationState>
        <Router AdditionalAssemblies="@lazyLoadedAssemblies" AppAssembly="@typeof(Program).Assembly" PreferExactMatches="@true" OnNavigateAsync="@OnNavigateAsync">
            <Found Context="routeData">
                <AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)">
                    <NotAuthorized>
                        @if (!context.User.Identity.IsAuthenticated)
                        {
    
                        }
                        else
                        {
                            <p>You are not authorized to access this resource.</p>
                        }
                    </NotAuthorized>
                </AuthorizeRouteView>
            </Found>
            <NotFound>
                <LayoutView Layout="@typeof(MainLayout)">
                    <p>Sorry, there's nothing at this address.</p>
                </LayoutView>
            </NotFound>
        </Router>
    </CascadingAuthenticationState>
    </CascadingValue>
    

    App.razor.cs:

    using Blazored.LocalStorage;
    using Microsoft.AspNetCore.Components;
    using Microsoft.AspNetCore.Components.Authorization;
    using Microsoft.AspNetCore.Components.Routing;
    using Microsoft.Extensions.Logging;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Reflection;
    using System.Threading.Tasks;
    
    namespace Client
    {
        public partial class App : ComponentBase
        {
            private List<Assembly> lazyLoadedAssemblies = new();
    
            public string AppCountry { get; set; }
    
            private async Task OnNavigateAsync(NavigationContext args)
            {
                try
                {
                    AppCountry = await localStorageService.GetItemAsync<string>("Country");
                    Console.WriteLine(AppCountry);
                    if (string.IsNullOrEmpty(AppCountry))
                    {
                        AppCountry = "RO";
                    }
                    IEnumerable<Assembly> assemblies = Enumerable.Empty<Assembly>();
                    switch (await localStorageService.GetItemAsync<string>("Country"))
                    {
                        case "RO":
                            assemblies = await AssemblyLoader.LoadAssembliesAsync(
                            new[]
                               {
                               "RomanianAppLayout.dll"
                               });
    
                            break;
    
                        case "US":
                            assemblies = await AssemblyLoader.LoadAssembliesAsync(
                            new[]
                               {
                               "USAppLayout.dll"
                               });
                            break;
    
                        default:
                            await localStorageService.SetItemAsync("Country", "RO");
                            goto case "RO";
    
                    }
    
                    lazyLoadedAssemblies.Clear();
                    lazyLoadedAssemblies.AddRange(assemblies);
                }
                catch (Exception ex)
                {
                    Logger.LogError("Error: {Message}", ex.Message);
                }
            }
        }
    }