DEV Community

Cover image for Manipulando arquivos no azure storage: FullStackPlayGround
Lucas Silvério
Lucas Silvério

Posted on

Manipulando arquivos no azure storage: FullStackPlayGround

Oi pessoal!

Nesse vou mostrar como manipular arquivos do azure storage com c#, e ainda fornecer um exemplo de como a aplicar em um aplicativo angular.

Você precisa ter instalado em sua máquina:

e também uma assinatura no Azure

Move Storage

O move storage é um aplicativo angular com uma interface amigável para fazer as operações que serão demonstradas nesse artigo.
Tanto a api quanto o app estão no mesmo repositório.
As operações que vamos ver são:

Faça uma pré-visualização do projeto:

Faça clone ou dê uma espiada no código do projeto:

Navegue no terminal até a pasta raiz do projeto onde se encontra o Readme.md

Azure

Faça login na sua conta do azure e defina uma conta padrão para esse tutorial, assim você garante que a operação será feita no tenant correto:

az login
az account set --subscription <subscriptionid>
Enter fullscreen mode Exit fullscreen mode

Vamos definir algumas variáveis no terminal, para facilitar a escrita dos demais comandos

substitua o <nome exclusivo do storage> por por exemplo:
storagelsv1990, na qual a primeira parte é o nome do app, e a segunda parte são as iniciais do seu nome seguido do ano em que nasceu, (Lucas Silvério Vargas, 1990 - lsv1990).
essa é só uma dica para dar um nome ao storage, que deve ser exclusivo.

$group="MoveStorage"
$storageName="<nome exlusivo do app>"
Enter fullscreen mode Exit fullscreen mode

Agora vamos criar um grupo de recursos e criar o nosso storage

az group create -n $group -l eastus2
az storage account create -n $storageName -g $group -l eastus2 --sku Standard_LRS
Enter fullscreen mode Exit fullscreen mode

Obtenha a string de conexão e guarde, vamos utilizar mais adiante no nosso aplicativo:

az storage account show-connection-string -g $group -n $storageName

Enter fullscreen mode Exit fullscreen mode

Agora crie um container e vamos subir alguns arquivos de exemplo:

az storage container create -n container1 --account-name $storageName
az storage blob upload-batch -d container1 -s .\documents\ --account-name $storageName 
Enter fullscreen mode Exit fullscreen mode

Aplicativo

No terminal navegue até o aplicativo angular e levante o servidor.

cd .\src\app\
npm i
ng s -o
Enter fullscreen mode Exit fullscreen mode

Em outra aba do terminal navegue até a api e levante a aplicação dotnet.

cd .\src\api\
dotnet run
Enter fullscreen mode Exit fullscreen mode

image

Adicione uma conexão ao storage, vamos colar a connection string que obtivemos anteriormente e informar um apelido para essa instância de gerenciamento:
image

Selecione o container1 e será carregado e os arquivos serão listados:
image

Crie uma nova instância de gerenciamento com a mesma connection string e vamos criar um novo container pelo próprio aplicativo:
image

O nome pode conter apenas letras minúsculas, números e hifens e deve começar com uma letra ou com um número. Cada hífen deve ser precedido e seguido por um caractere que não seja um hífen. O nome também deve ter entre 3 e 63 caracteres.

Selecione um arquivo e arraste para área de arquivos do container2, e o arquivo será copiado de um container para o outro:
image

Também é possível mover entre storages diferentes.

No repositório você consegue ver como construí essa dinâmica no front-end, mas nesse artigo vou explanar apenas os métodos em c#.

WebApi

Disclaimer

Essa é uma aplicação para fins didáticos, nela eu passo as connection strings de alguns métodos pelos parâmetros da url. Em produção não fazemos assim, connection strings são informados em arquivos de configuração como o appsettings.json.

O método DecodeUrl é usado para fazer o decode da connection string e um tratamento para sinais de "+" que as mesmas podem possuir

private static string DecodeUrl(string connectionString) => HttpUtility.UrlDecode(connectionString).Replace(" ", "+");
Enter fullscreen mode Exit fullscreen mode

Leia mais sobre isso aqui.

Comandos

Os comandos foram declarados como Records para diminuir a escrita de código e também estão no arquivo de controller, devido a natureza simples desse projeto:

    public record StorageConnection(string ConnectionString, string Alias);
    public record Container(string Name, StorageConnection Connection);
    public record FileConvert(string Name, string Base64);
    public record Upload(Container Container, List<FileConvert> FilesBase64);
    public record MoveFile(Container From, Container To, string File);
    public record NewContainer(string ConnectionString, string ContainerName);
