Nella prima parte abbiamo visto come creare un’applicazione console ed utilizzarla per elaborare (ridimensionare) in modalità Continuously dei Blob contenenti immagini, caricati in un particolare container del nostro storage. L’applicazione non è stata fisicamente copiata su un Web Site di Azure, ma è stata eseguita “in locale” sfruttando gli endpoint allo storage. Per caricare il nostro processo su Web Site i passi da compiere sono pochi e semplici:
- Aprire il Web Site e visualizzare la sezione “Configure”:
- Nella sottosezione “connection strings”, aggiungiamo la stringa di connessione “AzureJobsRuntime”:
- Visualizziamo la sezione “WebJobs”:
-
Prima di effettuare l’upload dell’eseguibile è necessario creare una cartella compressa contenente sia “.exe” che “.dll” necessari al corretto funzionamento dell’applicazione. E’ sufficiente creare un archivio “zip” partendo (ad esempio) dalla cartella Debug\Release del nostro progetto. A questo punto è sufficiente cliccare sul bottone “ADD”, assegnare un nome al nostro “WebJob”, specificare il percorso della cartella compressa ed infine la modalità di esecuzione:
Se avessimo optato per un’esecuzione On Demand del Job ci saremmo trovati in una situazione di questo tipo:
Dove per eseguire il processo si rende necessario cliccare l’icona con la dicitura “RUN ONCE”. Se si vuole invece provare la versione Scheduled è necessario attivare il servizio “Windows Azure Scheduler” tra quelli presenti in questa pagina: https://account.windowsazure.com/PreviewFeatures
Windows Azure mi appassiona veramente tanto e le nuove funzionalità rilasciate (seppur in alpha) aumentano ancora di piu’ la voglia e volontà di adottare questa piattaforma. E’ il caso dei WebJobs, un nuovo SDK in versione alpha che permette di eseguire programmi e script ospitati nei Web Site di Windows Azure, “semplicemente” tramite upload di un file (ad esempio “.exe” o “.cmd” ) dato che tutto il “difficile” è onere del “WebJobs SDK”.
Questa nuova feature permette di eseguire dei veri e propri batch, processi che normalmente impiegherebbero molto tempo per essere eseguiti, come ad esempio la riorganizzazione di file, invio di email, processamento di immagini o code (Queue). Un batch puo’ essere eseguito in tre modalità differenti:
- On-Demand (a richiesta)
- Continuously, il processo in background è sempre attivo “in attesa di fare qualcosa”, il Trigger per attivare il processo puo’ essere ad esempio la ricezione di un messaggio in una specifica coda oppure la creazione di un nuovo Blob
- Scheduled, vogliamo che il nostro processo esegua del lavoro ad una certa ora di uno o piu’ giorni della settimana (in modalità singola o ricorrente)
Un piccolo scenario d’esempio: un task (sempre attivo) che triggerato al caricamento di un Blob (un file immagine) in uno specifico container (“inputcontainer”), lo elabora (ridimensiona l’immagine e ne cambia formato in “png”) e salva il Blob risultato in un altro container (“outputcontainer”).
Per iniziare è sufficiente creare una nuova applicazione console C# ed aggiungere i package necessari traminte NuGet:
PM> Install-Package Microsoft.WindowsAzure.Jobs.Host –pre
In Program.cs scriviamo il codice seguente:
static void Main(string[] args)
{
JobHost host = new JobHost();
host.RunAndBlock();
}
public static void ProcessJob([BlobInput(@"inputcontainer/{name}")] Stream inputStream,
[BlobOutput(@"outputcontainer/{name}")] Stream outputStream)
{
using (Bitmap inputImage = new Bitmap(inputStream))
{
Image outputImage = new Bitmap(200, 200);
using (Graphics g = Graphics.FromImage(outputImage))
{
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.CompositingMode = CompositingMode.SourceCopy;
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
using (ImageAttributes imageAttributes = new ImageAttributes())
{
Rectangle destRect = new Rectangle(0, 0, 200, 200);
g.DrawImage(inputImage, destRect, 0, 0, inputImage.Width, inputImage.Height, GraphicsUnit.Pixel, imageAttributes);
}
}
System.Drawing.Imaging.ImageFormat pngFormat = new System.Drawing.Imaging.ImageFormat(ImageFormat.Png.Guid);
outputImage.Save(outputStream, pngFormat);
}
}
E’ abbastanza intuitivo che il “lavoro sporco” del Task è eseguito dal codice presente in ProcessJob, il quale verrà attivato (BlobInput) ogni volta che un nuovo Blob verrà caricato in “inputcontainer”. L’output è definito dall’attributo BlobOutput, nello specifico la creazione di un nuovo Blob (immagine 200x200) nel container “outputcontainer”. Il codice di ridimensionamento è out of scope. Il nome del Blob in ingresso sarà uguale a quello di uscita in base al pattern specificato dal token “{name}”.
Chi si occupa di gestire i Bindings, di rimanere in “ascolto” e dei Trigger è la classe JobHost che puo’ essere inizializzata come specificato nel Main. In questo caso si suppone che l’App.config contenga le definizione delle due ConnectionStrings necessarie rispettivamente per lavorare con lo Storage di Azure (“AzureJobsData”) e con le attività di logging (“AzureJobsRuntime”):
<connectionStrings>
<add name="AzureJobsRuntime"
connectionString="DefaultEndpointsProtocol=https;AccountName=ACCOUNT_NAME;AccountKey=ACCOUNT_KEY"/>
<add name="AzureJobsData"
connectionString="DefaultEndpointsProtocol=https;AccountName=ACCOUNT_NAME;AccountKey=ACCOUNT_KEY"/>
</connectionStrings>
Altrimenti è necessario specificare il nome delle due stringhe di connessione tramite costruttore della classe JobHost. Le due connessioni possono coincidere ed ovviamente per eseguire l’esempio è necessario modificarle secondo il proprio account, sostituendo i valori di ACCOUNT_NAME e ACCOUNT_KEY.
Il metodo “RunAndBlock()” esegue il Task nello stesso Thread attivo, mentre per utilizzare un Background Thread è necessario invocare il metodo “RunOnBackgroundThread()” (che ritorna immediatamente il controllo al chiamante).
Per testare il tutto possiamo premere F5 e dopo qualche secondo, se tutte le configurazioni sono corrette, dovremmo ottenere una console simile alla seguente:
Questo implica che il nostro Job è in attesa di “fare qualcosa”. Per lavorare con lo storage di Windows Azure possiamo scaricare il Tool “Azure Storage Explorer”. Una volta installato e configurato è possibile esplorare e modificare il nostro storage, nel mo caso, inizailmente abbiamo una situazione simile alla seguente:
Dopo aver selezionato la voce “inputcontainer” nella lista “Container”, scegliamo la voce “New” nella lista dei comandi “Blob”, specifichiamo il nome del nuovo Blob e premiamo “Create Blob”:
Dalla lista dei Blob presenti selezioniamo quello appena creato e scegliamo la voce “View” per visualizzarne i dettagli:
Click su “Upload Image File” per caricare una nuova immagine ed attendere il completamento delle operazioni di upload. Rieseguendo la nostra applicazione, dopo qualche secondo, dovremmo ottenere una console di questo tipo:
A questo punto ”outputcontainer” dovrebbe contenere un Blob con lo stesso nome di quello di input e contenente un immagine di dimensione 200x200px:
Nella seconda parte del post vedremo come caricare l’eseguibile direttamente in un nostro Web Site ospitato su Windows Azure.