Guest post: Sincronizzare i dati nelle Universal Windows app con OneDrive

Questo post è stato scritto da Matteo Pagani, Windows AppConsult Engineer in Microsoft

La sincronizzazione dei dati delle applicazioni sta diventando, nel mondo mobile, un'esigenza sempre più frequente. Sono molteplici, infatti, i device con cui un utente interagisce quotidianamente: smartphone, tablet, pc, ecc. Spesso, anche se in contesti diversi, utilizziamo la stessa applicazione su ognuno di questi dispositivi e ci aspettiamo che i nostri dati e le nostre attività siano sempre sincronizzati.

I client di posta sono un ottimo esempio di questo scenario: la loro utilità sarebbe molto ridotta se, dopo aver letto una serie di mail sul telefono, le trovassimo ancora marcate come da leggere spostandoci sul PC o sul tablet.

Nel mondo delle Universal Windows app per Windows 10 questo scenario è ancora più frequente: la stessa applicazione, infatti, è in grado di girare sul telefono, sul desktop, sul tablet, ecc., quindi la sincronizzazione dei dati non è più una funzionalità facoltativa, ma diventa uno dei requisiti fondamentali da implementare.

La soluzione più efficiente per gestire questo requisito è sicuramente quello di affidarsi alle Mobile App di Azure. Tra le varie funzionalità, offre anche la possibilità di mantenere un database nel cloud, i cui dati vengono automaticamente sincronizzati in locale (sfruttando SQLite) tra le varie applicazioni mobile. I vantaggi delle Mobile App sono molteplici:

  1. Supporto cross-platform: esiste un SDK per tutte le principali piattaforme mobile. Ciò ci permette di sincronizzare i nostri dati non solo all'interno della stessa Universal Windows app che gira su molteplici device, ma anche tra le eventuali versioni della nostra app per Android e iOS.
  2. Gestione dei conflitti: l'SDK si fa carico, in automatico, di risolvere le principali tipologie di conflitti che si possono verificare negli scenari di sincronizzazione dati.
  3. Supporto all'offline: l'SDK è in grado di funzionare anche in mancanza di connettività. I dati saranno semplicemente mantenuti nel database SQLite locale, per poi essere sincronizzati con il database nel cloud appena la connettività sarà ripristinata.

Per alcuni scenari, però, le Mobile App di Azure possono essere fin troppo potenti rispetto ai nostri requisiti. Ad esempio, a volte non ci serve implementare una vera e propria sincronizzazione dati, ma semplicemente offrire delle funzionalità di backup e ripristino, per permettere all'utente di non perdere i dati nel caso in cui cambi telefono o debba fare un reset di quello attualmente in suo possesso.

In questo caso, possiamo trovare un valido alleato in OneDrive, il cloud storage di Microsoft. In una Universal Windows app, infatti, possiamo darne praticamente per scontata la disponibilità: per poter usufruire, infatti, di tutti i servizi offerti da Windows e poter installare applicazioni dallo Store è necessario un Microsoft Account, che include anche l'accesso a OneDrive.

Il team di OneDrive, recentemente, ha introdotto un nuovo modello di sviluppo, basato su un set di API REST facilmente utilizzabili da qualsiasi piattaforma. Inoltre, sono stati realizzati una serie di SDK specifici per le piattaforme principali, come Windows, Android e iOS, che ne semplificano l'utilizzo all'interno di un'applicazione. Uno dei punti di forza di queste nuove API è la maggiore flessibilità rispetto alla precedente Live SDK; se avete già avuto modo di utilizzarle in passato, ricorderete che non erano particolarmente adatte per scenari di sincronizzazione, in virtù del fatto che, ad ogni accesso a OneDrive, era richiesta una esplicita autorizzazione all'utente tramite un popup.

