Поделиться через


Сборки с отложенной загрузкой в ASP.NET Core Blazor WebAssembly

Примечание.

Это не последняя версия этой статьи. В текущем выпуске смотрите версию этой статьи .NET 9.

Предупреждение

Эта версия ASP.NET Core больше не поддерживается. Дополнительные сведения см. в политике поддержки .NET и .NET Core. В текущем выпуске смотрите версию этой статьи .NET 9.

Внимание

Эта информация относится к предварительному выпуску продукта, который может быть существенно изменен до его коммерческого выпуска. Майкрософт не предоставляет никаких гарантий, явных или подразумеваемых, относительно приведенных здесь сведений.

В текущем выпуске смотрите версию этой статьи .NET 9.

Blazor WebAssembly Производительность запуска приложения можно улучшить, ожидая загрузки сборок, созданных разработчиком, до тех пор, пока сборки не требуются, что называется отложенной загрузкой.

В первых разделах этой статьи рассматривается конфигурация приложений. Рабочую демонстрацию см. в разделе Полный пример в конце этой статьи.

Этот раздел относится только к приложениям Blazor WebAssembly. Отложенная загрузка сборок не дает преимущества серверным приложениям, так как выполняемые на сервере приложения не загружают сборки на клиент.

Отложенная загрузка не должна использоваться для основных сборок сред выполнения, которые могут быть обрезаны при публикации и могут быть недоступны на клиенте при загрузке приложения.

Шаблон расширения файла ({FILE EXTENSION}) для файлов сборки

Файлы сборок используют формат упаковки Webcil для сборок .NET с расширением .wasm.

На протяжении всей статьи {FILE EXTENSION} обозначает "wasm".

Файлы сборок основаны на библиотеках динамических ссылок (DLL) с расширением .dll файла.

На протяжении всей статьи {FILE EXTENSION} обозначает "dll".

Конфигурация файла проекта

Пометьте сборки для отложенной загрузки в файле проекта приложения (.csproj) с помощью элемента BlazorWebAssemblyLazyLoad. Используйте имя сборки вместе с расширением файла. Платформа Blazor предотвращает загрузку сборки при запуске приложения.

<ItemGroup>
  <BlazorWebAssemblyLazyLoad Include="{ASSEMBLY NAME}.{FILE EXTENSION}" />
</ItemGroup>

Заполнитель {ASSEMBLY NAME} — это имя сборки, а {FILE EXTENSION} заполнитель — расширение файла. Требуется расширение файла .

Включите по одному элементу BlazorWebAssemblyLazyLoad для каждой сборки. Если сборка имеет зависимости, включите запись BlazorWebAssemblyLazyLoad для каждой зависимости.

Конфигурация компонента Router

Платформа Blazor автоматически регистрирует единую службу для отложенной загрузки сборок в клиентских Blazor WebAssembly приложениях LazyAssemblyLoader. Метод LazyAssemblyLoader.LoadAssembliesAsync:

  • Использует интероперабельность JS для выборки сборок через сетевой вызов.
  • Загружает сборки в среду выполнения в WebAssembly в браузере.

Примечание.

Руководство по размещеннымBlazor WebAssemblyрешениям рассматривается в разделе Сборки с отложенной загрузкой в размещенномBlazor WebAssembly решении.

Компонент BlazorRouter определяет сборки, в которых Blazor ищет маршрутизируемые компоненты. Кроме того, он отвечает за отрисовку компонента для маршрута, по которому переходит пользователь. Метод Router компонента OnNavigateAsync используется совместно с отложенной загрузкой для загрузки подходящих сборок для конечных точек, запрашиваемых пользователем.

Логика реализуется внутри OnNavigateAsync, чтобы определить сборки, которые необходимо загрузить с LazyAssemblyLoader. Ниже приведены варианты структурирования логики:

  • Условные проверки в методе OnNavigateAsync.
  • Таблица подстановки, которая сопоставляет маршруты с именами сборок, либо внедряется в компонент, либо реализуется в коде компонента.

В следующем примере :

  • Указано пространство имен для Microsoft.AspNetCore.Components.WebAssembly.Services.
  • Служба LazyAssemblyLoader внедрена (AssemblyLoader).
  • Путь, по которому должен быть загружен список сборок, представлен заполнителем {PATH}. В примере используется условная проверка для одного пути, который загружает один набор сборок.
  • Заполнитель {LIST OF ASSEMBLIES} — это разделенный запятыми список строк имени файла сборки, включая их расширения файлов (например, "Assembly1.{FILE EXTENSION}", "Assembly2.{FILE EXTENSION}").

