Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial

Windows Azure Table Storage

Sfruttare le tabelle per la memorizzazione di entità, in modalità "NoSQL"
Sfruttare le tabelle per la memorizzazione di entità, in modalità "NoSQL"
Link copiato negli appunti

Nel terzo articolo della guida per .NET abbiamo creato utilizzato lo Storage Account, lo spazio che possiamo "riservare" su Windows Azure per memorizzare in modo centralizzato blob analizzando il portale per la creazione dello storage e il codice per salvare e recuperare una immagine al suo interno.

Per riepilogare i primi passi per chi non avesse letto l'articolo precedente, lo storage account è, come indica il nome, uno spazio di memorizzazione di informazioni (blob, entità, messaggi) legato alla nostra subscription, che, in perfetto stile Windows Azure si paga a consumo calcolando il solo spazio occupato e il numero di transazioni effettuato su di esso.

In pratica ci viene messo a disposizione uno spazio di 100 TB (avete letto bene, sono 100 TB per storage account), affidabile e sempre disponibile in quanto ogni dato memorizzato viene replicatosu 3 macchine diverse, ad alte performance in quanto in caso di necessità i dati vengono suddivisi su macchine diverse per eseguire query parallele, accessibile da qualunque piattaforma via REST/HTTP, per il quale a fine mese ci viene presentato un conto che tiene in considerazione solo lo spazio effettivamente occupato e il numero di accessi effettuati ad esso.

Tutto il resto è trasparente per lo sviluppatore che, tramite alcune librerie disponibili per .NET, Node.js, PHP, Java, ma anche per piattaforme mobile come Windows Phone, iPhone, Android, può scrivere poche e semplici righe di codice per gestire i propri dati. Ovviamente occorre computare anche la banda utilizzata al download dei dati come per qualunque altro componente Windows Azure.

Al momento della scrittura di questo articolo, lo storage account viene calcolato a 0,0887 Euro per GB allocato e a 0,0071 per ogni 10.000 transazione nell'arco del mese.

Lo Storage Account è accessbile via REST/HTTP: lo storage, in pratica, non solo è accessibile (previa verifica di sicurezza sugli accessi) da qualunque tipologia di client, ma anche accessibile da ovunque. Non occorre infatti avere una applicazione ospitata su Windows Azure per potervi accedere. Durante la creazione dello storage account riceviamo l'url relativo che verrà esposto pubblicamente e reso di fatto accessibile da qualunque location sul pianeta con una connessione internet.

Per il salvataggio delle informazioni in tabelle occorre effettuare una serializzazione REST (Representational State Transfer) del "record" che vogliamo salvare.

Record è indicato fra virgolette in quanto, più che di record dovremmo parlare di entità applicativa che viene inviata o recuperata tramite il servizio REST/HTTP e che internamente potrà salvare l'informazione nel modo che ritiene più opportuno: la tipologia di memorizzazione interna è infatti completamente trasparente all'applicazione che farà solamente uso di metodi HTTP (GET, POST, MERGE, DELETE) per effettuare le operazioni in modo standard.

Per creare lo storage account, dal portale di Windows Azure, occorre selezionare la voce Storage Account dopo aver scelto la subscription sulla quale legare lo spazio per poi fornire un nome univoco all'account stesso.

La maschera di gestione è rappresentata nella figura seguente:

Figura 26.
(clic per ingrandire)



Il nome dello storage account deve essere univoco in quanto viene utilizzato come prefisso per l'URI di accesso. Ad esempio scegliendo "devleap", verrà creato in automatico sul DNS un dominio devleap.table.core.windows.net che ci consentirà di effettuare richieste REST di inserimento, modifica, cancellazione e query per gestire le entità in tabelle.

L'organizzazione delle tabelle, così come le partizioni interne ad ogni tabella, è a cura dell'applicazione stessa. Non occorre infatti definire una struttura per le tabelle che potranno quindi contenere informazioni eterogenee: per salvare un cliente all'interno di una tabella è sufficiente inviare una richiesta HTTP di tipo PUT serializzata in formato standard REST. La mancanza di struttura implica che la tabella possa contenere qualunque tipologia di informazione e che ogni "record" potrebbe essere diverso dall'altro, sia per la natura dell'entità serializzata, sia per la versione dell'entità stessa: ad esempio, se un domani decidessimo di aggiungere una proprietà all'entità, le nuove entità verranno serializzate e quindi salvate con la nuova proprietà, mentre le vecchie entità, quelle già presenti nella tabella stessa, al momento del loro recupero, non conterranno la proprietà.

Come abbiamo avuto modo di spiegare meglio nell'articolo precedente sullo Storage Account, per l'account "devleap" vengono riportati gli URI per blob, table e queue, la location dove è stato deciso di creare lo storage account e una coppia di chiavi (Primary e Secondary) che consente di firmare le richieste di accesso allo storage in modo da proteggere il tutto da accessi indesiderati.

Per creare un nuovo storage account è sufficiente utilizzare il pulsante "New Storage Account" e compilare le informazioni a maschera seguente:

Figura 27.
(clic per ingrandire)



E' importante utilizzare una delle due chiavi per firmare le richieste di accesso allo storage: tramite il pulsate "View" è possibile effettuare un copia/incolla della chiave di accesso. Visual Studio, nel designer della configurazione cloud, ci propone un tipo di impostazione denominata Connection String in cui inserire queste informazioni:

Figura 28.
(clic per ingrandire)



Per craere una tabella, utilizzando le librerie .NET e, ricordandoci che per tutte le operazioni che effettueremo potremmo utilizzare direttamente richieste REST/HTTP, si può usare il codice seguente:

CloudStorageAccount account = CloudStorageAccount.Parse(ConfigurationManager.AppSettings["DataConnectionString"]);
CloudTableClient tableClient = account.CreateCloudTableClient();
tableClient.CreateTableIfNotExist("Libri");

Rispetto al codice dell'articolo precedente sui blob, abbiamo usato il tradizionale file di configurazione .NET dove memorizzare la stringa con l'account:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <appSettings>
    <add key="DataConnectionString" value="DefaultEndpointsProtocol=https;AccountName=devleap;AccountKey=Apvw/XB2EICQT8LNvXppqFcWhQT8xxxxxxxxxxxmwO91qK3+Q9ZJOxpNyKlm4g=="/>
  </appSettings>
</configuration>

La prima riga di codice recupera le informazioni sullo storage account e le memorizza in una classe che consente poi di accedere alle diverse tipologie di risorse ospitabili nello storage.

La seconda riga di codice crea la classe CloudTableClient a partire dallo storage account che consente di lavorare con gli oggetti di tipo table per la loro gestione operativa, e, la terza riga crea la tabella nel caso non esista già al'interno dell'account.

Prima di vedere il codice per lavorare con le table, è fondamentale sottolineare che lo storage non è relazionale: ogni tabella vive di vita propria e non possono esistere constraint di integrità referenziale.

È anche impossibile eseguire transazioni cross-table (anche cross-partition). Il mondo relazionale esiste su Windows Azure ed è rappresentato da SQL Azure, che sarà oggetto del prossimo articolo.

Per semplificarci il compito di serializzare e deserializzare le entità è possibile utilizzare la classe base TableServiceEntity: questa classe espone già le tre proprietà base che consentono la memorizzazione in tabella.

  • PartitionKey consente di indicare la partizione di appartenenza dell'entità: ogni tabella può infatti essere suddivisa in partizioni per consentire al sistema di load balancing di dividere fisicamente una tabella su nodi diversi nel caso in cui il sistema vada sotto carico. In pratica ogni partizione può essere spostata da Windows Azure da un nodo fisico all'altro, indipendentemente dalle altre partizioni della tabella e ovviamente anche dalle altre tabelle, su nodi diversi in base alle necessità.
  • RowKey rappresenta la chiave per identificare e rintracciare l'entità all'interno della partizione: per fare una analogia con i database, va considerata come chiave primaria, insieme alla PartitionKey per rintracciare una entità.
  • Timestamp: proprietà gestita in automatico dal sistema di memorizzazione per gestire il versioning delle entità; ad ogni modifica dell'entità, il sistema aggiorna il timestamp per consentire alle applicazioni di gestire la concorrenza ottimistica.

Non ci resta che aggiungere le nostre proprietà come nell'esempio seguente per poi poter leggere e scrivere entità nello storage.

public class Libro : TableServiceEntity
    {
        public String Titolo { get; set; }
        public Int32 Anno{ get; set; }
    }

L'accesso alle tabelle avviene tramite una classe che rappresenta il contesto di esecuzione denominata TableServiceContext, una sorta di Object Context di Entity Framework o Data Context di Linq to SQL. Per la precisione, la classe TableServiceContext deriva dalla classe DataServiceContext del .NET Framework che rappresenta il contesto lato client della libreria WCF Data Service: il compito di questa classe è inviare le richieste LINQ in formato OData via HTTP, deserializzare le entità ricevute e tenere sotto controllo le eventuali modifiche (compresi inserimenti e cancellazioni) per proparli sempre sotto forma di richieste OData al servizio.

La classe TableServiceContext consente di creare query (di tipo DataServiceQuery come per i WCF Data Services) utilizzando una sintassi molto semplice. Ad esempio per effettuare il binding delle entità Libro salvate nello storage su una griglia ASP.NET è possibile utilizzare il codice seguente:

CloudStorageAccount account = CloudStorageAccount.Parse(ConfigurationManager.AppSettings["DataConnectionString"]);
TableServiceContext context = new TableServiceContext(account.TableEndpoint.ToString(), account.Credentials);
gridLibri.DataSource = context.CreateQuery("Libri").ToList();
gridLibri.DataBind();

La prima riga di codice recupera le informazioni di configurazione dal classico .config di .NET per creare una instanza della classe CloudStorageAccount. Tramite questa classe è possibile ricavare le informazioni sulla connessione in modo semplice accedendo alle sue proprietà TableEndpoint e Credential.

La classe TableServiceContext consente la creazione di una query verso lo storage utilizzando il metodo generico CreateQuery<T>, il quale necessita del parametro che indica il nome della tabella su cui effettuare la query.

Sempre utilizzando le classi CloudStorageAccount e TableServiceContext è possibile aggiungere una entità senza preoccuparsi dei dettagli OData, REST e HTTP.

Libro l = new Libro();
l.PartitionKey = "A";
l.RowKey = Guid.NewGuid().ToString();
l.Titolo = "Windows Azure Step by Step";
l.Anno = "2011";
CloudStorageAccount account = CloudStorageAccount.Parse(ConfigurationManager.AppSettings["DataConnectionString"]);
TableServiceContext context = new TableServiceContext(account.TableEndpoint.ToString(), account.Credentials);
context.AddObject("Libri", l);
context.SaveChanges();

Il codice è autodescrittivo: il metodo AddObject aggiunge l'istanza della classe libro al contesto lato client nella collezione di entità denominata Libri; questa collezione corrisponde alla tabella "Libri" lato server che viene aggiornata utilizzando il metodo (ereditato anch'esso dalla classe DataService del .NET Framework) SaveChanges.

Ti consigliamo anche