Ora, invece, questo vincolo è stato rimosso: l'utente dovrà autenticarsi solo la prima volta, dopodiché l'SDK potrà essere utilizzata in maniera "silente". C'è di più: in una Universal Windows app avremo la possibilità di sfruttare direttamente il Microsoft Account del dispositivo, senza dover richiedere all'utente di effettuare manualmente il login.

Ma andiamo per gradi e vediamo come sfruttare l'SDK di OneDrive in una Universal Windows app per gestire alcune funzionalità base: login, creazione di cartelle, upload e download di file. Come esempio, realizzeremo una semplice applicazione in grado di effettuare l'upload di un'immagine contenuta all'interno del progetto Visual Studio e, successivamente, di scaricarla nuovamente in una cartella scelta dall'utente.

In uno scenario reale di backup & ripristino, al posto di un'immagine avremmo un database SQLite o un file JSON o XML memorizzato nello storage locale. Le API che andremo ad utilizzare, però, sono le medesime e non sono legate alla posizione e alla tipologia di file che vogliamo caricare o scaricare da OneDrive.

Installare l'SDK e configurare l'applicazione

Per quanto riguarda il mondo Windows, l'SDK C# è disponibile sotto forma di Portable Class Library, pubblicata come progetto open source su GitHub all'indirizzo https://github.com/onedrive/onedrive-sdk-csharp

Per semplificare l'installazione l'SDK è disponibile anche come pacchetto NuGet: l'identificativo da cercare nella schermata di NuGet è Microsoft.OneDriveSDK.

Una volta installata, siamo pronti per iniziare a utilizzarla. Uno dei concetti base delle API di OneDrive è l'autenticazione: per motivi di sicurezza, l'applicazione deve essere opportunamente configurata per poter utilizzare le API. L'obiettivo è quello di evitare che eventuali tentativi di hacking (ad esempio, intercettazione del traffico di rete) possano consentire semplicemente ad altre applicazioni o utenti di accedere al vostro account OneDrive.

Per poter utilizzare le API, perciò, la vostra Universal Windows app deve essere registrata sul Dev Center, sfruttando l'opzione Associate app with the Store che trovate all'interno del menu Store che compare facendo clic con il tasto destro sul progetto in Visual Studio. Completando la procedura guidata, l'applicazione sarà registrata sullo Store e, di conseguenza, potrà accedere a tutta una serie di servizi che richiedono l'autenticazione (ad esempio, uno di questi sono le notifiche push).

Ora che abbiamo compiuto questa operazione, siamo pronti per iniziare la fase di login, così da chiedere all'utente l'autorizzazione ad accedere al suo account OneDrive.

L'autenticazione

In caso di utilizzo all'interno di una Universal Windows app non dovremo fare alcuna operazione particolare per gestire l'autenticazione. Il grosso del lavoro, infatti, verrà svolto dall'SDK, che si farà carico di gestire tutto il processo. Esistono due modalità per gestire l'autenticazione:

  1. Tramite OnlineIdAuthenticator: con questo approccio, l'utente sarà automaticamente loggato con il Microsoft Account del device e dovrà solamente, al primo tentativo di login, confermare l'autorizzazione.
  2. Tramite WebAutenthicationBroker: con questo approccio viene proposto all'utente un popup, all'interno del quale, tramite una WebView, gli verrà chiesto di confermare le sue credenziali.

Per ora ci concentreremo sul primo approccio, più semplice per lo sviluppatore e per l'utente finale. Questo approccio ha però un limite: può essere utilizzato solamente se la nostra applicazione prevede di utilizzare le API di OneDrive in foreground, ovvero mentre l'applicazione è in esecuzione. Se vogliamo poter sfruttare queste API anche all'interno di un background task (ad esempio, per effettuare delle sincronizzazioni periodiche in automatico), dovremo usare il secondo metodo di login, che tratteremo più avanti nel corso del post.

