Blazor - Upload de arquivos (InteractiveServer) - III


   Neste artigo veremos como realizar o upload de arquivos no Blazor usando o modo de renderização InteractiveServer.

Continuando o artigo anterior vamos concluir a implementação criando os componentes Blazor.

Definindo o menu

Na pasta Components/Layout vamos ajustar o código do arquivo NavMenu conforme abaixo:

...
<div class="nav-scrollable" onclick="document.querySelector('.navbar-toggler').click()">
    <nav class="flex-column">
        <div class="nav-item px-3">
            <NavLink class="nav-link" href="" Match="NavLinkMatch.All">
                <span class="bi bi-house-door-fill-nav-menu" aria-hidden="true"></span> Home
            </NavLink>
        </div>
       <div class="nav-item px-3">
            <NavLink class="nav-link" href="uploadserver">
                <span class="bi bi-list-nested-nav-menu" aria-hidden="true"></span> Upload 
            </NavLink>
        </div>
        <div class="nav-item px-3">
            <NavLink class="nav-link" href="exibirarquivos">
                <span class="bi bi-list-nested-nav-menu" aria-hidden="true"></span> Ver Arquivos
            </NavLink>
        </div>
    </nav>
</div>

A seguir vamos incluir no arquivo _Imports.razor o código abaixo:

@using System.Net.Http
@using System.Net.Http.Json
@using Microsoft.AspNetCore.Components.Forms
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.Web
@using static Microsoft.AspNetCore.Components.Web.RenderMode
@using Microsoft.AspNetCore.Components.Web.Virtualization
@using Microsoft.JSInterop
@using BlazorUploads
@using BlazorUploads.Components
@using BlazorUploads.Repositories
@using BlazorUploads.Services
@using BlazorUploads.Context
@using BlazorUploads.Entities
@using Microsoft.Net.Http.Headers
@inject HttpClient client
@inject IWebHostEnvironment env
@inject IUploadService _uploadService
@inject IUploadRepository _uploadRepository

Vamos ajustar o código do componente Home.razor conforme o código a seguir:

@page "/"
<PageTitle>Home</PageTitle>
<h1>Upload de arquivos</h1>
<img src="/uploads1.jpg"/>

Criando o componente para enviar arquivos

Vamos criar na pasta Components/Pages o componente UploadServer.razor  que vai enviar arquivos para o servidor:

@page "/uploadserver"
@rendermode InteractiveServer
<h3>Upload de arquivos (InteractiveServer)</h3>
<EditForm Model="@arquivoUpload" OnValidSubmit="@HandleFormSubmit" 
enctype="multipart/form-data">
    Selecione até 5 arquivo(s): <InputFile OnChange="@SelectFiles" multiple />
    <br />
    <button type="submit">Enviar</button>
</EditForm>
@if (arquivos.Count > 0)
{
    <li>Arquivos selecionados </li>
    <ul>
        @foreach (var arq in arquivos)
        {
            <li>@arq.Name @arq.Size bytes</li>
        }
    </ul>
}
<br />
<ul>
    @foreach (var mensagem in mensagens)
    {
        <li>
            @mensagem
        </li>
    }