App.razor:

@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.WebAssembly.Services
@using Microsoft.Extensions.Logging
@inject LazyAssemblyLoader AssemblyLoader
@inject ILogger<App> Logger

<Router AppAssembly="typeof(App).Assembly" 
    OnNavigateAsync="OnNavigateAsync">
    ...
</Router>

@code {
    private async Task OnNavigateAsync(NavigationContext args)
    {
        try
           {
               if (args.Path == "{PATH}")
               {
                   var assemblies = await AssemblyLoader.LoadAssembliesAsync(
                       [ {LIST OF ASSEMBLIES} ]);
               }
           }
           catch (Exception ex)
           {
               Logger.LogError("Error: {Message}", ex.Message);
           }
    }
}
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.WebAssembly.Services
@using Microsoft.Extensions.Logging
@inject LazyAssemblyLoader AssemblyLoader
@inject ILogger<App> Logger

<Router AppAssembly="typeof(App).Assembly" 
    OnNavigateAsync="OnNavigateAsync">
    ...
</Router>

@code {
    private async Task OnNavigateAsync(NavigationContext args)
    {
        try
           {
               if (args.Path == "{PATH}")
               {
                   var assemblies = await AssemblyLoader.LoadAssembliesAsync(
                       new[] { {LIST OF ASSEMBLIES} });
               }
           }
           catch (Exception ex)
           {
               Logger.LogError("Error: {Message}", ex.Message);
           }
    }
}
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.WebAssembly.Services
@using Microsoft.Extensions.Logging
@inject LazyAssemblyLoader AssemblyLoader
@inject ILogger<App> Logger

<Router AppAssembly="typeof(Program).Assembly" 
    OnNavigateAsync="OnNavigateAsync">
    ...
</Router>

@code {
    private async Task OnNavigateAsync(NavigationContext args)
    {
        try
           {
               if (args.Path == "{PATH}")
               {
                   var assemblies = await AssemblyLoader.LoadAssembliesAsync(
                       new[] { {LIST OF ASSEMBLIES} });
               }
           }
           catch (Exception ex)
           {
               Logger.LogError("Error: {Message}", ex.Message);
           }
    }
}

Примечание.

В предыдущем примере не показано содержимое разметки Router компонента Razor (...). Полный код см. в разделе Полный пример этой статьи.

Примечание.

В выпуске ASP.NET Core 5.0.1 и дальнейших выпусках 5.x компонент Router содержит параметр PreferExactMatches со значением @true. Дополнительные сведения см. в статье Миграция с ASP.NET Core 3.1 на 5.0.

Сборки, включающие маршрутизируемые компоненты

Если список сборок включает маршрутизируемые компоненты, этот список сборок для данного пути передается в коллекцию Router компонента AdditionalAssemblies.

В следующем примере :

  • List<Assembly> в lazyLoadedAssemblies передает список сборок в AdditionalAssemblies. Платформа выполняет поиск маршрутов в сборках и обновляет коллекцию маршрутов при обнаружении новых маршрутов. Для доступа к типу Assembly пространство имен для System.Reflection добавляется в начало файла App.razor.
  • Путь, по которому должен быть загружен список сборок, представлен заполнителем {PATH}. В примере используется условная проверка для одного пути, который загружает один набор сборок.
  • Заполнитель {LIST OF ASSEMBLIES} — это разделенный запятыми список строк имени файла сборки, включая их расширения файлов (например, "Assembly1.{FILE EXTENSION}", "Assembly2.{FILE EXTENSION}").

App.razor:

@using System.Reflection
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.WebAssembly.Services
@using Microsoft.Extensions.Logging
@inject ILogger<App> Logger
@inject LazyAssemblyLoader AssemblyLoader

<Router AppAssembly="typeof(App).Assembly" 
    AdditionalAssemblies="lazyLoadedAssemblies" 
    OnNavigateAsync="OnNavigateAsync">
    ...
</Router>

@code {
    private List<Assembly> lazyLoadedAssemblies = [];

    private async Task OnNavigateAsync(NavigationContext args)
    {
        try
        {
            if (args.Path == "{PATH}")
            {
                var assemblies = await AssemblyLoader.LoadAssembliesAsync(
                    [ {LIST OF ASSEMBLIES} ]);
                lazyLoadedAssemblies.AddRange(assemblies);
            }
        }
        catch (Exception ex)
        {
            Logger.LogError("Error: {Message}", ex.Message);
        }
    }
}
@using System.Reflection
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.WebAssembly.Services
@using Microsoft.Extensions.Logging
@inject ILogger<App> Logger
@inject LazyAssemblyLoader AssemblyLoader