Partiamo perciò dal primo approccio, basato sull'OnlineIdAuthenticator. In questo caso, la configurazione da fare è veramente minima: tutte le informazioni relative all'applicazione che si dovrà autenticare saranno prese in automatico dallo Store, grazie all'associazione che abbiamo fatto in precedenza.

L'unica cosa che dobbiamo definire sono gli scope, ovvero quali funzionalità esposte dall'SDK di OneDrive vogliamo utilizzare: le troviamo elencate all'indirizzo https://dev.onedrive.com/auth/msa_oauth.htm#authentication-scopes.

Gli scope più comunemente utilizzati sono:

  • wl.signin, che ci permette di sfruttare il single sign-on.
  • wl.offline_access, che ci permette di interagire con OneDrive senza richiedere continuamente l'autorizzazione all'utente.
  • onedrive.readwrite, che ci garantisce la possibilità di scrivere e leggere file sull'account dell'utente.

Una volta che abbiamo definito gli scope che vogliamo utilizzare, dobbiamo includerli all'interno di un array di stringhe, come nell'esempio seguente:

private readonly string[] Scopes = new[] { "wl.signin", "wl.offline_access", "onedrive.readwrite" };

Tale array è il parametro che dobbiamo passare al metodo di autenticazione che, nel caso di una Universal Windows app, viene reso disponibile dalla classe OneDriveClientExtensions e si chiama GetClientUsingOnlineIdAuthenticator() . Il suo utilizzo è molto semplice, come possiamo vedere nell'esempio seguente:

private async void OnOneDriveLogin(object sender, RoutedEventArgs e)

{

IOneDriveClient client = OneDriveClientExtensions.GetClientUsingOnlineIdAuthenticator(Scopes);

await client.AuthenticateAsync();

}

A questo punto all'utente comparirà una finestra di dialogo, nella quale dovrà confermare di voler autorizzare l'applicazione ad accedere a OneDrive e sfruttare i permessi richiesti con lo scope. Sarà la prima e ultima volta che l'utente vedrà questa schermata: da questo momento in poi, qualsiasi successiva chiamata al metodo AuthenticateAsync() verrà eseguita in maniera silenziosa, senza richiedere nuovamente il permesso all'utente.

Il punto di forza di questo approccio è che tutto il meccanismo di autenticazione richiesto dalle API REST sarà a noi completamente trasparente. Ciò che conta è che ora siamo in possesso di un oggetto di tipo IOneDriveClient valido, che ci permetterà di effettuare tutte le operazioni base con lo storage di OneDrive.

Gestire file e cartelle

L'SDK di OneDrive ricalca la struttura delle API REST, offrendo una serie di classi e metodi che richiamano l'utilizzo dei comandi del protocollo HTTP, come POST, GET, PUT, ecc. Una classe fondamentale che dovremo imparare a conoscere è Item, che rappresenta qualsiasi elemento memorizzato su OneDrive, indipendentemente che sia un file o una cartella. Potremo capire la tipologia di elemento grazie alla proprietà Folder: se questa è null, significa che si tratta di un file; in caso contrario, è una cartella. Oltre a Folder, la classe Item contiene molte altre proprietà che ci permettono di recuperare informazioni dettagliate sull'elemento, come identificativo (Id), descrizione (Description), data di creazione e ultima modifica (CreatedDateTime e LastModifiedDateTime) e così via.

Il punto di partenza per lavorare con questi oggetti è la proprietà Drive, che rappresenta lo storage OneDrive dell'utente; da lì possiamo sfruttare la proprietà Root, che identifica la radice dello storage, quella che contiene tutti i file e le cartelle dell'utente.

Un'operazione fondamentale per il nostro scenario è la creazione di cartelle: come impostazione predefinita, infatti, non avremo la possibilità di scrivere file direttamente nella root dello storage OneDrive. Nell'ottica, perciò, di offrire funzionalità di sincronizzazione o di backup e restore dei dati della nostra app, dovremo creare una cartella, all'interno della quale memorizzare il (o i) file di backup.