</ul>
@code {
    List<string> mensagens = new();
    List<IBrowserFile> arquivos = new();
    int tamanhoMaximoArquivo = 1 * 1024 * 1024; //1 MB
    ArquivoUpload arquivoUpload = new();
    List<ArquivoUpload> uploads = new();
    private void SelectFiles(InputFileChangeEventArgs e)
    {
        arquivos = e.GetMultipleFiles(tamanhoMaximoArquivo).ToList();
    }
    private async Task HandleFormSubmit()
    {
        mensagens.Clear();
        var extensoesPermitidas = new string[] { ".png", ".jpg", ".jpeg", ".gif" };
        int contador = 0;
        mensagens.Add("Arquivo(s) enviado(s)  ");
        foreach (var arquivo in arquivos)
        {
            try
            {
                (int statusCode, string statusMessage) =
                    await _uploadService.ArquivoUploadAsync(arquivo,
                                                            tamanhoMaximoArquivo,
                                                            extensoesPermitidas);
                if (statusCode == 1)
                {
                    mensagens.Add($" {arquivo.Name} ");
                    var arquivoDados = new ArquivoUpload
                    {
                            NomeArquivoUpload = statusMessage
                    };
                    // salva imagem no banco de dados
                    await _uploadRepository.UploadArquivoDb(arquivoDados);
                    uploads.Add(arquivoDados);
                    contador++;
                }
                else
                {
                    mensagens.Add(statusMessage);
                }
            }
            catch (Exception ex)
            {
                mensagens.Add($"Arquivo : {arquivo.Name} Erro : {ex.Message}");
            }
        }
        mensagens.Add($" {contador}/{arquivos.Count} enviado(s)");
    }
}
Este código Blazor cria uma página para fazer o upload de arquivos para um servidor usando o modelo de Blazor com renderização interativa no lado do servidor (@rendermode InteractiveServer). Vamos explicar cada parte do código:
  1. @page "/uploadserver": Define a URL da página como "/uploadserver".
  2. @rendermode InteractiveServer: Define o modo de renderização como InteractiveServer, indicando que a lógica da página será executada no servidor.
  3. <h3>...</h3>: Título da página.
  4. <EditForm>...</EditForm>: Um formulário de edição Blazor que usa um modelo (Model="@arquivoUpload") para rastrear os dados do arquivo a serem enviados.
    O método OnValidSubmit="@HandleFormSubmit" será chamado quando o formulário for enviado.
    • <InputFile OnChange="@SelectFiles" multiple />: Um componente Blazor para selecionar arquivos. O método SelectFiles é chamado quando os arquivos são selecionados.
    • <button type="submit">Enviar</button>: Botão para enviar o formulário.
  5. @if (arquivos.Count > 0): Se há arquivos selecionados, exibe informações sobre esses arquivos.
  6. <li>...</li>...: Lista os arquivos selecionados, exibindo seus nomes e tamanhos.
  7. @foreach (var mensagem in mensagens): Exibe mensagens, como erros ou confirmações de envio.
  8. @code {...}: Bloco de código C# incorporado na página Blazor.
    • List<string> mensagens = new();: Lista para armazenar mensagens exibidas na página.
    • List<IBrowserFile> arquivos = new();: Lista para armazenar os arquivos selecionados.
    • int tamanhoMaximoArquivo = 1 * 1024 * 1024; //1 MB: Define o tamanho máximo permitido para o arquivo (1 MB).
    • ArquivoUpload arquivoUpload = new();: Instância do modelo ArquivoUpload para rastrear os dados do arquivo a serem enviados.
    • List<ArquivoUpload> uploads = new();: Lista para armazenar informações sobre os arquivos enviados.
    • SelectFiles(InputFileChangeEventArgs e): Método chamado quando os arquivos são selecionados. Atualiza a lista de arquivos (arquivos).
    • async Task HandleFormSubmit(): Método chamado quando o formulário é enviado. Limpa as mensagens, valida os arquivos e envia para o servidor. Atualiza as mensagens com o resultado do envio.
    • A lógica dentro do loop foreach itera sobre os arquivos, chama o serviço de upload (_uploadService.ArquivoUploadAsync) e atualiza as mensagens de acordo.
    • _uploadRepository.UploadArquivoDb(arquivoDados): Salva informações sobre o arquivo no banco de dados.
    • Finalmente, as mensagens são atualizadas para refletir o número de arquivos enviados com sucesso.

A seguir vamos criar o componente ExibirArquivos.razor usando o seguinte código:

@page "/exibirarquivos"
@rendermode InteractiveServer
<h3>Arquivos Armazenados</h3>
@if (arquivos != null && arquivos.Any())
{
    <div class="file-list">
        @foreach (var arquivo in arquivos)
        {
            <div class="file-item">
                <img src="\uploads\@arquivo.NomeArquivoUpload" alt="arquivo" />
                <p>@arquivo.NomeArquivoUpload</p>
                <button @onclick="() => ExcluirArquivo(arquivo.Id)">Excluir</button>
            </div>
        }
    </div>
}
else
{
    <li>Nenhum arquivo encontrado</li>
}
@code{
    private IEnumerable<ArquivoUpload>? arquivos;
    protected override async Task OnInitializedAsync()
    {
        await CarregaImagens();
    }
    private async Task ExcluirArquivo(int arquivoId)
    {
        await _uploadRepository.DeletaArquivo(arquivoId);
        arquivos = await _uploadRepository.GetArquivos();
    }
    private async Task CarregaImagens()
    {
        arquivos = await _uploadRepository.GetArquivos();
    }
}

Este código exibe os arquivos salvos no banco de dados SQLite e permite excluir os arquivos da tabela sem contudo excluir os arquivos da pasta uploads.

Agora vamos definir um estilo vinculado a este componente criando o arquivo ExibirArquivos.razor.css com este código:

.file-list {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between; 
}
.file-item {
    margin: 5px;
    text-align: center;
}
img {
    max-width: 120px; /* Tamanho máximo da imagem */
    max-height: 120px;
    border: 1px solid #ccc; 
}
/*.file-item:hover {
    transform: scale(3.0); 
}*/

Executando o projeto teremos o seguinte resultado:

1- Pagina inicial

2- Enviando arquivos

3- Visualizando arquivos

Baixe o projeto aqui :   https://github.com/macoratti/BlazorUploads-InteractiveServer

"Porque pela graça sois salvos, por meio da fé; e isto não vem de vós, é dom de Deus.
Não vem das obras, para que ninguém se glorie"
Efésios 2:8,9


Referências:


José Carlos Macoratti