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
Per inserire un commento, devi avere un account.
Fai il login e torna a questa pagina, oppure registrati alla nostra community.
Approfondimenti
Generare file per il download da Blazor WebAssembly
Inizializzare i container in Azure Container Apps
Ottimizzazione dei block template in Angular 17
Potenziare Azure AI Search con la ricerca vettoriale
Usare Refit e Polly in Blazor per creare client affidabili e fortemente tipizzati
Applicare il versioning ai nostri endpoint ASP.NET Core Minimal API
Esportare ed analizzare le issue di GitHub con la CLI e GraphQL
Utilizzare Model as a Service su Microsoft Azure
Eseguire operazioni sui blob con Azure Storage Actions
Utilizzare la versione generica di EntityTypeConfiguration in Entity Framework Core
Creare form tipizzati con Angular
Effettuare chiamate con versioning da Blazor ad ASP.NET Core
I più letti di oggi
- Miglioramenti nelle performance di Angular 16
- Ottimizzare le performance delle collection con le classi FrozenSet e FrozenDictionary
- HTML5 con CSS e JavaScript
- Ottimizzazione dei block template in Angular 17
- ecco tutte le novità pubblicate sui nostri siti questa settimana: https://aspit.co/wkly buon week-end!