Abbiamo detto che una cartella non è altro che un oggetto di tipo Item con la proprietà Folder valorizzata. Ecco, perciò, come appare la definizione di una nuova cartella:

Item newItem = new Item

{

Name = "OneDrive Sample",

Folder = new Folder()

};

A questo punto possiamo crearla sull'account OneDrive dell'utente:

Item newItem = new Item

{

Name = "OneDrive Sample",

Folder = new Folder()

};

 

await _client.Drive.Root.Children.Request().AddAsync(newItem);

Ogni cartella su OneDrive espone una proprietà di nome Children, che permette di accedere agli elementi figli, come file e sottocartelle. La cartella speciale Root non fa eccezione, perciò ne sfruttiamo la proprietà Children per interagire con gli elementi al suo interno.

Quello che vedete è un classico esempio di utilizzo dell'SDK di OneDrive: dopo aver identificato l'elemento con cui vogliamo interagire, creiamo la richiesta tramite il metodo Request() , che ci mette poi a disposizione i vari metodi (che, solitamente, combaciano con quelli del protocollo HTTP) per effettuare le operazioni vere e proprie. In questo caso, l'aggiunta di un nuovo elemento (la cartella) viene effettuata tramite il metodo AddAsync() , che richiede come parametro l'oggetto Item che rappresenta l'elemento da creare.

Possiamo già mettere alla prova il lavoro svolto finora: se eseguissimo questo blocco di codice, troveremmo all'interno del nostro account OneDrive una nuova cartella di nome OneDrive Sample.

Upload di file

Vediamo ora come gestire la procedura di backup, ovvero come caricare su OneDrive il file che contiene i dati della nostra applicazione: potrebbe essere un database SQLite, un file XML o JSON, ecc.

In questo esempio, ipotizziamo di caricare all'interno della cartella creata in precedenza un'immagine, che abbiamo incluso all'interno del progetto di Visual Studio. Ecco come fare:

private async void OnUploadFile(object sender, RoutedEventArgs e)

{

StorageFile file = await Package.Current.InstalledLocation.GetFileAsync("Wallpaper.png");

using (Stream stream = await file.OpenStreamForReadAsync())

{

await _client.Drive.Root.ItemWithPath("OneDrive Sample/Wallpaper.png").Content.Request().PutAsync<Item>(stream);

}

}

