Dll Error in A Blazor WebAssembly Application

A Blazor WebAssembly application first downloads all of its DLLs when it launches. A DLL is therefore loaded when the app loads, even if it is only used in one particular page. Delaying the loading of some application assemblies until they are needed can enhance startup performance.

Lazy Loading Assemblies

First, you need to edit the project file (csproj) and add the list of lazy-loaded assemblies using <BlazorWebAssemblyLazyLoad>:

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

  <PropertyGroup>
    <TargetFramework>net5.0</TargetFramework>
    <RuntimeIdentifier>browser-wasm</RuntimeIdentifier>
    <UseBlazorWebAssembly>true</UseBlazorWebAssembly>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="5.0.0-preview.8.20414.8" />
    <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="5.0.0-preview.8.20414.8" PrivateAssets="all" />
    <PackageReference Include="YamlDotNet" Version="8.1.2" />
  </ItemGroup>

  <ItemGroup>
    <BlazorWebAssemblyLazyLoad Include="YamlDotNet" />
  </ItemGroup>
</Project>

This will change the way the blazor.boot.json file is generated. You should see a new section named lazyAssembly:

Now, if you visit a page that requires the DLL but it is not loaded, an error will appear:

blazor.webassembly.js:1 crit: Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100]
Unhandled exception rendering component: Could not load file or assembly 'YamlDotNet, Version=8.0.0.0, Culture=neutral, PublicKeyToken=ec19458f3c15af5e' or one of its dependencies.
System.IO.FileNotFoundException: Could not load file or assembly 'YamlDotNet, Version=8.0.0.0, Culture=neutral, PublicKeyToken=ec19458f3c15af5e' or one of its dependencies.
File name: 'YamlDotNet, Version=8.0.0.0, Culture=neutral, PublicKeyToken=ec19458f3c15af5e'
   at OnlineTools.Pages.YamlToJson.BuildRenderTree(RenderTreeBuilder __builder) in C:\Users\meziantou\source\repos\meziantou\online-tools\OnlineTools\Pages\YamlToJson.razor:line 0
   at Microsoft.AspNetCore.Components.ComponentBase.<.ctor>b__6_0(RenderTreeBuilder builder)
   at Microsoft.AspNetCore.Components.Rendering.ComponentState.RenderIntoBatch(RenderBatchBuilder batchBuilder, RenderFragment renderFragment)
   at Microsoft.AspNetCore.Components.RenderTree.Renderer.RenderInExistingBatch(RenderQueueEntry renderQueueEntry)
   at Microsoft.AspNetCore.Components.RenderTree.Renderer.ProcessRenderQueue()

You must load the DLL before accessing the page in order to resolve this error. When a user navigates to the page, you can use the OnNavigateAsync router event to stop the navigation and load the DLL. You must modify the App.razor component to accomplish this.

@inject Microsoft.AspNetCore.Components.WebAssembly.Services.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<System.Reflection.Assembly> lazyLoadedAssemblies = new List<System.Reflection.Assembly>();

    private async Task OnNavigateAsync(NavigationContext context)
    {
        if (context.Path == "yaml-to-json") // Url of the page that needs the lazy loaded assembly
        {
            var assemblies = await AssemblyLoader.LoadAssembliesAsync(new[] { "YamlDotNet.dll" });
            lazyLoadedAssemblies.AddRange(assemblies);
        }
    }
}

This will alter the process used to create the blazor.boot.json file. There ought to be a new section there called lazyAssembly.

Now, if you visit a page that requires the DLL but it is not loaded, an error will appear:

blazor.webassembly.js:1 crit: Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100]
Unhandled exception rendering component: Could not load file or assembly 'YamlDotNet, Version=8.0.0.0, Culture=neutral, PublicKeyToken=ec19458f3c15af5e' or one of its dependencies.
System.IO.FileNotFoundException: Could not load file or assembly 'YamlDotNet, Version=8.0.0.0, Culture=neutral, PublicKeyToken=ec19458f3c15af5e' or one of its dependencies.
File name: 'YamlDotNet, Version=8.0.0.0, Culture=neutral, PublicKeyToken=ec19458f3c15af5e'
   at OnlineTools.Pages.YamlToJson.BuildRenderTree(RenderTreeBuilder __builder) in C:\Users\meziantou\source\repos\meziantou\online-tools\OnlineTools\Pages\YamlToJson.razor:line 0
   at Microsoft.AspNetCore.Components.ComponentBase.<.ctor>b__6_0(RenderTreeBuilder builder)
   at Microsoft.AspNetCore.Components.Rendering.ComponentState.RenderIntoBatch(RenderBatchBuilder batchBuilder, RenderFragment renderFragment)
   at Microsoft.AspNetCore.Components.RenderTree.Renderer.RenderInExistingBatch(RenderQueueEntry renderQueueEntry)
   at Microsoft.AspNetCore.Components.RenderTree.Renderer.ProcessRenderQueue()

You must load the DLL before accessing the page in order to resolve this error. When a user navigates to the page, you can use the OnNavigateAsync router event to stop the navigation and load the DLL. You must modify the App.razor component to accomplish this.

@inject Microsoft.AspNetCore.Components.WebAssembly.Services.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<System.Reflection.Assembly> lazyLoadedAssemblies = new List<System.Reflection.Assembly>();

    private async Task OnNavigateAsync(NavigationContext context)
    {
        if (context.Path == "yaml-to-json") // Url of the page that needs the lazy loaded assembly
        {
            var assemblies = await AssemblyLoader.LoadAssembliesAsync(new[] { "YamlDotNet.dll" });
            lazyLoadedAssemblies.AddRange(assemblies);
        }
    }
}
  • AssemblyLoader.LoadAssembliesAsync will fetch the assemblies requested via a network call and load them into the runtime.
  • AdditionalAssemblies is optional. It configures the router to search components that can match URIs in the lazy loaded assemblies. If the lazy-loaded DLLs don’t contain any component, you can remove it.

When loading DLLs, displaying a loading indicator

It might take a while to load the lazy-loaded assemblies. You can display a loading indicator during this time to let the user know something is happening.

<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> 
    <Navigating>
        <p>Loading the page...</p>
    </Navigating>
</Router>

 

 

Related Posts

Leave a Reply

Your email address will not be published. Required fields are marked *