Opožděné načtení sestavení v ASP.NET Core Blazor WebAssembly
Poznámka:
Toto není nejnovější verze tohoto článku. Aktuální verzi najdete ve verzi .NET 8 tohoto článku.
Upozorňující
Tato verze ASP.NET Core se už nepodporuje. Další informace najdete v tématu .NET a .NET Core Zásady podpory. Aktuální verzi najdete ve verzi .NET 8 tohoto článku.
Důležité
Tyto informace se týkají předběžného vydání produktu, který může být podstatně změněn před komerčním vydáním. Microsoft neposkytuje žádné záruky, výslovné ani předpokládané, týkající se zde uváděných informací.
Aktuální verzi najdete ve verzi .NET 8 tohoto článku.
Blazor WebAssembly Výkon spouštění aplikace je možné zlepšit čekáním na načtení sestavení aplikací vytvořených vývojářem, dokud se sestavení nevyžadují, což se nazývá opožděné načítání.
Počáteční části tohoto článku se týkají konfigurace aplikace. Funkční ukázku najdete v části Kompletní příklad na konci tohoto článku.
Tento článek se týká Blazor WebAssembly jenom aplikací. Opožděné načítání sestavení nepodporuje aplikace na straně serveru, protože aplikace vykreslené serverem nestahují sestavení do klienta.
Opožděné načítání by se nemělo používat pro sestavení modulu runtime jádra, která se můžou při načítání aplikace oříznout při publikování a nedostupnosti v klientovi.
Zástupný symbol přípony souboru ({FILE EXTENSION}
) pro soubory sestavení
Soubory sestavení používají formát balení webcilu pro sestavení .NET s příponou .wasm
souboru.
V celém článku {FILE EXTENSION}
představuje zástupný symbol "wasm
".
Soubory sestavení jsou založené na knihovnách DYNAMIC-Link (DLL) s příponou .dll
souboru.
V celém článku {FILE EXTENSION}
představuje zástupný symbol "dll
".
Konfigurace souboru projektu
Označte sestavení pro opožděné načítání v souboru projektu aplikace (.csproj
) pomocí BlazorWebAssemblyLazyLoad
položky. Použijte název sestavení s příponou souboru. Architektura Blazor brání sestavení při spuštění aplikace.
<ItemGroup>
<BlazorWebAssemblyLazyLoad Include="{ASSEMBLY NAME}.{FILE EXTENSION}" />
</ItemGroup>
Zástupný {ASSEMBLY NAME}
symbol je název sestavení a {FILE EXTENSION}
zástupný symbol je přípona souboru. Přípona souboru je povinná.
Zahrňte jednu BlazorWebAssemblyLazyLoad
položku pro každé sestavení. Pokud sestavení obsahuje závislosti, zahrňte BlazorWebAssemblyLazyLoad
položku pro každou závislost.
Router
konfigurace komponent
Architektura Blazor automaticky zaregistruje jednu službu pro opožděné načítání sestavení v aplikacích na straně Blazor WebAssembly klienta . LazyAssemblyLoader Metoda LazyAssemblyLoader.LoadAssembliesAsync:
- Pomocí JS zprostředkovatele komunikace načítá sestavení prostřednictvím síťového volání.
- Načte sestavení do modulu runtime, který se spouští na WebAssembly v prohlížeči.
Poznámka:
Pokyny k hostovaným řešením najdete v části Hostované Blazor WebAssemblyBlazor WebAssemblyřešení v sestaveních Opožděné načítání.
BlazorRouter Komponenta určuje sestavení, která Blazor vyhledá směrovatelné komponenty, a je také zodpovědná za vykreslení komponenty pro trasu, ve které uživatel prochází. Metoda Router komponenty OnNavigateAsync
se používá ve spojení s opožděným načítáním k načtení správných sestavení pro koncové body, které uživatel požaduje.
Logika je implementována uvnitř OnNavigateAsync k určení sestavení, která se mají načíst s LazyAssemblyLoader. Mezi možnosti strukturování logiky patří:
- Podmíněné kontroly uvnitř OnNavigateAsync metody.
- Vyhledávací tabulka, která mapuje trasy na názvy sestavení, buď vložené do komponenty, nebo implementované v
@code
rámci bloku.
V následujícím příkladu:
- Je určen obor názvů pro Microsoft.AspNetCore.Components.WebAssembly.Services .
- Služba LazyAssemblyLoader se vloží (
AssemblyLoader
). - Zástupný
{PATH}
symbol je cesta, kde se má načíst seznam sestavení. Příklad používá podmíněnou kontrolu jedné cesty, která načte jednu sadu sestavení. - Zástupný
{LIST OF ASSEMBLIES}
symbol je čárkami oddělený seznam řetězců názvu souboru sestavení, včetně jejich přípon (například"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(
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);
}
}
}
Poznámka:
Předchozí příklad nezobrazuje obsah značky Router komponenty Razor (...
). Ukázku s úplným kódem najdete v části Kompletní příklad tohoto článku.
Poznámka:
S vydáním ASP.NET Core 5.0.1 a pro všechny další verze 5.x komponenta Router
zahrnuje parametr PreferExactMatches
nastavený na @true
. Další informace najdete v tématu Migrace z ASP.NET Core 3.1 na verzi 5.0.
Sestavení, která obsahují směrovatelné komponenty
Pokud seznam sestavení obsahuje směrovatelné součásti, předá se seznam sestavení pro danou cestu kolekci Router součásti AdditionalAssemblies .
V následujícím příkladu:
- Seznam Assembly<>předá
lazyLoadedAssemblies
seznam sestavení do .AdditionalAssemblies Architektura vyhledá trasy a aktualizuje kolekci tras, pokud jsou nalezeny nové trasy. Pro přístup k Assembly typu je obor názvů System.Reflection zahrnutý v horní částiApp.razor
souboru. - Zástupný
{PATH}
symbol je cesta, kde se má načíst seznam sestavení. Příklad používá podmíněnou kontrolu jedné cesty, která načte jednu sadu sestavení. - Zástupný
{LIST OF ASSEMBLIES}
symbol je čárkami oddělený seznam řetězců názvu souboru sestavení, včetně jejich přípon (například"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 = 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);
}
}
}
Poznámka:
Předchozí příklad nezobrazuje obsah značky Router komponenty Razor (...
). Ukázku s úplným kódem najdete v části Kompletní příklad tohoto článku.
Poznámka:
S vydáním ASP.NET Core 5.0.1 a pro všechny další verze 5.x komponenta Router
zahrnuje parametr PreferExactMatches
nastavený na @true
. Další informace najdete v tématu Migrace z ASP.NET Core 3.1 na verzi 5.0.
Další informace najdete v tématu ASP.NET Blazor Základní směrování a navigace.
Interakce uživatelů s obsahem <Navigating>
Při načítání sestavení, která mohou trvat několik sekund, Router může komponenta označit uživateli, že přechod stránky probíhá s vlastností směrovače Navigating .
Další informace najdete v tématu ASP.NET Blazor Základní směrování a navigace.
Zpracování zrušení v OnNavigateAsync
Objekt NavigationContext předaný zpětnému OnNavigateAsync volání obsahuje nastavenou CancellationToken , když dojde k nové události navigace. OnNavigateAsync Zpětné volání musí vyvolat, když je token zrušení nastavený, aby se zabránilo pokračování ve spouštění zpětného OnNavigateAsync volání v zastaralé navigaci.
Další informace najdete v tématu ASP.NET Blazor Základní směrování a navigace.
OnNavigateAsync
události a přejmenované soubory sestavení
Zavaděč prostředků spoléhá na názvy sestavení definované v blazor.boot.json
souboru. Pokud jsou sestavení přejmenována, názvy sestavení použité v zpětném OnNavigateAsync volání a názvy sestavení v blazor.boot.json
souboru nejsou synchronizované.
Chcete-li tuto opravu napravit:
- Zkontrolujte, jestli aplikace běží v
Production
prostředí při určování názvů sestavení, které se mají použít. - Uložte přejmenované názvy sestavení do samostatného souboru a načtěte z daného souboru, abyste zjistili, jaký název sestavení se má použít se službou LazyAssemblyLoader a OnNavigateAsync zpětným voláním.
Opožděné načtení sestavení v hostovaném Blazor WebAssembly řešení
Implementace opožděného načítání architektury podporuje opožděné načítání s předrenderingem v hostovaném Blazor WebAssemblyřešení. Během předřalení se předpokládá, že se načtou všechna sestavení, včetně těch, která jsou označená pro opožděné načítání. Ručně zaregistrujte LazyAssemblyLoader službu v Server projektu.
V horní části Program.cs
souboru Server projektu přidejte obor názvů pro Microsoft.AspNetCore.Components.WebAssembly.Services:
using Microsoft.AspNetCore.Components.WebAssembly.Services;
Server V Program.cs
projektu zaregistrujte službu:
builder.Services.AddScoped<LazyAssemblyLoader>();
V horní části Startup.cs
souboru Server projektu přidejte obor názvů pro Microsoft.AspNetCore.Components.WebAssembly.Services:
using Microsoft.AspNetCore.Components.WebAssembly.Services;
V Startup.ConfigureServices
(Startup.cs
) Server projektu zaregistrujte službu:
services.AddScoped<LazyAssemblyLoader>();
Kompletní příklad
Ukázka v této části:
- Vytvoří sestavení robota (
GrantImaharaRobotControls.{FILE EXTENSION}
) jako knihovnu Razor tříd (RCL), která obsahuje komponentuRobot
(Robot.razor
se šablonou/robot
trasy ). - Lazily načte sestavení seznamu RCL, aby vykresloval jeho
Robot
komponentu, když/robot
uživatel požaduje adresu URL.
Vytvořte samostatnou Blazor WebAssembly aplikaci, která demonstruje opožděné načítání Razor sestavení knihovny tříd. Pojmenujte projekt LazyLoadTest
.
Do řešení přidejte projekt knihovny tříd ASP.NET Core:
- Visual Studio: Klikněte pravým tlačítkem na soubor řešení v Průzkumník řešení a vyberte Přidat>nový projekt. V dialogovém okně nových typů projektů vyberte Razor knihovnu tříd. Pojmenujte projekt
GrantImaharaRobotControls
. Nezaškrtávejte políčko Stránky podpory a zobrazení. - Visual Studio Code/.NET CLI: Spusťte
dotnet new razorclasslib -o GrantImaharaRobotControls
ho z příkazového řádku. Tato-o|--output
možnost vytvoří složku a pojmenuje projektGrantImaharaRobotControls
.
Ukázková komponenta uvedená dále v této části používá Blazor formulář. V projektu RCL přidejte Microsoft.AspNetCore.Components.Forms
balíček do projektu.
Poznámka:
Pokyny k přidávání balíčků do aplikací .NET najdete v článcích v části Instalace a správa balíčků na webu Pracovní postup používání balíčků (dokumentace k NuGetu). Ověřte správné verze balíčků na NuGet.org.
Vytvořte HandGesture
třídu v seznamu RCL metodou ThumbUp
, která hypoteticky dělá robota gestem palec nahoru. Metoda přijímá argument pro osu nebo Left
Right
, jako .enum
Metoda se vrátí true
k úspěchu.
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 }
}
Do kořenového adresáře projektu RCL přidejte následující komponentu. Tato komponenta uživateli umožňuje odeslat žádost o gesto pro palec doleva nebo doprava.
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> </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> </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> </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
V projektu vytvořte odkaz na projekt pro GrantImaharaRobotControls
seznam RCL:
- Visual Studio: Klikněte pravým tlačítkem myši na
LazyLoadTest
projekt a vyberte Přidat>odkaz na projekt a přidejte odkaz na projekt proGrantImaharaRobotControls
seznam RCL. - Visual Studio Code/.NET CLI: Spusťte
dotnet add reference {PATH}
v příkazovém prostředí ze složky projektu. Zástupný{PATH}
symbol je cesta k projektu RCL.
Zadejte sestavení seznamu RCL pro opožděné načítání v LazyLoadTest
souboru projektu aplikace (.csproj
):
<ItemGroup>
<BlazorWebAssemblyLazyLoad Include="GrantImaharaRobotControls.{FILE EXTENSION}" />
</ItemGroup>
Následující Router komponenta ukazuje načtení GrantImaharaRobotControls.{FILE EXTENSION}
sestavení, když uživatel přejde na /robot
. Nahraďte výchozí App
komponentu aplikace následující App
komponentou.
Během přechodů stránky se uživateli zobrazí stylovaná zpráva s prvkem <Navigating>
. Další informace najdete v části Interakce uživatele s obsahem<Navigating>
.
Sestavení je přiřazeno AdditionalAssemblies, což vede ke směrovači, který hledá směrovatelné komponenty, kde najde komponentu Robot
. Trasa Robot
komponenty se přidá do kolekce tras aplikace. Další informace najdete v článku o směrování a navigaci jádra ASP.NET Blazor a sestaveních, která obsahují směrovatelné součásti tohoto článku.
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…</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 async Task OnNavigateAsync(NavigationContext args)
{
try
{
if (args.Path == "robot")
{
var assemblies = await AssemblyLoader.LoadAssembliesAsync(
new[] { "GrantImaharaRobotControls.{FILE EXTENSION}" });
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">
<Navigating>
<div style="padding:20px;background-color:blue;color:white">
<p>Loading the requested page…</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 async Task OnNavigateAsync(NavigationContext args)
{
try
{
if (args.Path == "robot")
{
var assemblies = await AssemblyLoader.LoadAssembliesAsync(
new[] { "GrantImaharaRobotControls.{FILE EXTENSION}" });
lazyLoadedAssemblies.AddRange(assemblies);
}
}
catch (Exception ex)
{
Logger.LogError("Error: {Message}", ex.Message);
}
}
}
Sestavte a spusťte aplikaci.
Pokud je komponenta Robot
z seznamu RCL požadována, /robot
GrantImaharaRobotControls.{FILE EXTENSION}
sestavení se načte a komponenta Robot
se vykreslí. Načtení sestavení můžete zkontrolovat na kartě Síť vývojářských nástrojů prohlížeče.
Odstraňování potíží
- Pokud dojde k neočekávanému vykreslování, například vykreslení komponenty z předchozí navigace, ověřte, že kód vyvolá, pokud je nastaven token zrušení.
- Pokud se sestavení nakonfigurovaná pro opožděné načítání neočekávaně načítá při spuštění aplikace, zkontrolujte, jestli je sestavení označené pro opožděné načítání v souboru projektu.
Poznámka:
Známý problém existuje pro načítání typů z lazily načteného sestavení. Další informace najdete na webu Blazor WebAssembly lazy loading assemblies not working when using @ref attribute in the component (dotnet/aspnetcore #29342).