---
title: Lazy load assemblies in ASP.NET Core Blazor WebAssembly
author: guardrex
description: Discover how to lazy load assemblies in ASP.NET Core Blazor WebAssembly apps.
monikerRange: '>= aspnetcore-5.0'
ms.author: riande
ms.custom: mvc
ms.date: 09/09/2020
no-loc: [Kestrel, appsettings.json, "ASP.NET Core Identity", cookie, Cookie, Blazor, "Blazor Server", "Blazor WebAssembly", "Identity", "Let's Encrypt", Razor, SignalR]
uid: blazor/webassembly-lazy-load-assemblies
---
# Lazy load assemblies in ASP.NET Core Blazor WebAssembly
Blazor WebAssembly app startup performance can be improved by deferring the loading of some application assemblies until they are required, which is called *lazy loading*. For example, assemblies that are only used to render a single component can be set up to load only if the user navigates to that component. After loading, the assemblies are cached client-side and are available for all future navigations.
Blazor's lazy loading feature allows you to mark app assemblies for lazy loading, which loads the assemblies during runtime when the user navigates to a particular route. The feature consists of changes to the project file and changes to the application's router.
> [!NOTE]
> Assembly lazy loading doesn't benefit Blazor Server apps because assemblies aren't downloaded to the client in a Blazor Server app.
## Project file
Mark assemblies for lazy loading in the app's project file (`.csproj`) using the `BlazorWebAssemblyLazyLoad` item. Use the assembly name with the `.dll` extension. The Blazor framework prevents the assemblies specified by this item group from loading at app launch. The following example marks a large custom assembly (`GrantImaharaRobotControls.dll`) for lazy loading. If an assembly that's marked for lazy loading has dependencies, they must also be marked for lazy loading in the project file.
```xml
```
## `Router` component
Blazor's `Router` component designates which assemblies Blazor searches for routable components. The `Router` component is also responsible for rendering the component for the route where the user navigates. The `Router` component supports an `OnNavigateAsync` feature that can be used in conjunction with lazy loading.
In the app's `Router` component (`App.razor`):
* Add an `OnNavigateAsync` callback. The `OnNavigateAsync` handler is invoked when the user:
* Visits a route for the first time by navigating to it directly from their browser.
* Navigates to a new route using a link or a invocation.
* If lazy-loaded assemblies contain routable components, add a [List](xref:System.Collections.Generic.List%601)\<> (for example, named `lazyLoadedAssemblies`) to the component. The assemblies are passed back to the collection in case the assemblies contain routable components. The framework searches the assemblies for routes and updates the route collection if any new routes are found.
```razor
@using System.Reflection
...
@code {
private List lazyLoadedAssemblies = new List();
private async Task OnNavigateAsync(NavigationContext args)
{
}
}
```
[!INCLUDE[](~/blazor/includes/prefer-exact-matches.md)]
If the `OnNavigateAsync` callback throws an unhandled exception, the [Blazor error UI](xref:blazor/fundamentals/handle-errors#detailed-errors-during-development) is invoked.
### Assembly load logic in `OnNavigateAsync`
`OnNavigateAsync` has a `NavigationContext` parameter that provides information about the current asynchronous navigation event, including the target path (`Path`) and the cancellation token (`CancellationToken`):
* The `Path` property is the user's destination path relative to the app's base path, such as `/robot`.
* The `CancellationToken` can be used to observe the cancellation of the asynchronous task. `OnNavigateAsync` automatically cancels the currently running navigation task when the user navigates to a different page.
Inside `OnNavigateAsync`, implement logic to determine the assemblies to load. Options include:
* Conditional checks inside the `OnNavigateAsync` method.
* A lookup table that maps routes to assembly names, either injected into the component or implemented within the [`@code`](xref:mvc/views/razor#code) block.
`LazyAssemblyLoader` is a framework-provided singleton service for loading assemblies. Inject `LazyAssemblyLoader` into the `Router` component:
```razor
...
@using Microsoft.AspNetCore.Components.WebAssembly.Services
@inject LazyAssemblyLoader assemblyLoader
...
```
The `LazyAssemblyLoader` provides the `LoadAssembliesAsync` method that:
* Uses JS interop to fetch assemblies via a network call.
* Loads assemblies into the runtime executing on WebAssembly in the browser.
The framework's lazy loading implementation supports lazy loading with prerendering in a hosted Blazor solution. During prerendering, all assemblies, including those marked for lazy loading, are assumed to be loaded. Manually register `LazyAssemblyLoader` in the *Server* project's `Startup.ConfigureServices` method (`Startup.cs`):
```csharp
services.AddScoped();
```
### User interaction with `` content
While loading assemblies, which can take several seconds, the `Router` component can indicate to the user that a page transition is occurring:
* Add an [`@using`](xref:mvc/views/razor#using) directive for the namespace.
* Add a `` tag to the component with markup to display during page transition events.
```razor
...
@using Microsoft.AspNetCore.Components.Routing
...
Loading the requested page…
...
```
[!INCLUDE[](~/blazor/includes/prefer-exact-matches.md)]
### Handle cancellations in `OnNavigateAsync`
The `NavigationContext` object passed to the `OnNavigateAsync` callback contains a `CancellationToken` that's set when a new navigation event occurs. The `OnNavigateAsync` callback must throw when this cancellation token is set to avoid continuing to run the `OnNavigateAsync` callback on a outdated navigation.
If a user navigates to Route A and then immediately to Route B, the app shouldn't continue running the `OnNavigateAsync` callback for Route A:
```razor
@inject HttpClient Http
@inject ProductCatalog Products
...
@code {
private async Task OnNavigateAsync(NavigationContext context)
{
if (context.Path == "/about")
{
var stats = new Stats = { Page = "/about" };
await Http.PostAsJsonAsync("api/visited", stats, context.CancellationToken);
}
else if (context.Path == "/store")
{
var productIds = [345, 789, 135, 689];
foreach (var productId in productIds)
{
context.CancellationToken.ThrowIfCancellationRequested();
Products.Prefetch(productId);
}
}
}
}
```
[!INCLUDE[](~/blazor/includes/prefer-exact-matches.md)]
> [!NOTE]
> Not throwing if the cancellation token in `NavigationContext` is canceled can result in unintended behavior, such as rendering a component from a previous navigation.
### `OnNavigateAsync` events and renamed assembly files
The resource loader relies on the assembly names that are defined in the `blazor.boot.json` file. If [assemblies are renamed](xref:blazor/host-and-deploy/webassembly#change-the-filename-extension-of-dll-files), the assembly names used in `OnNavigateAsync` methods and the assembly names in the `blazor.boot.json` file are out of sync.
To rectify this:
* Check to see if the app is running in the Production environment when determining which assembly names to use.
* Store the renamed assembly names in a separate file and read from that file to determine what assembly name to use in the `LazyLoadAssemblyService` and `OnNavigateAsync` methods.
### Complete example
The following complete `Router` component demonstrates loading the `GrantImaharaRobotControls.dll` assembly when the user navigates to `/robot`. During page transitions, a styled message is displayed to the user.
```razor
@using System.Reflection
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.WebAssembly.Services
@inject LazyAssemblyLoader assemblyLoader
Loading the requested page…
Sorry, there's nothing at this address.
@code {
private List lazyLoadedAssemblies = new List();
private async Task OnNavigateAsync(NavigationContext args)
{
try
{
if (args.Path.EndsWith("/robot"))
{
var assemblies = await assemblyLoader.LoadAssembliesAsync(
new List() { "GrantImaharaRobotControls.dll" });
lazyLoadedAssemblies.AddRange(assemblies);
}
}
catch (Exception ex)
{
...
}
}
}
```
[!INCLUDE[](~/blazor/includes/prefer-exact-matches.md)]
## Troubleshoot
* If unexpected rendering occurs (for example, a component from a previous navigation is rendered), confirm that the code throws if the cancellation token is set.
* If assemblies are still loaded at application start, check that the assembly is marked as lazy loaded in the project file.
## Additional resources
*