Como implementar upload de arquivos no ASP.NET MVC

Quando desenvolvemos aplicações web, é comum precisar de funcionalidades para adicionar imagens ou arquivos, como fotos de perfil de usuários, imagens de produtos, documentos anexados e muito mais. Implementar essa funcionalidade de forma eficiente e segura é essencial para uma boa experiência do usuário e para a integridade do sistema. Neste artigo vamos explorar como configurar o upload de arquivos em uma aplicação ASP.NET MVC, abordando cenários práticos, como salvar arquivos no sistema de arquivos local, armazená-los em um banco de dados.

Configurando o controlador para upload

Crie um controlador chamado “FileUploadController” com as seguintes ações:

				
					public class FileUploadController : Controller
{
public IActionResult Index() 
{
     return View();
};

[HttpPost]
public async Task<IActionResult> Upload(IFormFile file) 
{
   //código que recebe o arquivo.
}	
}

				
			

No código acima criamos duas actions no controlador “FileUploadController”. A primeira, “Index”, é responsável por exibir a tela com o formulário para envio de arquivos, onde o usuário poderá selecionar o arquivo desejado. 

Já a segunda, “Upload”, é a action que recebe o arquivo enviado pelo formulário. Para isso nós usamos a interface “IFormFile”, que é responsável por encapsular os dados do arquivo enviados pelo cliente e permitir o acesso diretamente no lado do servidor.

Mais adiante vamos detalhar a implementação da lógica na action “Upload” para processar o arquivo enviado pelo usuário. Esse método seguirá etapas para validar o arquivo e salvar o conteúdo de forma segura.

Criando a view com o formulário de upload

Agora vamos criar a view com o nome “Index.cshtml” com o nosso formulário:

				
					<form asp-controller="FileUpload" asp-action="Upload" method="post" enctype="multipart/form-data">
    <div class="form-group">
        <label for="file">Escolha o arquivo:</label>
        <input type="file" class="form-control" />
    </div>
    <button type="submit" class="btn btn-primary">Enviar</button>
</form>

				
			

No codigo acima, nós criamos um formulário informando que ele deve ser enviado para action “Upload” que está na controller “FileUpload”.

Logo abaixo, vamos adicionar as mensagens que serão retornadas em caso de erro ou sucesso:

				
					@if (TempData["Message"] != null)
{
    <div class="alert alert-success">@TempData["Message"]</div>
}


@foreach (var error in ViewData.ModelState.Values.SelectMany(v => v.Errors))
{
    <div class="alert alert-danger">@error.ErrorMessage</div>
}

				
			

Validando o se o arquivo é válido

A primeira validação é para saber se foi enviado um arquivo válido.

				
					if (file == null || file.Length == 0)
        {
            ModelState.AddModelError("", "Selecione um arquivo válido.");
            return View("Index");
        }

				
			

Se o arquivo recebido for nulo ou tiver tamanho zero, o sistema exibirá uma mensagem de erro informando o problema e redirecionará o usuário de volta à tela inicial (Index). Isso evita processar uploads inválidos.

Validação de extensão

Agora vamos adicionar uma validação para aceitar apenas arquivos com determinadas extensões.

				
					var allowedExtensions = new[] { ".jpg", ".png", ".pdf" };
var extension = Path.GetExtension(file.FileName).ToLower();

if (!allowedExtensions.Contains(extension))
{
    ModelState.AddModelError("", "Formato de arquivo não permitido.");
    return View("Index");
}

				
			

Nesta etapa, permitimos apenas arquivos com as extensões .jpg, .png e .pdf. Qualquer outro formato será rejeitado com uma mensagem de erro. Isso protege a aplicação de uploads de arquivos maliciosos.

Validação de tamanho máximo

Além disso, teremos uma validação tamanho máximo do arquivo.

				
					 if (file.Length > 5 * 1024 * 1024)
{
    ModelState.AddModelError("", "O arquivo não pode exceder 5 MB.");
    return View("Index");
}

				
			

Isso vai evitar sobrecarga no servidor e uploads indesejados, impomos um limite de tamanho (5 MB). Arquivos maiores serão rejeitados com uma mensagem adequada.

Armazenando o arquivo na aplicação

Agora que adicionamos as validações, vamos armazenar o arquivo na aplicação, garantindo que a pasta de destino exista antes de salvar o arquivo.

Primeiro, definimos o diretório onde os arquivos serão armazenados:

				
					var uploadDirectory = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot/uploads");
				
			

