V prvním dílu totoho seriálu jsme se seznámili s účelem Azure Mobile Services (vyzkoušejte zdarma!) a některými základními fakty. Dnes se podíváme na datové služby. Téměř každá aplikace potřebuje ukládat nějaká data. Jednodušší aplikace vystačí s uložením dat na lokálním zařízení (např. vybrané město v aplikaci Počasí), ale často je třeba data sdílet mezi více zařízeními (nejlepší skóre ve hře, rodinný nákupní seznam apod.) anebo je ukládat trvale tak, aby zůstala zachována např. při ztrátě zařízení. Pojďme si tuto funkčnost ukázat na jednoduché aplikaci – budeme ukládat dat o knihách v knihovně.

Výsledný kód

Z pedagogických důvodů začnu od konce. Seznámíme se nejprve s výsledným funkčním kódem a poté si ukážeme, co všechno jsme museli udělat, aby správně fungoval. Kód v C# je shodný pro platformu Windows Phone 8 a Windows Store:

Řekněme, že máme v aplikaci třídu Kniha definovanou následovně:

public class Kniha
{
    public int Id { get; set; }
    public string Nazev { get; set; }
    public string Autor { get; set; }
}

Vlastnost Id typu int je povinná a slouží jako primární klíč. Ostatní vlastnosti můžeme zvolit libovolně, ale pouze takové jednoduché typy, které lze serializovat pomocí JSON konvence. V aplikaci přidáme referenci na příslušnou knihovnu (použijeme Mobile Services SDK pro danou platformu), poté si vytvoříme instanci třídy MobileServiceClient. Ta slouží k provádění všech operací nad daty a předáme jí URL naší služby a její klíč, který si nakopírujeme na Azure portále (o bezpečnosti více příště):

static MobileServiceClient client = new MobileServiceClient("https://mjurekdemomobile.azure-mobile.net/", "xXAeTldds...VJTyGlIo91");

Vložení nové knihy pak vypadá následovně:

var k = new Kniha() { Nazev = "Babička", Autor = "Božena Němcová"};
var knihy = client.GetTable<Kniha>();
await knihy.InsertAsync(k);

Povšimněte si, že operace se provádí asynchronně s použitím klíčového slova await – to platí pro veškeré operace s daty. Nikde zde neřeším připojení do databáze a podobné věci. Ve skutečnosti je vkládaný objekt serializován do JSON formátu a prostřednictvím HTTPS požadavku typu POST odeslán na server. Tam je deserializován a uložen do databáze.

Jenom pro zajímavost uveďme analogický kód v JavaScriptu pro Windows Store anebo v HTML stránce v prohlížeči (bez zpětných volání při asynchronním dokončení):

var k = { nazev: "Babička", autor: "Božena Němcová"};
client.getTable("Kniha").insert(k);

Objective C kód pro iOS bude vypadat zhruba takto:

NSDictionary *k= @{ @"nazev" : @"Babička", @"autor" : @"Božena Němcová"};
MSTable *knihy= [client getTable:@"Kniha"];
[knihy insert:k];

A Java kód pro Android aplikace takto:

Kniha k = new Kniha();
k.Nazev = "Babička";
k.Autor = "Božena Němcová";
MobileServiceTable<Kniha> knihy= client.getTable(Kniha.class);
knihy.Insert(k);

Pokud budu chtít naopak data číst, použiji v C# např. následující kód:

var knihy = client.GetTable<Kniha>();
var levneKnihy = await knihy.Where(k => k.Cena < 1000).ToListAsync();

Kód je opět asynchronní a používá velmi pohodlné LINQ konstrukce. Na pozadí se používá URL podle OData konvence, ale to vás nemusí až tak zajímat, vy pouze pohodlně čtete data a dostanete zpět seznam objektů. Co se však mezitím stalo v databázi?

Schéma databáze

Na klientovi sice nemusíme databázové záležitosti řešit, nicméně na pozadí relační databáze samozřejmě existuje – je nutné ji specifikovat již při zakládání mobilní služby. Konfiguruje se prostřednictvím webového portálu:

image

Při práci s databází se uplatňují následující pravidla. Tabulky je nutné vždy vytvořit ručně prostřednictvím portálu:

image

Zvolíte si pouze jméno tabulky a přístupová oprávnění (o těch více příště). V databázi se vždy vytvoří nové schéma odpovídající jménu mobilní služby (první část jejího DNS jména) a v ní se vytvoří nová tabulka se zadaným jménem. Tato tabulka má vždy sloupeček Id typu bigint, který je automaticky generovaným primárním klíčem:

image

Pokud chcete aby se další sloupečky vytvářely automaticky, nechte zapnuté “Enable dynamic schema” v záložce Configure. Pokud tuto možnost zakážete, jednotlivé sloupečky v tabulce budete muset vytvářet ručně prostřednictvím standardních nástrojů pro správu databáze. Důležité ovšem je, aby jméno sloupečku vždy odpovídala jménům jednotlivých prvků v JSON formátu přenášeném mezi klientem a serverem.

Mapování mezi klientem a serverovou službou je poměrně jednoduché. Jméno třídy vždy odpovídá jménu tabulky. Pokud nám tato konvence nevyhovuje, je možné mapování změnit pomocí atributu [DataTable]. Obdobně jsou jména vlastností třídy mapována na jména sloupců tabulky, konvenci lze změnit pomocí [DataMember].

Práce s daty

Jedním ze záměrů celé mobilní služby je odstínit vývojáře klientské aplikace od databázových detailů. Proto portál nabízí jenom základní funkci pro práci s daty – zobrazení záznamů, vymazání jednoho záznamu, všech záznamů v tabulce anebo celé tabulky:

image

Dále je možné nastavit, které sloupečky slouží k výběru řádků a je tedy z výkonnostních důvodů nad nimi vhodné vytvořit index, nepotřebné sloupečky je pak možné smazat:

image

Pokud ovšem máme větší ambice pro práci s daty, můžeme použít standardní databázové nástroje – portál pro správu SQL Azure anebo SQL Server Management Studio. Pokud nebudeme nečekaným způsobem zasahovat do jmen tabulek a sloupců, je vše ostatní dovoleno. Můžeme například vytvářet složitější vícesloupcové indexy, relace mezi tabulkami, pohledy, triggery, uložené procedury apod.

Kód na serveru

Jakákoliv datová operace proti serveru vyvolá HTTPS požadavek. Ten je vyřízen prostřednictvím serverového skriptu, který je napsaný v serverovém JavaSriptu a v základní podobě vypadá například takto:

function read(query, user, request) {

     request.execute();

}

Tento skript lze pro každou operaci modifikovat - např. je možné omezit rozsah vracených záznamů anebo vkládat serverem generované údaje (aktuální čas, identita uživatele apod.). Ze skriptu je možné též volat řadu různých modulů, které zajistí například:

  • Diagnostický výstup
  • Práci s databází
  • Odeslání push notifikace
  • Odeslání emailu nebo SMS (placené služby třetí strany, v menším objemu zdarma)

Kromě toho je možné definovat tzv. joby - JavaScriptový kód, který se na serveru spouští buď v pravidelných intervalech anebo na vyžádání. Serverový kód jsme záměrně probrali poměrně stručně a též jsem se vyhnul bezpečnostním otázkám při přístupu k datům. Vrátíme se k nim v dalších dílech věnovaných funkci autentizačních služeb (3.díl) a notifikačních služeb (4.díl).

Michael