<Router AppAssembly="typeof(App).Assembly" 
    AdditionalAssemblies="lazyLoadedAssemblies" 
    OnNavigateAsync="OnNavigateAsync">
    ...
</Router>

@code {
    private List<Assembly> lazyLoadedAssemblies = new();

    private async Task OnNavigateAsync(NavigationContext args)
    {
        try
        {
            if (args.Path == "{PATH}")
            {
                var assemblies = await AssemblyLoader.LoadAssembliesAsync(
                    new[] { {LIST OF ASSEMBLIES} });
                lazyLoadedAssemblies.AddRange(assemblies);
            }
        }
        catch (Exception ex)
        {
            Logger.LogError("Error: {Message}", ex.Message);
        }
    }
}
@using System.Reflection
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.WebAssembly.Services
@using Microsoft.Extensions.Logging
@inject ILogger<App> Logger
@inject LazyAssemblyLoader AssemblyLoader

<Router AppAssembly="typeof(Program).Assembly" 
    AdditionalAssemblies="lazyLoadedAssemblies" 
    OnNavigateAsync="OnNavigateAsync">
    ...
</Router>

@code {
    private List<Assembly> lazyLoadedAssemblies = new List<Assembly>();

    private async Task OnNavigateAsync(NavigationContext args)
    {
        try
           {
               if (args.Path == "{PATH}")
               {
                   var assemblies = await AssemblyLoader.LoadAssembliesAsync(
                       new[] { {LIST OF ASSEMBLIES} });
                   lazyLoadedAssemblies.AddRange(assemblies);
               }
           }
           catch (Exception ex)
           {
               Logger.LogError("Error: {Message}", ex.Message);
           }
    }
}

Примечание.

В предыдущем примере не показано содержимое разметки Router компонента Razor (...). Полный код см. в разделе Полный пример этой статьи.

Примечание.

В выпуске ASP.NET Core 5.0.1 и дальнейших выпусках 5.x компонент Router содержит параметр PreferExactMatches со значением @true. Дополнительные сведения см. в статье Миграция с ASP.NET Core 3.1 на 5.0.

Дополнительные сведения см. в статье Маршрутизация ASP.NET Core Blazor и навигация.

Взаимодействие пользователей с содержимым <Navigating>

При загрузке сборок, которая может занять несколько секунд, компонент Router может показать пользователю, что переход на страницу происходит со свойством маршрутизатора Navigating.

Дополнительные сведения см. в статье Маршрутизация ASP.NET Core Blazor и навигация.

Обработка отмены в OnNavigateAsync

Объект NavigationContext, переданный в обратный вызов OnNavigateAsync, содержит CancellationToken, который задается при возникновении нового события навигации. Обратный вызов OnNavigateAsync необходим, если этот токен отмены установлен так, чтобы не выполнять обратный вызов OnNavigateAsync для устаревшей навигации.

Дополнительные сведения см. в статье Маршрутизация ASP.NET Core Blazor и навигация.

События OnNavigateAsync и переименованные файлы сборки

Загрузчик ресурсов зависит от имен сборок, определенных в файле манифеста загрузки. Если сборки переименованы, имена сборок, используемых для обратного OnNavigateAsync вызова, и имена сборок в файле манифеста загрузки не синхронизируются.

Чтобы исправить это, сделайте следующее.

  • Проверьте, выполняется ли приложение в среде Production при определении используемых имен сборок.
  • Сохраните имена переименованных сборок в отдельном файле и выполните чтение из этого файла, чтобы определить, какое имя сборки использовать со службой LazyAssemblyLoader и обратным вызовом OnNavigateAsync.

Ленивая загрузка сборок в размещенном решении Blazor WebAssembly

Реализация ленивой загрузки в фреймворке поддерживает ленивую загрузку с предварительной отрисовкой в размещенном Blazor WebAssemblyрешении. Во время предварительного рендеринга предполагается, что будут загружены все сборки, включая те, которые отмечены для отложенной загрузки. Вручную зарегистрируйте службу LazyAssemblyLoader в проекте Server.

В верхней части файла Program.cs проекта Server добавьте пространство имен для Microsoft.AspNetCore.Components.WebAssembly.Services.

using Microsoft.AspNetCore.Components.WebAssembly.Services;

В проекте Program.cs в Server зарегистрировать службу:

builder.Services.AddScoped<LazyAssemblyLoader>();

На самом верху файла Startup.cs проекта Server добавьте пространство имен для Microsoft.AspNetCore.Components.WebAssembly.Services:

using Microsoft.AspNetCore.Components.WebAssembly.Services;

В Startup.ConfigureServices (Startup.cs) проекта Server зарегистрируйте службу:

services.AddScoped<LazyAssemblyLoader>();

Полный пример

Демонстрация в этом разделе:

  • Создает сборку элементов управления робота (GrantImaharaRobotControls.{FILE EXTENSION}) в качестве библиотеки классов Razor (RCL), которая включает компонент Robot (Robot.razor с шаблоном маршрута /robot).
  • Выполняет отложенную загрузку сборки RCL, чтобы отрисовать компонент Robot, когда пользователь запрашивает URL-адрес /robot.

Создайте автономное Blazor WebAssembly приложение, чтобы продемонстрировать отложенную загрузку сборки Razor библиотеки классов. Присвойте проекту имя LazyLoadTest.

Добавьте в решение проект библиотеки классов ASP.NET Core:

  • Visual Studio: щелкните правой кнопкой мыши файл решения в Обозреватель решений и выберите "Добавить>новый проект". В диалоговом окне новых типов проектов выберите Razor библиотеку классов. Присвойте проекту имя GrantImaharaRobotControls. Не выбирайте флажок страницы поддержки и представлений.
  • Visual Studio Code/.NET CLI: выполните dotnet new razorclasslib -o GrantImaharaRobotControls из командной строки. Параметр -o|--output создает папку и присваивает имя проекту GrantImaharaRobotControls.

Создайте класс HandGesture в RCL с помощью метода ThumbUp, который гипотетически заставляет робота поднять большой палец вверх. Метод принимает аргумент для оси, Left или Right, в качестве enum. Метод возвращает значение true при успешном выполнении.

HandGesture.cs:

using Microsoft.Extensions.Logging;

namespace GrantImaharaRobotControls;

public static class HandGesture
{
    public static bool ThumbUp(Axis axis, ILogger logger)
    {
        logger.LogInformation("Thumb up gesture. Axis: {Axis}", axis);

        // Code to make robot perform gesture

        return true;
    }
}

public enum Axis { Left, Right }
using Microsoft.Extensions.Logging;

namespace GrantImaharaRobotControls
{
    public static class HandGesture
    {
        public static bool ThumbUp(Axis axis, ILogger logger)
        {
            logger.LogInformation("Thumb up gesture. Axis: {Axis}", axis);

            // Code to make robot perform gesture

            return true;
        }
    }

    public enum Axis { Left, Right }
}

Добавьте следующий компонент в корень проекта RCL. Компонент позволяет пользователю отправить запрос на жест поднятого большого пальца левой или правой руки.

Robot.razor:

@page "/robot"
@using Microsoft.AspNetCore.Components.Forms
@using Microsoft.Extensions.Logging
@inject ILogger<Robot> Logger

<h1>Robot</h1>

<EditForm FormName="RobotForm" Model="robotModel" OnValidSubmit="HandleValidSubmit">
    <InputRadioGroup @bind-Value="robotModel.AxisSelection">
        @foreach (var entry in Enum.GetValues<Axis>())
        {
            <InputRadio Value="entry" />
            <text>&nbsp;</text>@entry<br>
        }
    </InputRadioGroup>

    <button type="submit">Submit</button>
</EditForm>

<p>
    @message
</p>

@code {
    private RobotModel robotModel = new() { AxisSelection = Axis.Left };
    private string? message;

    private void HandleValidSubmit()
    {
        Logger.LogInformation("HandleValidSubmit called");

        var result = HandGesture.ThumbUp(robotModel.AxisSelection, Logger);

        message = $"ThumbUp returned {result} at {DateTime.Now}.";
    }

    public class RobotModel
    {
        public Axis AxisSelection { get; set; }
    }
}
@page "/robot"
@using Microsoft.AspNetCore.Components.Forms
@using Microsoft.Extensions.Logging
@inject ILogger<Robot> Logger

<h1>Robot</h1>

<EditForm Model="robotModel" OnValidSubmit="HandleValidSubmit">
    <InputRadioGroup @bind-Value="robotModel.AxisSelection">
        @foreach (var entry in Enum.GetValues<Axis>())
        {
            <InputRadio Value="entry" />
            <text>&nbsp;</text>@entry<br>
        }
    </InputRadioGroup>

    <button type="submit">Submit</button>