Aqui, indicamos que os arquivos serão salvos na pasta “wwwroot/uploads”. Caso essa pasta não exista, podemos criá-la da seguinte forma:

				
					if (!Directory.Exists(uploadDirectory))
{
    Directory.CreateDirectory(uploadDirectory);
}

				
			

Essa verificação evita erros no caso de a pasta ainda não estar criada no servidor ou em ambientes de desenvolvimento.

Em seguida, definimos o caminho completo para o arquivo:

				
					var filePath = Path.Combine(uploadDirectory, file.FileName);
				
			

Agora, usamos um FileStream para gravar os dados do arquivo no local especificado:

				
					using (var stream = new FileStream(filePath, FileMode.Create))
{
    await file.CopyToAsync(stream);
}

				
			

Essa operação realiza a gravação de forma assíncrona, permitindo que a aplicação permaneça responsiva mesmo durante o upload de arquivos.

				
					//Implementar lógica de gravação do nome do arquivo no banco.

TempData["Message"] = "Arquivo enviado com sucesso!";
return RedirectToAction("Index");

				
			
Após salvar o arquivo, você pode implementar um procedimento para salvar as informações do arquivo (nome, extensão …) no banco de dados. Após isso, armazenamos uma mensagem de sucesso em “TempData” e redirecionamos o usuário de volta à tela inicial.

Essa mensagem será exibida na view para confirmar que o upload foi concluído.

Salvando em banco de dados

Para salvar uma imagem diretamente no banco de dados você pode criar uma entidade “FileRecord” para armazenar as informações do arquivo. Nesta entidade a propriedade “Data” armazena os dados reais do arquivo em formato binário (array de bytes). É nessa propriedade que os dados do arquivo serão salvos.

				
					public class FileRecord
{
    public int Id { get; set; }
    public string FileName { get; set; }
    public string ContentType { get; set; }
    public byte[] Data { get; set; }
}

				
			

Agora podemos reaproveitar a action que “Upload” que criamos anteriormente para processar o arquivo recebido.

				
					public async Task<IActionResult> Upload(IFormFile file)
{
	
     //Adicione as validações do arquivo recebido.

    using var memoryStream = new MemoryStream();
    await file.CopyToAsync(memoryStream);

    var fileRecord = new FileRecord
    {
        FileName = file.FileName,
        ContentType = file.ContentType,
        Data = memoryStream.ToArray()
    };

    context.FileRecords.Add(fileRecord);
    await context.SaveChangesAsync();

    return RedirectToAction("Index");
}

				
			

Primeiro, criamos uma variável do tipo “MemoryStream”, que serve para armazenar temporariamente os dados do arquivo em memória. 

Em seguida, utilizamos o método “CopyToAsync” do arquivo enviado (file), que copia os dados do arquivo diretamente para o “memoryStream”.

Após obter os dados do arquivo, criamos uma entidade do tipo “FileRecord”, que representa a estrutura do arquivo que será salvo no banco de dados.

Com a entidade “fileRecord” criada e preenchida, nós a adicionamos ao banco de dados usando o método “Add” no contexto da aplicação (context).

Concluímos redirecionando o fluxo para a view “Index”, proporcionando uma experiência contínua e amigável.

Observação: Neste exemplo, não incluímos validações específicas para o arquivo recebido. Entretanto, em aplicações reais, é recomendável implementar validações para garantir segurança e consistência.

Dicas de segurança

  • Validação do tipo de arquivo: verifique a extensão.
  • Limitação de tamanho: defina um limite para evitar sobrecarga no servidor.
  • Evite substituição de arquivos: use nomes únicos para arquivos (ex.: GUIDs).
  • Armazenamento Isolado: salve os arquivos fora do diretório acessível pelo cliente, se possível.

Acelere a sua carreira conosco!

Se você é Desenvolvedor .NET Júnior e quer acelerar sua carreira até nível Pleno com salário de R$7k+, ou mesmo busca a primeira vaga, conheça a Mentoria .NET StartClique aqui

Se é Desenvolvedor .NET Pleno ou Sênior e quer virar referência técnica em sua equipe e mercado, com salário de R$10k+, conheça a Mentoria .NET ExpertClique aqui

Conclusão

O upload de arquivos em uma aplicação ASP.NET MVC pode ser configurado para diferentes cenários de armazenamento. Este guia cobriu desde a configuração básica até integrações com bancos de dados. Certifique-se de validar os arquivos e seguir as práticas recomendadas para evitar vulnerabilidades.