In this article, we are going to learn how to implement Lazy Loading in Blazor WebAssembly. Lazy Loading enables us to improve the startup speed of our Blazor WebAssembly application by delaying the download of the resources we do not require yet. For example, if we have a large Blazor WebAssembly application, and our users just want to access the home or the contact page, there is no point in downloading all those files related to the products, authentication, etc. With lazy loading implemented, the app will download all these resources only when the user asks for them.

To download the source code for this article, you can visit our Lazy Loading in Blazor WebAssembly repository.

We are going to divide this article into the following sections:

So let’s get started.

A New Blazor WebAssembly Project Creation

We are going to start by creating a new project and then explaining how to implement Lazy Loading in Blazor WebAssembly with an example.

That said, let’s create a new Blazor WebAssembly project:

Lazy loading in blazor webassembly - project creation

You can choose any name you want, but we named it Blazor WasmLazyLoading.

We are going to modify the launchSettings.json file and remove the IIS profile and iisSettings:

{
  "profiles": {
    "BlazorWasmLazyLoading": {
      "commandName": "Project",
      "dotnetRunMessages": "true",
      "launchBrowser": true,
      "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}",
      "applicationUrl": "https://localhost:5001;http://localhost:5000",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    }
  }
}

Now, if we start our application, open the Dev Tools window (F12), navigate to the Application tab, and inspect the cache:

Entire dll i downloaded and cached at the start of application

We can see that our BlazorWasmLazyLoading.dll file is downloaded and cached, which is a normal thing, but this also means that all the components in this DLL are downloaded, even though we are still on the Home page, and didn’t navigate anywhere else. Of course, for small applications like this one, this is not an issue at all. But for the larger application, it could increase the download speed significantly. So, let’s learn how to prevent that.

Adding a new Razor Class Library to Extract Components from the Main Project

In our main project, next to the Home page, we have the Counter and FetchData pages. The FetchData page just fetches the data from the local file and displays them on the screen. In a real-world project, a component like this one would fetch data from a server and have a lot of child components like paging, sorting, filtering, searching, edit, update, etc. As you can see, a lot of resources to download even if we never navigate to the FetchData page. That said, we can agree that this component is a perfect one for our lazy loading example.

So, let’s create a new Razor class library project, name it Weather, and remove everything inside it except the _Imports.razor file. Also, we have to reference this project from the main one:

New Weather Razor Class Library

Now, let’s move the FetchData component file from the main project to the Weather project.

After we move the component file, we have to add required namespaces to the _Import.razor file in the Weather project:

@using Microsoft.AspNetCore.Components.Web
@using System.Net.Http
@using System.Net.Http.Json

These two namespaces are required for the HttpClient logic inside the FetchData component.

At this point, we have our two projects, but just because we created a new project it doesn’t mean it will not load as soon as the application starts. Well, we can confirm this by just starting our application and inspecting the cache as we previously did:

Weather project loaded as soon as application starts.

You can see that we are on the Home page, but nevertheless, the Weather.dll is downloaded. This means, we require an additional logic here, but at least, we are on the right track.

Implementing Lazy Loading in Blazor WebAssembly

In order to implement Lazy Loading in Blazor WebAssembly, we have to start with the main project file modification. So, let’s right-click on the BlazorWasmLazyLoading project and choose the EditProjectFile option:

<Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly">

    <PropertyGroup>
        <TargetFramework>net5.0</TargetFramework>
    </PropertyGroup>

    <ItemGroup>
        <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="5.0.0-rc.2.20475.17" />
        <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="5.0.0-rc.2.20475.17" PrivateAssets="all" />
        <PackageReference Include="System.Net.Http.Json" Version="5.0.0-rc.2.20475.5" />
    </ItemGroup>

    <ItemGroup>
        <ProjectReference Include="..\Weather\Weather.csproj" />
    </ItemGroup>

    <ItemGroup>
        <BlazorWebAssemblyLazyLoad Include="Weather.dll" />
    </ItemGroup>

</Project>

We have to use the BlazorWebAssemblyLazyLoad item group to delay the loading of an assembly. That’s exactly what we do here.

Now, let’s save a file and rebuild a solution.

After that, we can start the project and inspect the cache files:

Lazy Loading in Blazor WebAssembly disables caching

We can’t see the Weather.dll anymore. So, this means it is not loaded yet, which is great. Also, if we navigate to the Network tab, refresh the page, and inspect the blazor.boot.json file:

Weather dll loaded as lazy assembly

We can see that the lazyAssembly property is populated now (previously it was null).

Great.

But as soon as we try to navigate to the FetchData page, we are going to get a generic not found page instead. That’s because we need to load the Weather.dll before we navigate to the FetchData page.

Modifying App.razor File to Load the Required DLL

Let’s open the App.razor file and modify it:

@using System.Reflection
@using Microsoft.AspNetCore.Components.WebAssembly.Services
@inject LazyAssemblyLoader AssemblyLoader

<Router AppAssembly="@typeof(Program).Assembly"
        OnNavigateAsync="OnNavigateAsync"
        AdditionalAssemblies="_lazyLoadedAssemblies">
    <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 context)
    {
        if (context.Path == "fetchdata")
        {
            var assemblies = await AssemblyLoader.LoadAssembliesAsync(new[] { "Weather.dll" });
            _lazyLoadedAssemblies.AddRange(assemblies);
        }
    }
}

First, we import the required using directives and inject the AssemblyLoader to be able to load our assembly. Then in the Router component, we assign the OnNavigateAsync method to the OnNavigateAsync event callback. The OnNavigateAsync event callback triggers the event before navigating to a new page. Also, we populate the AdditionalAssemblies property. This property sets additional assemblies, from our application, to search for the components that match the required URIs.

In the @code part, we create a private list of assemblies named _lazyLoadedAssemblies and the OnNavigateAsync method with the NavigationContext parameter. Inside the method, we use the context parameter to check the currently required route. If it matches the fetchdata, which is the route of our FetchData component, we use the LoadAssembliesAsync method to load the Weather.dll dependency when the user navigates to the fetchdata route, and then add it to a _lazyLoadedAssemblies list.

Good.

As we remember, if we start the app and inspect the cache, we won’t be able to find the Weather.dll downloaded for sure. But, as soon as we navigate to the FetchData page, we are going to see the content of the page and also we can see the dependencies downloaded:

Implemented Lazy Loading in Blazor WebAssembly

This means, that only when we require some resources, our application will download them, which is exactly what we want.

Conclusion

Right now, we know how to load different dependencies only when we require them by using Lazy Loading in Blazor WebAssembly. As we said, this is a great feature because it allows us to speed up the loading time of our application.

Until the next article,

All the best.