ASP.NET Core -  Enviando Arquivos para um API


 Neste artigo vamos recordar como enviar um arquivo para uma API usando o HttpClient.

Hoje veremos como enviar arquivos para uma Web API que ao receber os arquivos vai salvar estes arquivos na pasta wwwroot do projeto no servidor.

recursos usados:

Criando o projeto Web API

Vamos criar um novo projeto ASP .NET Core Web API chamado ApiArquivos usando o .NET 6.

Vamos remover o controlador e a classe usada pelo controlador criado pelo template e criar no projeto a pasta wwwroot.

A seguir crie no projeto a pasta Services e nesta pasta crie a classe SalvarArquivosApi:

public class SalvaArquivosApi
{
    private readonly IWebHostEnvironment env;
    public SalvaArquivosApi(IWebHostEnvironment env)
    {
        this.env = env;
    }
    public async Task Salvar(IFormFile arquivo, string nomePasta)
    {
        var nomeArquivo = $"{Guid.NewGuid()}{Path.GetExtension(arquivo.FileName)}";
        string caminhoArquivoServidor = Path.Combine(env.WebRootPath, nomePasta);
        if (!Directory.Exists(nomePasta))
        {
            Directory.CreateDirectory(nomePasta);
        }

         string caminhoArquivo = Path.Combine(caminhoArquivoServidor, nomeArquivo);

        using (FileStream fileStream = File.Create(caminhoArquivo))
        {
            await arquivo.OpenReadStream().CopyToAsync(fileStream);
        }
    }
}

Neste código injetamos uma instância de IWebHostEnvironment no construtor da classe SalvarArquivosApi para obter acesso ao caminho da pasta wwwroot usando a propriedade WebRootPath.

Vamos gerar um nome de arquivo aleatório usando a struct Guid eo método NewGuid com a extensão do arquivo.

Se a pasta informada em nomePasta não existir será criada a pasta usando o método CreateDirectory.

A seguir montamos o caminho completo do arquivo com nome e criamos o arquivo na pasta.

Precisamos agora registrar este serviço no container DI pois vamos injetar o serviço no controlador. Para isso na classe Program vamos definir o código :

...

builder.Services.AddTransient<SalvaArquivosApi>();

var app = builder.Build();
...

Criando o controlador ArquivosController

Na pasta Controller do projeto vamos criar o controlador ArquivosController com o código abaixo:

using ApiArquivos.Services;
using Microsoft.AspNetCore.Mvc;
namespace ApiArquivos.Controllers;
[Route("api/[controller]")]
[ApiController]
public class ArquivosController : ControllerBase
{
    private readonly SalvaArquivosApi salvarArquivoApi;
    public ArquivosController(SalvaArquivosApi salvarArquivoApi)
    {
        this.salvarArquivoApi = salvarArquivoApi;
    }
    [HttpGet]
    public ActionResult<string> Get()
    {
        return $"Endpoint acessado em {DateTime.Now.ToShortDateString()}";
    }
    [HttpPost()]
    public async Task<IActionResult> Post([FromForm] IFormFile arquivo)
    {
        try
        {
            await salvarArquivoApi.Salvar(arquivo, "arquivos");
            return Ok();
        }
        catch (Exception ex)
        {
            var erro = ex.Message;
            var result = StatusCodes.Status500InternalServerError.ToString(erro);
            throw;
        }
    }
}

Criamos dois endpoints um Get apenas para testar a API e o outro Post que vai receber o arquivo enviado via request.

No método Post usamos o tipo o atributo [FromForm] que obtém valores de campos de formulário postados.

Definimos também o tipo IFormFile que representa os arquivos transmitidos em uma solicitação HTTP. A interface nos dá acesso a metadados como ContentDisposition, ContentType, Length, FileName e muito mais. IFormFile também fornece alguns métodos usados para armazenar arquivos.

A seguir usamos o método Salvar do nosso serviço para salvar o arquivo na pasta.

Criando o projeto Console para enviar o arquivo

Vamos incluir um projeto do tipo Console via menu File->Add-> New Project com o nome EnviaArquivoApi.

Na classe Program deste projeto inclua a código abaixo:

Console.WriteLine("## Envia arquivos para Web API ##\n");
string baseUrl = "http://localhost:5075/api/arquivos";
Console.WriteLine("Informe a pasta do arquivo\t");
var pathArquivo = Console.ReadLine();
if (string.IsNullOrEmpty(pathArquivo))
{
    Console.WriteLine("\nNome inválido");
    return;
}
Console.WriteLine("Informe o nome do arquivo\t");

var nomeArquivo = Console.ReadLine();
if (string.IsNullOrEmpty(nomeArquivo))
{
    Console.WriteLine("\nArquivo inválido");
    return;
}
var resultado = await EnviarArquivo(pathArquivo, nomeArquivo, baseUrl);
Console.WriteLine(resultado);
Console.ReadKey();
static async Task<string> EnviarArquivo(string caminho, string arquivo, string baseUrl)
{
    HttpClient httpClient = new HttpClient();
    var arquivoCompleto = Path.Combine(caminho, arquivo);
    var nomeArquivo = Path.GetFileName(arquivoCompleto);
    using var requestContent = new MultipartFormDataContent();
    using var fileStream = File.OpenRead(arquivoCompleto);
    requestContent.Add(new StreamContent(fileStream), "arquivo", nomeArquivo);
    var response = await httpClient.PostAsync(baseUrl, requestContent);
    response.EnsureSuccessStatusCode();
    return await response.Content.ReadAsStringAsync();
}

No código acima estamos informando o diretório e o nome do arquivo que desejamos enviar.

A seguir no método EnviarArquivo estamos usando uma instância de HttpClient e o método PostAsync para enviar o conteúdo informado para a uri de atendendimento da nossa api definida em baseUrl.

Para testar vamos enviar o arquivos filmes.csv que esta na pasta d:\dados para o servidor.

Executando o projeto teremos a API em atendimento e projeto Console sendo executado:

O projeto Console onde informamos a pasta e nome do arquivo:

Após o processamento teremos o arquivo salvo na pasta wwwroot/arquivos com o nome aleatório gerado e podemos visualizar o conteúdo do arquivo visto que é um arquivo csv :

E estamos conversados...

Pegue o projeto aqui:  ApiArquivos.zip

"Porque nele(Jesus) foram criadas todas as coisas que há nos céus e na terra, visíveis e invisíveis, sejam tronos, sejam dominações, sejam principados, sejam potestades. Tudo foi criado por ele e para ele."
Colossenses 1:16

Referências:


José Carlos Macoratti