Blazor - Usando Lazy Loading (.NET 5)

Hoje veremos como usar o recurso Lazy Loading do Blazor no ambiente do .NET 5.

Se você esta chegando agora e não sabe o que é o Blazor leia o artigo ASP .NET Core - Iniciando com o Blazor - Macoratti; se você já conhece e quer saber mais pode fazer o curso de Blazor Essencial.  

Blazor - Lazy Loading

O recurso Lazy Loading permite melhorar o desempenho de inicialização das aplicações WebAssembly adiando o carregamento de alguns assemblies do aplicativo até que eles sejam necessários.

O que é um assembly
  • Uma unidade lógica de código
  • Existe fisicamente como um arquivo EXE ou DLL
  • Pode conter um ou mais arquivos
  • Os arquivos que o compõem podem incluir qualquer tipo de arquivo como imagens , textos , etc.
  • Quando você compila o seu código fonte , por padrão , o arquivo EXE/DLL gerado é um assembly
  • Se o seu código não for empacotado como um assembly ele não poderá ser usado em qualquer outra aplicação
  • Ao falar da versão de um componente você estamos falando sobre a versão do assembly para  a qual o componente pertence

Por exemplo, os assemblies que são usados apenas para renderizar um único componente podem ser configurados para carregar somente se o usuário navegar até esse componente.  Após o carregamento, os assemblies são armazenados em cache do lado do cliente e estão disponíveis para todas as navegações futuras.

O recurso de Lazy Loading do Blazor permite que você marque assemblies de aplicativo para carregamento lento, que carrega os assemblies durante o runtime quando o usuário navega para uma rota específica.

Para habilitar o Lazy loading e assim adiar o carregamento de um assembly ou dll em uma aplicação Webassemly devemos
marcar os assemblies no arquivo de projeto .csproj criando um ItemGroup  e definindo o item BlazorWebAssemblyLazyLoad
incluindo o nome do arquivo assembly:

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

Com isso o Blazor impede que os assemblies especificados por este grupo de itens carreguem na inicialização do aplicativo. Se um assembly marcado tiver dependências elas também deverão ser marcadas no arquivo de projeto.

Carregando os assemblies sob demanda

Não basta habilitar o Lazy Loading a seguir teremos que definir a carga dos assemblies sob demanda quando o usuário navegar para o componente. Para isso podemos definir no arquivo App.razor estes arquivos usando o serviço LazyAssemblyLoader, e no evento OnNavigateAsync definir a lógica para escolher qual assembly deve ser carregado.

Para concluir devemos notificar o componente Router através da tag AdditionalAssemblies quais assembly ele deve renderizar.

Vamos demonstrar isso na prática criando um exemplo onde vamos criar uma aplicação WebAssembly padrão e a seguir incluir um projeto do tipo Class Library (.NET Standard) onde vamos definir uma classe com um método para incrementar um valor numérico de uma unidade.

A seguir iremos usar este método no componente Counter do projeto WebAssembly e mostrar como usar o Lazy loading.

Recursos usados:

Criando o projeto no VS Community 2019

Abra o VS 2019 Community (versão mínima 16.6) e selecione a opção Create a New Project;

A seguir selecione a opção Blazor app e clique em next;

Informe o nome do projeto :  Blazor_LazyLoading1 a localização e clique em Create;

Selecione a opção - Blazor WebAssembly App e clique no botão Create para criar o projeto.

Criando um novo projeto ContadorLazy

Vamos incluir um novo projeto do tipo Class Library chamado ContadorLazy no projeto.

A seguir vamos criar a classe Contador e o método estático Incrementar com o código abaixo:

    public class Contador
    {
        public static int Incrementar(int valor) => valor + 1;
    }

A seguir vamos incluir uma referência ao Projeto ContadorLazy no projeto Blazor_LazyLoading:

Agora vamos alterar o código do componente Counter da pasta Pages para usar o método Incrementar da classe Contador e assim implementar o contador:

@page "/counter"
<h1>Counter</h1>
<p>Current count: @currentCount</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
@code {
    private int currentCount = 0;
    private void IncrementCount()
    {
        currentCount = ContadorLazy.Contador.Incrementar(currentCount);
    }
}

Agora vamos executar o projeto e mostrar que a dll ContadorLazy.dll será carregada na carga do projeto conforme mostra a figura abaixo :

No Google Chrome: Pressione F12, selecione Application, ative o Cache Storage e digite o nome Contador para exibir as dlls que contenham este nome e que estão carregadas:

Temos assim que esta dll esta sendo carregada mesmo sem usarmos o componente.

Vamos habilitar o Lazy Loading para impedir esta carga na inicialização e a seguir vamos definir para carregar essa dll quando navegarmos para a rota 'counter'.

Habilitando o Lazy Loading

Para habilitar o Lazy Loading edite o arquivo de projeto da aplicação Blazor_LazyLoading e inclua o ItemGroup incluindo o nome  da dll que queremos retardar o carregamento conforme mostrado a seguir

<Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly">
  <PropertyGroup>
    <TargetFramework>net5.0</TargetFramework>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="5.0.0" />
    <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="5.0.0" PrivateAssets="all" />
    <PackageReference Include="System.Net.Http.Json" Version="5.0.0" />
  </ItemGroup>
	<ItemGroup>
		<BlazorWebAssemblyLazyLoad Include="ContadorLazy.dll" />
	</ItemGroup>
  <ItemGroup>
    <ProjectReference Include="..\ContadorLazy\ContadorLazy.csproj" />
  </ItemGroup>
</Project>

A seguir vamos definir no arquivo App.razor do projeto o código abaixo para carregar a dll ContadorLazy.dll apenas quando navegarmos para a rota 'counter' :

@inject LazyAssemblyLoader assemblyLoader
<Router AppAssembly="@typeof(Program).Assembly"
        AdditionalAssemblies="@lazyLoadedAssemblies"
        OnNavigateAsync="@OnNavigationAsync">
    <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 OnNavigationAsync(NavigationContext ctx)
    {
        if (ctx.Path.EndsWith("counter"))
        {
            var assemblies = await assemblyLoader.LoadAssembliesAsync(
                new List<string>() { "ContadorLazy.dll" }
                );

            lazyLoadedAssemblies.AddRange(assemblies);
        }
    }
}

Para este código funcionar ter que incluir os namespaces abaixo no arquivo _Imports.razor :

@using Microsoft.AspNetCore.Components.WebAssembly.Services
@using System.Reflection

Pronto ! já podemos testar o projeto e ver o Lazy Loading funcionando...

Executando o projeto teremos o resultado a seguir:

Vimos assim o recurso Lazy Loading que pode ser usado para melhorar o desempenho na inicialização das aplicações Blazor WebAssembly.

Pegue o projeto aqui:  Blazor_LazyLoading.zip (sem as referências)

E a vida eterna é esta: que te conheçam a ti, o único Deus verdadeiro, e a Jesus Cristo, a quem enviaste.
João 17:3
 


Referências:


José Carlos Macoratti