</EditForm>

<p>
    @message
</p>

@code {
    private RobotModel robotModel = new() { AxisSelection = Axis.Left };
    private string? message;

    private void HandleValidSubmit()
    {
        Logger.LogInformation("HandleValidSubmit called");

        var result = HandGesture.ThumbUp(robotModel.AxisSelection, Logger);

        message = $"ThumbUp returned {result} at {DateTime.Now}.";
    }

    public class RobotModel
    {
        public Axis AxisSelection { get; set; }
    }
}
@page "/robot"
@using Microsoft.AspNetCore.Components.Forms
@using Microsoft.Extensions.Logging
@inject ILogger<Robot> Logger

<h1>Robot</h1>

<EditForm Model="robotModel" OnValidSubmit="HandleValidSubmit">
    <InputRadioGroup @bind-Value="robotModel.AxisSelection">
        @foreach (var entry in (Axis[])Enum
            .GetValues(typeof(Axis)))
        {
            <InputRadio Value="entry" />
            <text>&nbsp;</text>@entry<br>
        }
    </InputRadioGroup>

    <button type="submit">Submit</button>
</EditForm>

<p>
    @message
</p>

@code {
    private RobotModel robotModel = new RobotModel() { AxisSelection = Axis.Left };
    private string message;

    private void HandleValidSubmit()
    {
        Logger.LogInformation("HandleValidSubmit called");

        var result = HandGesture.ThumbUp(robotModel.AxisSelection, Logger);

        message = $"ThumbUp returned {result} at {DateTime.Now}.";
    }

    public class RobotModel
    {
        public Axis AxisSelection { get; set; }
    }
}

В проекте LazyLoadTest создайте ссылку на проект GrantImaharaRobotControls RCL.

  • Visual Studio: щелкните проект правой кнопкой мыши LazyLoadTest и выберите "Добавить>ссылку на проект", чтобы добавить ссылку на проект для GrantImaharaRobotControls RCL.
  • Visual Studio Code/.NET CLI: выполните dotnet add reference {PATH} в командной строке из папки проекта. Заполнитель {PATH} — это путь к проекту RCL.

Укажите сборку RCL для отложенной загрузки в файле проекта приложения LazyLoadTest (.csproj):

<ItemGroup>
    <BlazorWebAssemblyLazyLoad Include="GrantImaharaRobotControls.{FILE EXTENSION}" />
</ItemGroup>

Следующий компонент Router демонстрирует загрузку сборки GrantImaharaRobotControls.{FILE EXTENSION}, когда пользователь переходит к /robot. Замените компонент приложения по умолчанию App следующим компонентом App.

Во время перехода по страницам для пользователя отображается стилизованное сообщение с элементом <Navigating>. Дополнительные сведения см. в разделе Взаимодействие пользователя с содержимым <Navigating>.

Сборка назначается AdditionalAssemblies, поэтому маршрутизатор ищет в сборке маршрутизируемые компоненты и находит компонент Robot. Маршрут компонента Robot добавляется в коллекцию маршрутов приложения. Дополнительные сведения см. в статье Маршрутизация ASP.NET Core Blazor и навигация и разделе Сборки с маршрутизируемыми компонентами в этой статье.

App.razor:

@using System.Reflection
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.WebAssembly.Services
@using Microsoft.Extensions.Logging
@inject ILogger<App> Logger
@inject LazyAssemblyLoader AssemblyLoader

<Router AppAssembly="typeof(App).Assembly"
        AdditionalAssemblies="lazyLoadedAssemblies" 
        OnNavigateAsync="OnNavigateAsync">
    <Navigating>
        <div style="padding:20px;background-color:blue;color:white">
            <p>Loading the requested page&hellip;</p>
        </div>
    </Navigating>
    <Found Context="routeData">
        <RouteView RouteData="routeData" DefaultLayout="typeof(MainLayout)" />
    </Found>
    <NotFound>
        <LayoutView Layout="typeof(MainLayout)">
            <p>Sorry, there's nothing at this address.</p>
        </LayoutView>
    </NotFound>
</Router>

