Effettuare l'upload di un file da Blazor su Azure Blob Storage

di Marco De Sanctis, in ASP.NET Core,

Quando la nostra applicazione deve supportare l'upload di file da parte dell'utente, Azure Blob Storage è sicuramente una soluzione preferibile rispetto per esempio al caricamento sul file system del web server. Visto che in Blazor possiamo sfruttare ogni package .NET Standard, possiamo facilmente integrarci con questo servizio cloud tramite il package Azure.Storage.Blobs.

Prima di guardare il codice, però, è necessaria una premessa: come sappiamo, l'accesso ad Azure Blob Storage è tipicamente protetto tramite delle master key che possiamo generare su Azure Portal. Visto però che Blazor gira nel client dell'utente, questa non è una soluzione sicura, perché equivarrebbe a pubblicare in chiaro queste chiavi, con il risultato che chiunque possa in qualche modo estrapolarle dal nostro codice e sfruttarle senza il nostro controllo.

Per evitare questo inconveniente, allora, sfrutteremo un SAS token - ossia una chiave che conceda accesso temporaneo a una parte storage, come descritto in questo script https://www.windowsazureitalia.com/script/150/Dare-Temporaneamente-Accesso-Blob-Azure-Storage.aspx.

API per la generazione del SAS token


L'idea generale è quella di esporre un endpoint in una nostra API che, a fronte di una richiesta - magari autenticata - generi on-demand un SAS token tramite cui il client possa accedere temporaneamente al blob storage. Il primo passo pertanto è quello di referenziare il package Azure.Storage.Blobs sul server:

Install-Package Azure.Storage.Blobs

A questo punto possiamo creare una action simile alla seguente:

[HttpPost]
public IActionResult Create(FileUploadRequest request)
{
    if (request == null)
        return this.BadRequest();

    BlobSasBuilder sas = new BlobSasBuilder
    {
        BlobContainerName = "photos",

        BlobName = request.FileName,

        Resource = "b",

        // Access expires in 1 hour!
        ExpiresOn = DateTimeOffset.UtcNow.AddHours(1),
        StartsOn = DateTimeOffset.UtcNow.AddSeconds(-30)
    };

    sas.SetPermissions(BlobAccountSasPermissions.All);

    StorageSharedKeyCredential credential = new StorageSharedKeyCredential(_accountName, _key);

    var container = new BlobContainerClient(_connectionString, "photos");

    var blob = container.GetBlobClient(request.FileName);

    var result = new UriBuilder(blob.Uri);
    result.Query = sas.ToSasQueryParameters(credential).ToString();

    return this.Ok(result.Uri.ToString());
}

L'oggetto FileUploadRequest in input contiene una proprietà FileName che, per semplicità, useremo anche come nome del blob di cui faremo l'upload. La prima parte del metodo, si occupa di generare una Shared Access Signature per un container di nome "photos", specificando che la risorsa è di tipo Blob tramite il parametro "b" e con una data di scadenza di un'ora. Sempre per semplicità, abbiamo acconsentito a tutti i permessi sul Blob in oggetto. In un caso reale, probabilmente vorremmo limitarli al solo Create, senza dare la possibilità all'utente di sovrascrivere o eliminare un blob esistente.

A questo punto, non dobbiamo far altro che costruire l'URL che il client potrà utilizzare per l'upload e restituirlo come risposta della nostra API.

Codice client side su Blazor


Nel nostro progetto Blazor, come già anticipato, possiamo referenziare il medesimo package Azure.Storage.Blobs, che però sfrutteremo in maniera piuttosto differente. Iniziamo con il creare un componente che contenga un oggetto FileUpload:

@inject HttpClient Http
@using Azure.Storage.Blobs
@using System.IO

.. altro codice qui ..

<InputFile OnChange="UploadAsync"></InputFile>

@code {
    private async Task UploadAsync(InputFileChangeEventArgs e)
    {
        var response = await this.Http.PostAsJsonAsync("/api/photos", 
            new FileUploadRequest() 
            {
              FileName = e.File.Name 
            });

        response.EnsureSuccessStatusCode();

        var uri = await response.Content.ReadAsStringAsync();

        var blob = new BlobClient(new Uri(uri));

        await blob.UploadAsync(e.File.OpenReadStream());
    }
}

Quando l'utente seleziona un file dal proprio sistema, FileUpload eseguirà il metodo UploadAsync che, come prima cosa, invoca l'API che abbiamo creato per recuperare l'URL del blob, compreso di SAS token, su cui dovremo effettuare l'upload.

Successivamente, crea un oggetto di tipo BlobClient passando l'URL ricevuto, e ne invoca il metodo UploadAsync passando lo stream del file in input, copiandone il contenuto su Blob Storage.

Dato che l'upload viene effettuato da Blazor (e quindi dal browser dell'utente) direttamente su Blob Storage, affinché tutto funzioni è indispensabile attivare CORS tramite l'opzione in figura:


Un'ultima nota riguarda il fatto che, per ragioni di sicurezza, UploadFile per default supporta file di dimensione non superiore a 500KB. Per consentire file più grandi, possiamo passare la dimensione massima come parametro del metodo OpenReadStream.

Commenti

Visualizza/aggiungi commenti

| Condividi su: Twitter, Facebook, LinkedIn

Per inserire un commento, devi avere un account.

Fai il login e torna a questa pagina, oppure registrati alla nostra community.

Approfondimenti

I più letti di oggi