Nello scorso appuntamento abbiamo incominciato una semplice applicazione Web che sfrutta lo storage sul cloud offerto da Windows Azure per permettere agli utenti del nostro servizio di pubblicare le proprie foto, in modo da averle sempre disponibili online, e di lasciare i propri commenti. Abbiamo già realizzato quest'ultima funzione facendo uso dei servizi di Table Storage, ora lavoriamo sulla gestione delle foto appoggiandoci al Blob Storage.
Blob, acronimo di "binary large object", rappresenta qualsiasi file binario, come immagini, video e documenti. File di questo tipo possono essere persistiti sullo storage in the cloud offerto da Windows Azure potendo approfittare delle sue caratteristiche di scalabilità, alta disponibilità e georeplicazione.
Tutti i dati sono sempre accessibili tramite chiamate REST al servizio (verso URL della forma http://myaccountname.blob.core.windows.net
), permettendo di fatto di accedere utilizzando qualunque linguaggio e piattaforma di sviluppo che sia in grado di effettuare chiamate HTTP.
I file, inoltre, sono organizzati in container che rappresentano concettualmente le cartelle del file system.
Leggere dal Blob Storage
Utilizziamo come base di partenza l'applicazione Web che abbiamo iniziato nello scorso appuntamento e sfruttiamo anche il Windows Azure storage account creato sempre nello scorso articolo.
Cominciamo inserendo nel file "server.js", subito sopra alla riga che inizia con "var tableclient = …
", il seguente frammento di codice:
var blobclient = azure.createBlobService();
blobclient.createContainerIfNotExists('photos', function (error) {
if (error) throw error;
blobclient.setContainerAcl('photos', azure.Constants.BlobConstants.BlobContainerPublicAccessType.BLOB, function (error) {
if (error) throw error;
});
});
Queste poche righe di codice si occupano di:
- inizializzare il client per l'accesso al Blob Storage
- assicurarsi che il container per le nostre foto sia disponibile tramite il metodo
createContainerIfNotExists
. Per default i container sono privati, e quindi utilizziamo il metodo setContainerAcl per impostarne i permessi a "container pubblico".
A questo punto, quando più in basso nel file server.js
inizializziamo il controller Home
, dobbiamo assicurarci di passargli come parametro non solo il client per il Table Storage, ma anche il Blob client appena creato. In più, aggiungiamo anche una nuova route /home/photos
alla nostra Web application, sotto a quelle già definite sempre all'interno del file server.js
. La sezione relativa alle rotte, in fondo al file, dovrebbe quindi apparire così:
var home = new Home(tableclient, blobclient);
app.get('/', home.showComments.bind(home));
app.get('/home', home.showComments.bind(home));
app.post('/home/newcomment', home.newComment.bind(home));
app.get('/home/photos', home.showPhotos.bind(home));
Apriamo ora il file home.js
e modifichiamo il costruttore di questo modulo come mostrato qui di seguito:
function Home (tableclient, blobclient) {
this.tableclient = tableclient;
this.blobclient = blobclient;
};
Quindi, aggiungiamo una nuova funzione sotto quelle già definite, inserendo questo codice:
showPhotos: function (req, res) {
this.blobclient.listBlobs(containerName, function (error, blobs) {
res.render('photos', {
title: 'Photos',
blobs: blobs });
});
},
Il questo frammento, utilizziamo il client per il Blob Storage service per elencare tutti i blob contenuti nel container "photos", quindi li mostriamo all'utente tramite il template Jade chiamato "photos" che andiamo ora a creare. Aggiungiamo un nuovo file nella cartella "WebRole1/views
" dandogli il nome di "photos.jade
" e inseriamo questo codice al suo interno:
h1 #{title}
each item in blobs
img(src=item.url, style="height: 200px")
Il codice, semplicissimo, scorre semplicemente l'elenco di blob passato dal controller e genera un tag <img>
per ognuno di essi, mostrando l'immagine puntata dalla proprietà url del singolo elemento.
Aggiungere file al Blob Storage
A questo punto non ci resta che scrivere qualche riga di codice che ci permetta di salvare file sul Blob Storage. Creeremo un semplice form HTML in cui l'utente potrà scegliere un'immagine dal suo harddisk, e questa verrà memorizzata sul cloud.
Creiamo nel file "server.js" una nuova route, sotto a quelle già definite:
app.post('/home/newphoto', home.newPhoto.bind(home));
Aggiungiamo quindi in fondo al file "photos.jade" un form HTML per l'upload:
hr
form(action="/home/newphoto", method="post", enctype="multipart/form-data")
div
label Scegli una foto:
input(name="imagefile", type="file")
input(type="submit", value="Carica")
Non resta quindi che creare la funzione nel controller Home che gestisca il salvataggio della nuova foto nel Blob Storage di Windows Azure. Sotto alle funzioni già definite, aggiungiamo questo frammento di codice:
newPhoto: function (req, res) {
var self = this;
this.blobclient.createBlockBlobFromFile(
'photos',
uuid(),
req.files.imagefile.path,
{ contentType: req.files.imagefile.type },
function (error) {
if (error) throw error;
self.showPhotos(req, res);
}
);
}
Come sempre, commentiamolo brevemente:
files
del parametro req contiene l'elenco dei file caricati dall'utente. Quello che ci interessa ha nome "imagefile", come abbiamo specificato nella form HTML- il metodo
createBlockBlobFromFile
prende come parametri: - il nome del container in cui inserire il nuovo blob
- il nome del blob, che qui generiamo casualmente con un UUID
- il percorso del file sul server di cui fare l'upload su Windows Azure
- eventuali opzioni aggiuntive sotto forma di coppie chiave-valore: qui specifichiamo il tipo di immagine caricata
- una funzione di callback che viene eseguita dopo che il file è stato caricato: se non ci sono errori, rimandiamo alla funzione del controller che mostra l'elenco delle foto.
Abbiamo così completato la nostra applicazione e possiamo vederla in funzione all'interno dell'emulatore di Windows Azure con il cmdlet a noi ormai ben noto:
Start-AzureEmulator -launch
e navigando all'URL "http://localhost:81/home/photos
" apparirà quindi una pagina simile a quella mostrata qui di seguito, in cui sono state già caricate tre foto.