@code {
    private List<Assembly> lazyLoadedAssemblies = [];
    private bool grantImaharaRobotControlsAssemblyLoaded;

    private async Task OnNavigateAsync(NavigationContext args)
    {
        try
        {
            if ((args.Path == "robot") && !grantImaharaRobotControlsAssemblyLoaded)
            {
                var assemblies = await AssemblyLoader.LoadAssembliesAsync(
                    [ "GrantImaharaRobotControls.{FILE EXTENSION}" ]);
                lazyLoadedAssemblies.AddRange(assemblies);
                grantImaharaRobotControlsAssemblyLoaded = true;
            }
        }
        catch (Exception ex)
        {
            Logger.LogError("Error: {Message}", ex.Message);
        }
    }
}
@using System.Reflection
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.WebAssembly.Services
@using Microsoft.Extensions.Logging
@inject ILogger<App> Logger
@inject LazyAssemblyLoader AssemblyLoader

<Router AppAssembly="typeof(App).Assembly"
        AdditionalAssemblies="lazyLoadedAssemblies" 
        OnNavigateAsync="OnNavigateAsync">
    <Navigating>
        <div style="padding:20px;background-color:blue;color:white">
            <p>Loading the requested page&hellip;</p>
        </div>
    </Navigating>
    <Found Context="routeData">
        <RouteView RouteData="routeData" DefaultLayout="typeof(MainLayout)" />
    </Found>
    <NotFound>
        <LayoutView Layout="typeof(MainLayout)">
            <p>Sorry, there's nothing at this address.</p>
        </LayoutView>
    </NotFound>
</Router>

@code {
    private List<Assembly> lazyLoadedAssemblies = new();
    private bool grantImaharaRobotControlsAssemblyLoaded;

    private async Task OnNavigateAsync(NavigationContext args)
    {
        try
        {
            if ((args.Path == "robot") && !grantImaharaRobotControlsAssemblyLoaded)
            {
                var assemblies = await AssemblyLoader.LoadAssembliesAsync(
                    new[] { "GrantImaharaRobotControls.{FILE EXTENSION}" });
                lazyLoadedAssemblies.AddRange(assemblies);
                grantImaharaRobotControlsAssemblyLoaded = true;
            }
        }
        catch (Exception ex)
        {
            Logger.LogError("Error: {Message}", ex.Message);
        }
    }
}
@using System.Reflection
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.WebAssembly.Services
@using Microsoft.Extensions.Logging
@inject ILogger<App> Logger
@inject LazyAssemblyLoader AssemblyLoader

<Router AppAssembly="typeof(Program).Assembly"
        AdditionalAssemblies="lazyLoadedAssemblies" 
        OnNavigateAsync="OnNavigateAsync">
    <Navigating>
        <div style="padding:20px;background-color:blue;color:white">
            <p>Loading the requested page&hellip;</p>
        </div>
    </Navigating>
    <Found Context="routeData">
        <RouteView RouteData="routeData" DefaultLayout="typeof(MainLayout)" />
    </Found>
    <NotFound>
        <LayoutView Layout="typeof(MainLayout)">
            <p>Sorry, there's nothing at this address.</p>
        </LayoutView>
    </NotFound>
</Router>

@code {
    private List<Assembly> lazyLoadedAssemblies = new List<Assembly>();
    private bool grantImaharaRobotControlsAssemblyLoaded;

    private async Task OnNavigateAsync(NavigationContext args)
    {
        try
        {
            if ((args.Path == "robot") && !grantImaharaRobotControlsAssemblyLoaded)
            {
                var assemblies = await AssemblyLoader.LoadAssembliesAsync(
                    new[] { "GrantImaharaRobotControls.{FILE EXTENSION}" });
                lazyLoadedAssemblies.AddRange(assemblies);
                grantImaharaRobotControlsAssemblyLoaded = true;
            }
        }
        catch (Exception ex)
        {
            Logger.LogError("Error: {Message}", ex.Message);
        }
    }
}

Выполните сборку и запустите приложение.

Когда запрашивается компонент Robot из RCL, загружается сборка /robot, и отображается компонент GrantImaharaRobotControls.{FILE EXTENSION}. Вы можете проверить загрузку сборки на вкладке "Сеть " средств разработчика браузера.

Устранение неполадок

  • Если происходит непредвиденная отрисовка (например, отрисовка компонента из предыдущей навигации), убедитесь, что код создает исключение, если задан токен отмены.
  • Если сборки, настроенные для отложенной загрузки, неожиданно загружаются при запуске приложения, убедитесь, что сборка помечена для отложенной загрузки в файле проекта.

Примечание.

Известная проблема существует при загрузке типов из лениво загружаемой сборки. Дополнительные сведения см. в разделе Blazor WebAssembly lazy loading assemblies not working when using @ref attribute in the component (dotnet/aspnetcore #29342).

Дополнительные ресурсы