Il primo passo è recuperare un riferimento all'oggetto di tipo StorageFile (la classe base della Universal Windows Platform che rappresenta i file) che vogliamo caricare su OneDrive. In questo esempio, utilizziamo la classe Package.Current.InstalledLocation, che rappresenta la cartella in cui viene installata l'applicazione, la quale coincide con la struttura del nostro progetto Visual Studio. Se fosse stato un file nello storage locale (scenario molto probabile se stiamo effettuando il backup dei dati dell'applicazione), avremmo usato la classe ApplicationData.Current.LocalFolder.

Indipendentemente dalla posizione del file, una volta che lo abbiamo recuperato dobbiamo elaborarne il contenuto sotto forma di oggetto di tipo Stream tramite il metodo OpenStreamForReadAsync() : l'SDK di OneDrive, infatti, lavora con questo formato per gestire il trasferimento di dati. Dopodiché, introduciamo un nuovo metodo per recuperare l'accesso ad un elemento specifico: il metodo ItemWithPath() , che accetta in ingresso il percorso completo del file, incluse eventuali sotto cartelle. Si tratta dell'approccio migliore per il nostro scenario, dato che sappiamo a priori qual è la posizione del file dove vogliamo salvare i nostri dati.

Come possiamo notare nell'esempio di codice, il file non deve necessariamente esistere già: in caso contrario, l'operazione di upload provvederà a crearlo. Non è sufficiente, però, creare il file: dobbiamo anche "riempirlo" con i nostri dati, ovvero con lo stream che abbiamo recuperato in precedenza. Il contenuto viene esposto da una proprietà chiamata Content della classe Item. Da lì, possiamo inizializzare la richiesta tramite il metodo Request() e sfruttare il metodo PutAsync<T>() , che accetta in ingresso proprio lo stream con cui "riempire" il file. Il gioco è fatto: ora su OneDrive sarà presente un nuovo file, chiamato Wallpaper.png, all'interno della cartella OneDrive Sample. Il contenuto del file sarà esattamente l'immagine che abbiamo precedentemente incluso all'interno del progetto di Visual Studio.

Download del file

Esattamente come per effettuare l'upload, per poter scaricare all'interno dell'applicazione un file presente su OneDrive dobbiamo prima recuperare l'oggetto di tipo Item che lo rappresenta. L'approccio da utilizzare è lo stesso che abbiamo visto in precedenza:

Stream stream = await _client.Drive.Root.ItemWithPath("OneDrive Sample/Wallpaper.png").Content.Request().GetAsync()

Si sfruttano nuovamente il metodo ItemWithPath() (dato che conosciamo a priori posizione e nome del file) e la proprietà Content, che ci permette di accedere allo stream del contenuto. In questo caso, però, non dobbiamo effettuare un upload, ma un download: dopo aver creato la richiesta con il metodo Request() , perciò, usiamo il metodo GetAsync() , al posto di PutAsync<T>() .

Ora che abbiamo recuperato l'oggetto Stream con il contenuto del file, possiamo manipolarlo nel modo che reputiamo più adatto. Ad esempio, il seguente blocco di codice sfrutta la classe FileSavePicker per proporre all'utente di salvare l'immagine scaricata sul proprio dispositivo. In uno scenario di backup e restore, avremmo utilizzato nuovamente le API per accedere allo storage locale (ApplicationData.Current.LocalFolder) per salvare il file con i nostri dati, sovrascrivendo quello esistente.

using (Stream stream = await _client.Drive.Root.ItemWithPath("OneDrive Sample/Wallpaper.png").Content.Request().GetAsync())

{

FileSavePicker picker = new FileSavePicker();

picker.FileTypeChoices.Add("Pictures", new List<string> { ".png" });

picker.SuggestedFileName = "Wallpaper.png";

picker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;

StorageFile destinationFile = await picker.PickSaveFileAsync();

 

using (Stream destinationStream = await destinationFile.OpenStreamForWriteAsync())

{

await stream.CopyToAsync(destinationStream);

await destinationStream.FlushAsync();

}

}

Dopo aver recuperato l'oggetto di tipo StorageFile che rappresenta il file di destinazione dei nostri dati, chiamiamo il metodo OpenStreamForWriteAsync() , che ci dà accesso al contenuto del file sotto forma di Stream. In questo caso, si tratta di uno stream vuoto, per cui sfruttiamo il metodo CopyToAsync() per copiare lo stream originale (quello scaricato da OneDrive) nello stream di destinazione.

Anche l'operazione di download è terminata: ora, all'interno dello storage locale (o, come nell'esempio, nella cartella scelta dall'utente), troveremo una copia del file scaricato da OneDrive.

Effettuare il backup in background

Fino ad ora abbiamo visto come effettuare operazioni di download e upload mentre l'applicazione è in esecuzione. In alcuni scenari, però, potrebbe essere utile effettuare queste attività anche mentre l'applicazione non è in esecuzione. Per questo motivo possiamo sfruttare i background task, ovvero progetti di tipo Windows Runtime Component che contengono blocchi di codice che possono essere eseguiti anche quando l'applicazione non è in esecuzione. I background task sono legati ai trigger, ovvero eventi che ne scatenano l'esecuzione. In scenari di backup automatico uno dei più utili risulta essere il TimeTrigger, che permette di eseguire il task ad intervalli di tempo predefiniti (con un limite minimo di 15 minuti).

Il problema, però, è che le API di autenticazione che abbiamo visto in precedenza non sono in grado di funzionare all'interno di un background task, in quanto fanno uso di API che interagiscono con l'interfaccia utente. Ci serve, perciò, sfruttare un altro approccio, che ci permetta di autenticarci in maniera silente.

Per questo scopo, la classe OneDriveClient espone il metodo GetSilentlyAuthenticatedMicrosoftAccountClient() che, però, presuppone che l'utente si sia già autenticato e loggato in precedenza e che, di conseguenza, abbia già specificato le informazioni sul suo Microsoft Account. Uno dei parametri richiesti, infatti, si chiama refresh token e ci viene restituito nel momento in cui viene effettuata la prima autenticazione con successo. Tale token ha validità un anno e ci permette di effettuare operazioni con le API di OneDrive senza dover richiedere nuovamente all'utente le sue credenziali.

Se ricordate l'inizio del post, abbiamo detto però che non siamo in grado di sfruttare l'Online Authenticator Id nel caso in cui la nostra applicazione faccia uso di un background task. Questo perché tale approccio si fa carico di gestire in automatico (e, quindi, di nascondere) tutta la logica di autenticazione richiesta dalle API e, perciò, non ci permette di recuperare il refresh token e di salvarlo per usi futuri.

Dobbiamo, perciò, sfruttare l'autenticazione tramite WebAuthenticationBroker che, invece, ci darà accesso a tutte le informazioni che ci servono. Lo svantaggio è che la procedura di login non sarà più automatica come prima, ma l'utente dovrà confermare il suo Microsoft Account inserendo username e password, oltre a dover confermare l'autorizzazione. Il flusso, perciò, sarà il seguente:

  1. L'utente farà login nell'applicazione principale, sfruttando il WebAuthenticationBroker.
  2. Una volta che il login è andato a buon fine, otterremo un oggetto di tipo IOneDriveClient con, al suo interno, il refresh token che ci serve. Lo salveremo nello storage locale, sfruttando la classe ApplicationData.Current.LocalSettings.
  3. Il background task, quando sarà eseguito, recupererà dallo storage locale il refresh token e lo sfrutterà per effettuerà il login tramite il metodo GetSilentlyAuthenticatedMicrosoftAccountClient().

Questo approccio richiede però un'informazione che, fino a questo momento, avevamo tralasciato: l'application id, ovvero l'identificativo univoco dell'applicazione che ci viene assegnato dai servizi Microsoft per l'autenticazione. Il login tramite WebAuthenticationBroker, infatti, sfrutta questa informazione che, in precedenza, veniva gestita in maniera trasparente dall'Online Id Authenticator.

Per recuperarlo, dobbiamo collegarci al Dev Center (http://dev.windows.com), accedere alla nostra dashboard ed entrare nel dettaglio della nostra applicazione (anche se non l'abbiamo ancora pubblicata, la troveremo comunque in quanto all'inizio del posto ne abbiamo riservato il nome).

Tra le voci disponibili nel menu a sinistra troveremo la voce Services: clicchiamo su Push Notifications e, nella schermata che compare, clicchiamo sulla voce Live Services site. Verremo portati al sito dedicato alla registrazione di tutte le applicazioni che interagiscono con i servizi di Microsoft. Qui dovremo effettuare due operazioni:

  1. Nella sezione API Settings, dovremo impostare su Yes alla voce Mobile or desktop client app.
  2. Nella sezione App Settings, dovremo prendere nota del parametro Client ID: ci servirà in fase di login.

 

Ora possiamo iniziare il processo di autenticazione all'interno dell'applicazione usando un altro metodo della classe OneDriveExtensions, ovvero GetClientUsingWebAuhtenticationBroker() .

private async void OnOneDriveWebViewLogin(object sender, RoutedEventArgs e)

{

IOneDriveClient client = OneDriveClientExtensions.GetClientUsingWebAuthenticationBroker("00000000481837EF", Scopes);

await client.AuthenticateAsync();

refreshToken = client.AuthenticationProvider.CurrentAccountSession.RefreshToken;

ApplicationData.Current.LocalSettings.Values["RefreshToken"] = refreshToken;

}

Con questa modalità sfrutteremo il classico processo di autenticazione basato sul protocollo oAuth: l'utente, invece di inserire i suoi dati personali direttamente nell'applicazione (e, quindi, essere facilmente trafugabili dallo sviluppatore), li inserirà all'interno di una pagina web, controllata dal fornitore del servizio (in questo caso, Microsoft). Se l'autenticazione va a buon fine, lo sviluppatore riceverà un token (completamente anonimo) che dovrà essere incluso in tutte le chiamate successive.

Come potete notare dall'esempio, il metodo GetClientUsingWebAuthenticationBroker() richiede un ulteriore parametro oltre agli scope, ovvero l'application id: si tratta del Client ID che abbiamo recuperato in precedenza dal Dev Center. Chiamando il metodo AuthenticateAsync() comparirà una finestra di dialogo, nella quale l'utente dovrà confermare le credenziali di accesso del suo Microsoft Account. Una volta che l'autenticazione è andata a buon fine, tramite la proprietà AuthenticationProvider.CurrentAccountSession della classe IOneDriveClient siamo in grado di accedere al refresh token di cui abbiamo parlato in precedenza, tramite la proprietà RefreshToken. Dato che tale informazione ci servirà anche all'interno del background task, la salviamo nello storage locale, sfruttando la classe ApplicationData.Current.LocalSettings.

Ora abbiamo tutti gli strumenti per sfruttare le API di OneDrive anche all'interno del background task. Non entrerò in questo post nei dettagli su come creare e configurare un background task, in quanto è già stato trattato numerose volte in questo blog. Potete fare riferimento alla documentazione ufficiale all'indirizzo https://msdn.microsoft.com/en-us/library/windows/apps/mt299100.aspx

È sufficiente sapere che un background task è un progetto, di tipo Windows Runtime Component, che contiene una classe che implementa l'interfaccia IBackgroundTask. Ciò ci obbligherà a definire il metodo Run() , che viene invocato nel momento in cui viene eseguito il background task. All'interno di questo metodo andremo ad includere il codice che si autenticherà, in maniera silente, con OneDrive e effettuerà l'upload del file con i dati della nostra applicazione.

Ecco un esempio di codice completo di un background task:

public sealed class UploadTask: IBackgroundTask

{

private readonly string[] Scopes = new[] { "wl.signin", "wl.offline_access", "onedrive.readwrite" };

 

public async void Run(IBackgroundTaskInstance taskInstance)

{

var deferral = taskInstance.GetDeferral();

if (ApplicationData.Current.LocalSettings.Values.ContainsKey("RefreshToken"))

{

string refreshToken = ApplicationData.Current.LocalSettings.Values["RefreshToken"].ToString();

string returnUrl = WebAuthenticationBroker.GetCurrentApplicationCallbackUri().ToString();

IOneDriveClient client = await OneDriveClient.GetSilentlyAuthenticatedMicrosoftAccountClient("00000000481837EF", returnUrl, Scopes,

refreshToken);

 

StorageFile file = await Package.Current.InstalledLocation.GetFileAsync("BackgroundWallpaper.jpg");

using (Stream stream = await file.OpenStreamForReadAsync())

{

await client.Drive.Root.ItemWithPath("OneDrive Sample/BackgroundWallpaper.png").Content.Request().PutAsync<Item>(stream);

}

}

 

 

deferral.Complete();

}

}

Il primo passo è controllare la presenza nello storage locale del refresh token, tramite il metodo ContainsKey() esposto dalla collezione ApplicationData.Current.LocalSettings.Values. La seconda informazione che ci serve è l'url di callback, ovvero l'url che i servizi di OneDrive devono richiamare nel momento in cui l'autenticazione è stata complicata. Questa informazione, in realtà, non è necessaria per un'applicazione mobile: viene sfruttata, infatti, soprattutto negli scenari web, in quanto identifica la pagina del nostro sito che dovrà elaborare il risultato dell'operazione di login. La possiamo recuperare tramite la classe WebAuthenticationBroker che, grazie al metodo GetCurrentApplicationCallbackUri() , ci restituisce un URL valido per la nostra applicazione.

Ora siamo in possesso di tutti gli strumenti necessari per effettuare l'autenticazione silente tramite il metodo GetSilentlyAuthenticatedMicrosoftAccountClient() esposto dalla classe OneDriveClient. Le informazioni richieste sono, nell'ordine:

  1. Il Client ID dell'applicazione, che abbiamo recuperato in precedenza dal Dev Center.
  2. L'url di callback
  3. Gli scope
  4. Il refresh token

Il gioco è fatto: ora abbiamo in mano un oggetto di tipo IOneDriveClient autenticato, che ci permetterà di usare le API di OneDrive allo stesso modo di come abbiamo fatto nell'applicazione principale. L'esempio di codice precedente recupera un'altra immagine presente all'interno del nostro progetto Visual Studio (chiamata BackgroundWallpaper.jpg) e la carica su OneDrive, anche quando l'applicazione non è in esecuzione. In uno scenario reale, avremmo effettuato l'upload del file che contiene i dati della nostra applicazione, presente nello storage locale.

Se avete registrato correttamente il task in background e volete testarne il corretto funzionamento, potete sfruttare il menu a tendina presente in Visual Studio Lifecycle events. Al suo interno, oltre a trovare le opzioni per simulare il ciclo di vita dell'applicazione, troveremo anche il nome del nostro task: premendolo, simuleremo l'esecuzione del task, senza dover attendere che il trigger ad esso collegato venga scatenato.

Maneggiare con cura

Come avete visto, l'SDK di OneDrive è molto potente e ci permette di implementare velocemente soluzioni di sincronizzazione o di backup e ripristino dei dati nelle nostre applicazioni. È importante, però, fare una serie di considerazioni prima di sceglierla come soluzione principale per la sincronizzazione dati:

  1. L'SDK di OneDrive lavora con file e cartelle e, di conseguenza, siete costretti ogni volta ad effettuare l'upload e il download completo del file di dati. Nel caso, perciò, in cui il database della vostra applicazione possa raggiungere dimensioni importanti è meglio affidarsi alle Mobile App di Azure: dato che lavorano direttamente con il database, è possibile sincronizzare solo i dati che sono stati effettivamente modificati rispetto all'ultima volta, minimizzando perciò il trasferimento di dati.
  2. Per lo stesso motivo, la risoluzione dei conflitti è più complessa e presenta maggiori limiti: non abbiamo modo di risolvere i singoli conflitti, ma possiamo solamente capire eventualmente qual è la versione più recente del file e scegliere se dare la priorità. Di conseguenza, in scenari limite, ci sono maggiori probabilità di perdita di dati.

In conclusione

Nel corso di questo post abbiamo visto come sfruttare l'SDK di OneDrive per effettuare operazioni di download e upload di dati, che possiamo sfruttare per aggiungere alla nostra applicazione funzionalità di backup e ripristino o di sincronizzazione dati. È importante, però, tenere a mente le considerazioni fatte nel corso del post, per capire se si tratta della soluzione migliore per il nostro progetto o se è il caso, invece, di scegliere soluzioni differenti.

Potete trovare la soluzione descritta nel post sul mio repository GitHub all'indirizzo https://github.com/qmatteoq/OneDriveSDK-Sample Unico accorgimento: la proprietà ClientId sarà vuota, in quanto deve essere sostituita l'informazione relativa ad una vostra applicazione, che deve essere stata registrata sullo Store utilizzando il vostro account sviluppatori.

Happy coding!