Blazor 
- Upload de 
arquivos (Static Server) - I
    
       | 
    Neste artigo veremos como realizar o upload de arquivos no Blazor usando o modo de renderização Static Server Rendering. | 
Este é o modo padrão de renderização quando você não definir outro modo de renderização.
Funciona assim:

A renderização 
estática do lado do servidor é útil onde os componentes não precisam ser 
interativos.
Esse modo de renderização é simples e rápido e não exige que o componente viva 
por mais tempo do que a resposta HTML leva para ser renderizada e devolvida
Destacando que o modo de renderização Static Server Rendering é o modo de renderização padrão para aplicações Blazor no .NET 8 (sem interatividade)
Vejamos agora alguns conceitos importantes relacionados com este modo de renderização :
Criando o projeto
Vamos criar um novo projeto usando o template Blazor Web App usando o VS 2022 com o nome BlazorUploadSSR :

Definindo as seguintes configurações:

Neste projeto além de enviar arquivos para o servidor vamos também salvar o caminho do arquivo enviado em um banco de dados SQLite e a seguir usar essa informação para exibir as imagens.
Para isso vamos incluir no projeto o pacote nuget: Microsoft.EntityFrameworkCore.Sqlite
Vamos também criar na pasta wwwroot do projeto a pasta uploads para receber os arquivos enviados.
Para representar o arquivo que iremos salvar vamos criar uma pasta Entities e nesta pasta vamos cria a classe ArquivoDatabase:
		public class ArquivoDatabase
{
    public int Id { get; set; }
    public string? NomeArquivoUpload { get; set; }
}
		 | 
	
Vamos criar a pasta Context no projeto e nesta pasta criar a classe de contexto AppDbContext:
		public class AppDbContext : DbContext
{
    public AppDbContext(DbContextOptions options) : base(options)
    { }
    public DbSet<ArquivoUpload> ArquivosUploads { get; set; }
}
		 | 
	
Aqui definimos o mapeamento ORM da entidade para a tabela no SQLite.
A seguir na classe Program vamos registrar o contexto no contêiner DI :
		var connectionString = builder.Configuration.GetConnectionString("Sqlite");
builder.Services.AddDbContext<AppDbContext>(opt => 
                               opt.UseSqlite(connectionString));
		 | 
	
Neste código a string de conexão esta sendo obtida do arquivo appsettings.json:
		{
  "ConnectionStrings": {
    "Sqlite": "data source=ArquivosDB"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*"
}
		 | 
	
Aqui definimos que o nome do banco a ser criado será ArquivosDB.
Criando o Repositório
Para poder realizar operações com o banco de dados SQLite vamos criar uma pasta Repositories no projeto e nesta pasta vamos criar a interface IUploadRepository e sua implementação que será feita na classe concreta UploadRepository.
Aqui estamos usando o seguinte código:
IUploadRepository
		public interface IUploadRepository
{
    Task UploadArquivoDb(ArquivoUpload arquivo);
    Task<IEnumerable<ArquivoUpload>> GetArquivos();
    Task<ArquivoUpload> GetArquivo(int id);
    Task DeletaArquivo(int id);
}
		 | 
	
UploadRepository
		public class UploadRepository : IUploadRepository
{
    private readonly AppDbContext _context;
    public UploadRepository(AppDbContext context)
    {
        _context = context ?? throw new ArgumentNullException(nameof(context));
    }
		    public async Task UploadArquivoDb(ArquivoUpload arquivo)
    {
        _context.ArquivosUploads.Add(arquivo);
        await _context.SaveChangesAsync();
    }
		    public async Task<IEnumerable<ArquivoUpload>> GetArquivos()
    {
        return await _context.ArquivosUploads.ToListAsync();
    }
		    public async Task DeletaArquivo(int id)
    {
        var arquivo = await GetArquivo(id);
		        if (arquivo is not null)
        {
            _context.Remove(arquivo);
            await _context.SaveChangesAsync();
        }
    }
		    public async Task<ArquivoUpload> GetArquivo(int id)
    {
        var arquivo = await _context.ArquivosUploads.FirstOrDefaultAsync(a => a.Id == id);
        return arquivo;
    }
}
		 | 
	
Agora não podemos esquecer de registrar o serviço do contexto e do serviço do repositório no contêiner DI:
		var builder = WebApplication.CreateBuilder(args); // Add services to the container.
builder.Services.AddRazorComponents()
    .AddInteractiveServerComponents();
		var connectionString = builder.Configuration.GetConnectionString("Sqlite");
		builder.Services.AddDbContext<AppDbContext>(opt =>
                                  opt.UseSqlite(connectionString));
		
		builder.Services.AddTransient<IUploadRepository, UploadRepository>();  | 
	
Para poder criar o banco de dados SQLite sem aplicar o Migrations vamos criar o método CreateDatabase na classe Program conforme o código a seguir:
		var builder = WebApplication.CreateBuilder(args);
		...
var app = builder.Build();
CreateDatabase(app);
...
app.Run();
		static void CreateDatabase(WebApplication app)
{
    var serviceScope = app.Services.CreateScope();
    var dataContext = serviceScope.ServiceProvider.GetService<AppDbContext>();
    dataContext?.Database.EnsureCreated();
}
		 | 
	
Com isso na primeira execução do projeto, o banco de dados ArquivosDB será criado.
Com isso temos 
tudo pronto para criar os componentes Blazor e faremos isso 
no próximo artigo. ![]()
"Na verdade, na verdade vos digo que quem ouve a minha palavra, e crê naquele 
que me enviou, tem a vida eterna, e não entrará em condenação, mas passou da 
morte para a vida."
João 
5:24

Referências:
C# - Tasks x Threads. Qual a diferença
DateTime - Macoratti.net
Null o que é isso ? - Macoratti.net
Formatação de data e hora para uma cultura ...
C# - Calculando a diferença entre duas datas
NET - Padrão de Projeto - Null Object Pattern
C# - Fundamentos : Definindo DateTime como Null ...
C# - Os tipos Nullable (Tipos Anuláveis)