Enter fullscreen mode Exit fullscreen mode

Criar um novo container

[HttpPost("container")]
public ActionResult AddContainer(NewContainer container)
{
    var storage = new BlobServiceClient(container.ConnectionString);
    storage.CreateBlobContainer(container.ContainerName);
    return Created("", new { response = "Arquivo transferido" });
}
Enter fullscreen mode Exit fullscreen mode

Listar containers

[HttpGet("containers/{connectionString}")]
public ActionResult GetContainers(string connectionString)
{
     var storage = new BlobServiceClient(DecodeUrl(connectionString));
     var response = storage.GetBlobContainers().Select(x => x.Name);
     return Ok(response);
}
Enter fullscreen mode Exit fullscreen mode

Deletar um container

[HttpDelete("container/{connectionString}/{containerName}")]
public ActionResult RemoveContainer(string connectionString, string containerName)
{
    var blob = new BlobContainerClient(DecodeUrl(connectionString), containerName);
    blob.Delete();
    return NoContent();
}
Enter fullscreen mode Exit fullscreen mode

Listar arquivos de um container

[HttpGet("files/{connectionString}/{containerName}")]
public ActionResult GetFiles(string connectionString, string containerName)
{
    var container = new BlobContainerClient(DecodeUrl(connectionString), containerName);
    var response = container.GetBlobs().Select(x => x.Name);
    return Ok(response);
}
Enter fullscreen mode Exit fullscreen mode

Deletar um arquivo

[HttpDelete("file/{connectionString}/{containerName}/{fileName}")]
public ActionResult RemoveFile(string connectionString, string containerName, string fileName)
{
    var blob = new BlobClient(DecodeUrl(connectionString), containerName, fileName);
    blob.Delete();
    return NoContent();
}
Enter fullscreen mode Exit fullscreen mode

Upload de arquivos

[HttpPost("upload")]
public ActionResult Upload(Upload upload)
{
    var container = new BlobContainerClient(upload.Container.Connection.ConnectionString, upload.Container.Name);
    foreach (var file in upload.FilesBase64)
    {
        var data = file.Base64.Substring(file.Base64.IndexOf(",") + 1);
        container.UploadBlob(file.Name, new MemoryStream(Convert.FromBase64String(data)));
    }
    return Created("", new { response = "Arquivos enviados" });
}
Enter fullscreen mode Exit fullscreen mode

Download de um arquivo

[HttpGet("download/{connectionString}/{containerName}/{fileName}")]
public async Task<ActionResult> DownloadFile(string connectionString, string containerName, string fileName)
{
    var blob = new BlobClient(DecodeUrl(connectionString), containerName, fileName);
    BlobProperties properties = await blob.GetPropertiesAsync();
    var result = await blob.DownloadContentAsync();
    return File(result.Value.Content.ToArray(), properties.ContentType, "");
}
Enter fullscreen mode Exit fullscreen mode

Mover um arquivo de um storage/container para outro storage/container


[HttpPost("move")]
public async Task<ActionResult> MoveFile(MoveFile moveFile)
{
    BlobContainerClient sourceContainer = new(DecodeUrl(moveFile.From.Connection.ConnectionString), moveFile.From.Name);
    BlobContainerClient destContainer = new(moveFile.To.Connection.ConnectionString, moveFile.To.Name);
    BlobClient destBlob = destContainer.GetBlobClient(moveFile.File);
    await destBlob.StartCopyFromUriAsync(GetSharedAccessUri(moveFile.File, sourceContainer));
    await sourceContainer.DeleteBlobAsync(moveFile.File);
    return Created("", new { response = "Arquivo transferido" });
}
private static Uri GetSharedAccessUri(string blobName, BlobContainerClient container)
{
    DateTimeOffset expiredOn = DateTimeOffset.UtcNow.AddMinutes(60);
    BlobClient blob = container.GetBlobClient(blobName);
    Uri sasUri = blob.GenerateSasUri(BlobSasPermissions.Read, expiredOn);
    return sasUri;
}
Enter fullscreen mode Exit fullscreen mode

Veja mais sobre o método de cópia e os motivos de gerar uma UriSaS aqui

Espero que isso te ajude!

Top comments (0)