Technology Experience

.NET World

Programmazione, libri, snippet di codice, articoli tecnici

.NET World

Parse.com : piattaforma cloud per desktop e mobile

La settimana scorsa ho tenuto un corso su Windows Presentation Foundation e MVVM e come spesso mi capita, nei tempi morti (a pranzo, oppure davanti alla macchinetta del caffè) si continua a chiaccherare di tecnologia con i partecipanti del corso stesso. E’ in una di queste chiaccherate che sono venuto a conoscenza di Parse.com, una piattaforma cloud che in pochi passaggi vi permette di avere un database documentale a vostra completa disposizione. E non solo questo, dal momento che potete usufruire di una serie di servizi come le push notification in ambito mobile, data analytics e così via. Data la scarsità del tempo che ho a disposizione in questi giorni, ho avuto poco tempo per studiare la piattaforma, ma secondo me è interessante, perchè vi toglie le preoccupazioni della gestione di un vostro server, o di altre tematiche come performance o scalabilità: parliamo di cloud puro, insomma. I punti di forza di Parse.com secondo me sono la gratuità del servizio (almeno fino a quando non avete bisogno di salire di qualità o di quantità di dati – visitate questa pagina per avere il pricing), ed il fatto che è multi-piattaforma (ci sono SDK e sample code per .NET, iOS, Android, Javascript, PHP e via dicendo).

Dal punto di vista tecnico – che sto un po’ studiando questa mattina – le cose sono molto semplici. Una volta registrati, si ottengono i soliti parametri Application ID e Client Key, da inserire nel codice della vostra applicazione.

ParseClient.Initialize("appKey", "secretKey");

Ovviamente trovate tranquillamente la libreria su NuGet:

nuget

 

Tutta la logica di caricamento & salvataggio delle vostre entity passa attraverso l’utilizzo della classe ParseObject. Quindi quello che dovete fare è trasformare le vostre entity di dominio (aggregate in ottica DDD, per capirci) in oggetti ParseObject, che dietro le quinte non sono nient’altro che Dictionary<string, object>. Ad esempio:

public async Task<string> SalvaAutomobileAsync(Automobile automobile)
{
    string className = automobile.GetType().Name;
    ParseObject obj = new ParseObject(className);
    obj["Marca"] = automobile.Marca;
    obj["Modello"] = automobile.Modello;
    obj["Cilindrata"] = automobile.Cilindrata;
    await obj.SaveAsync();

    return obj.ObjectId;
}

E’ solo codice di esempio, chiaramente, giusto per capire come funzionano le cose.

Parse.com vi mette a disposizione una dashboard online per visualizzare le entity salvate (che vengono salvate in formato serializzato usando JSON) e per compiere tutta una serie di operazioni, che per ora ho trascurato e che prenderò in considerazione solo se finiranno per servirmi (mi riferisco a Cloud Code per schedulare dei job, oppure a App Configuration per salvare sul cloud le impostazioni della vostra applicazione, e via dicendo).

Insomma, Parse.com è un’alternativa come tante, uno strumento a disposizione di noi dev, per cui vale sempre la pena di darci un’occhiata per capire pro & contro.

Send to Kindle
.NET World

Un nuovo blog su Unity! Mi fa solo piacere!

L’amico Marcello Marchetti ha aperto in questi giorni un nuovo blog dedicato interamente a Unity 3D, l’ambiente di sviluppo che permette di creare giochi multipiattaforma in 2D e 3D, per PC e per tutte le piattaforme mobile iOS / Windows Phone / Android. E molto altro ancora.

unity_platform

Chi di voi segue la community, molto probabilmente conosce già Marcello, dal momento che è già qualche anno che tiene sessioni su Unity 3D nei vari eventi che si succedono con il passare del tempo. Il suo blog è un’occasione per essere informati e per leggere contenuti – ne sono certo – anche di un certo spessore, visto che l’autore non è certo un novellino su Unity 3D.

In un mondo dominato dai social, sono davvero felice dell’apertura di questo nuovo blog.

Buona lettura! Grazie Marcello!

Send to Kindle
.NET World

Microsoft Azure for student developers

Se siete studenti, Microsoft ha buone notizie per voi.

Grazie al programma Microsoft Azure for student developers, attivo dallo scorso 24 Marzo, potete attivare un abbonamento Azure con tutta una serie di vantaggi. Ad esempio, potete utilizzare il vostro normale Microsoft Account (associato al programma Dreamspark) e non c’è più il vincolo di dover inserire a tutti i costi il numero di carta di credito (cosa che spesso gli studenti non posseggono).

Azure è una grande opportunità per tutti noi developer e nella visione di Microsoft mira a diventare la casa di tutti, dal momento che permette di hostare un elevatissimo numero di software e servizi non solo di proprietà Microsoft. Permette di avere macchine virtuali Linux, o database server come Oracle, piuttosto che mettere online siti in pochi minuti implementati con linguaggi come Java, PHP o Python. Il programma Microsoft Azure for student developers è attivo in 140 Paesi del mondo, tra cui ovviamente l’Italia, altrimenti non sarei più a parlarvene.

Maggiori informazioni qui.

Send to Kindle
.NET World

Essere notificati dei cambiamenti di valore di una DependencyProperty

La dependency property (d’ora in poi DP) LanguageProperty è una proprietà definita nell’oggetto FrameworkElement di WPF (assembly PresentationFramework.dll, namespace System.Windows). Oggi mi è servito implementare un meccanismo per mettermi in ascolto di tutti i cambiamenti di valore di questa proprietà nel costruttore di uno UserControl, cosa che sarebbe banale nel caso di una nostra custom dependency property (quando si crea una DP ci viene praticamente gratis il meccanismo di PropertyCallback), ma un po’ meno quando si tratta di una DP di quelle predefinite di WPF.

Ho risolto così:

private void ListenForChangingLanguage()
{
    DependencyPropertyDescriptor dpd = DependencyPropertyDescriptor
        .FromProperty(LanguageProperty, typeof(UserControl));

    if (dpd != null)
    {
        dpd.AddValueChanged(this, delegate
        { // TODO });
    }
}

Questo meccanismo è piuttosto comodo, e lo si ottiene con poche linee di codice. All’interno del costruttore del mio UserControl chiamo il metodo qui sopra e tutto viene gratis. Chiaramente ciò che implementate all’interno del delegate è a carico vostro, io l’ho lasciato volutamente vuoto (a parte il commento, LOL). A me è servito per hostare un mio UserControl in una normalissima Window WPF, e giocando con la LanguageProperty posso essere notificato all’interno dello UserControl e reagire di conseguenza (nel mio caso cambio a run-time la lingua).

Send to Kindle
.NET World

Usare WPF Localization Extension con un ContextMenu definito nelle risorse di una Window

Mi è stato chiesto di sviluppare uno UserControl WPF multilingua, quindi in grado di switchare sia a design-time che a run-time da una lingua all’altra. Ovviamente mi sono buttato subito sull’extension WPF Localization Extension. Direi che è semplice da utilizzare (una volta capiti bene i suoi meccanismi) e fa quello che promette. Supporta il passaggio da una lingua all’altra a run-time, supporta una lingua da visualizzare a design-time, ed è facile aggiungere nuove lingue, dal momento che è sufficiente creare un nuovo file di risorse dedicato alla nuova lingua.

Do per scontato che sappiate già utilizzare questa extension. Supponiamo di avere una Window definita come segue:

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:lex="http://wpflocalizeextension.codeplex.com"
        lex:LocalizeDictionary.DesignCulture="en-US"
        lex:ResxLocalizationProvider.DefaultAssembly="WpfApplication1"
        lex:ResxLocalizationProvider.DefaultDictionary="Strings"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Button Content="{lex:Loc Ok}" Width="100" Height="30" />
    </Grid>
</Window>

Qui si instanzia il WPF Localization Extension, dicendo che la culture a design-time è “en-US”, che le risorse sono contenute nell’assembly “WpfApplication1” e che i file di risorse si chiamano “Strings.resx” (e di conseguenza Strings.it-IT.resx, Strings.fr-FR.resx, e via dicendo).

Il problema nasce quando si vuole definire un ContextMenu nelle risorse della Window. D’istinto verrebbe da scrivere il seguente codice XAML:

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:lex="http://wpflocalizeextension.codeplex.com"
        lex:LocalizeDictionary.DesignCulture="en-US"
        lex:ResxLocalizationProvider.DefaultAssembly="WpfApplication1"
        lex:ResxLocalizationProvider.DefaultDictionary="Strings"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <ContextMenu x:Key="m">
            <MenuItem Header="{lex:Loc Menu1}" />
            <MenuItem Header="{lex:Loc Menu2}" />
            <MenuItem Header="{lex:Loc Menu3}" />
        </ContextMenu>
    </Window.Resources>
    <Grid>
        <Button Content="{lex:Loc Ok}"
                ContextMenu="{StaticResource m}"
                Width="100" Height="30" />
    </Grid>
</Window>

In pratica, abbiamo aggiunto un ContextMenu con x:Key=”m”, e lo si utilizza all’interno del Button. Peccato che il WPF Localization Extension non sia in grado di trovare le stringhe localizzate. Ve ne accorgete perchè invece di vedere la stringa prelevata dal vostro file di risorsa, trovate la stringa “Key:Menu1” (vado a memoria), segno inequivocabile che qualcosa è andato storto. E’ vero quello che ho appena scritto? Non proprio. Va sempre bene utilizzare la markup extension {lex:Loc}, ma va utilizzata una sintassi differente, che è la seguente:

<ContextMenu x:Key="m">
    <MenuItem Header="{lex:Loc WpfApplication1:Strings:Menu1}" />
    <MenuItem Header="{lex:Loc WpfApplication1:Strings:Menu2}" />
    <MenuItem Header="{lex:Loc WpfApplication1:Strings:Menu3}" />
    <MenuItem Header="{lex:Loc WpfApplication1:Strings:Menu4}" />
    <MenuItem Header="{lex:Loc WpfApplication1:Strings:Menu5}" />
</ContextMenu>

Non ho trovato una documentazione ufficiale (ma io con i motori di ricerca, si sa, non sono bravissimo), ma direi che la sintassi sia: <namespace>:<file_di_risorsa:<chiave>. Strana sintassi, perchè bisogna separare ogni parte con un “:”, come si vede dallo stralcio di XAML qui sopra.

Et voilà, il gioco è fatto! Così il ContextMenu viene correttamente popolato con le traduzioni prese dal file di risorsa, traduzioni che cambiano anche a run-time nel caso in cui switchate da una lingua all’altra programmaticamente agendo sull’oggetto singleton LocalizeDictionary.

Send to Kindle
.NET World

Cosa dovrebbero sempre avere le vostre app per Windows Phone

Nel momento in cui vi scrivo, VivendoByte ha pubblicato quasi un centinaio di app per Windows Phone, e purtroppo molte meno per Windows 8.1. Diciamo che mi sento piuttosto preparato sull’argomento, per cui ho deciso di scrivere questo post, che spero possa essere utile a tutti quelli che sviluppano app – teoricamente non solo per Windows Phone, contenente tutta una serie di piccoli accorgimenti che renderanno la vostra app più gradevole. Il tema predominante è di questo vademecum è il tema “mantenere il contatto con i vostri utenti”. In cosa consiste? Partiamo subito!

Se avete un account Twitter dedicato, usatelo!
Per esempio, do un po’ di tempo ho aperto l’account @VivendoByte, che utilizzo soprattutto per comunicare l’uscita di nuove app, oppure aggiornamenti per quelle già disponibili sullo store, oppure altre informazioni riguardanti il mondo VivendoByte. Come sfruttare questa cosa dalla vostra app? Beh, sappiamo che per ottenere la certificazione siamo già obbligati adesso ad implementare una pagina di About, con i nostri vari recapiti digitali (e-mail per il supporto tecnico, nome dell’applicazione, versione, etc.). Nulla vieta di inserire da qualche parte una voce “Seguici su Twitter” (“Follow us on Twitter”, in inglese), che apre Internet Explorer. In questo modo l’utente sa che esistete anche sul social network dei cinguettii, e può followarli in modo estremamente rapido. Questa funzionalità può essere inserita ovunque: nell’application bar dell’app, oppure in qualsiasi altro luogo.

Invogliate l’utente a dare un feedback alla vostra app
Statisticamente sappiamo che gli utenti Windows Phone sono i più restii ad andare sullo store per lasciare un qualche commento alla vostra app. Come realizzare tutto ciò? Vi do qualche consiglio:

  1. sappiamo che c’è un launcher che permette di raggiungere la pagina della nostra app: questo launcher deve essere proposto ogni tanto all’utente
  2. cosa intendo con “ogni tanto”? Dipende. Può essere “ogni 5 volte che l’utente avvia l’app”, che è la tecnica che mi piace di più. Può dipendere da quanto tempo utilizza l’app stessa.

Qui purtroppo c’è una cosa che ad oggi non è fattibile. Mi piacerebbe avere del codice C# che mi permette di capire se l’utente ha già lasciato un feedback alla mia app. Se no, lo devo quasi amichevolmente costringere; se sì, posso fare in modo di rinviare la proposta di rating, ad esempio che appaia solo dopo che sono trascorsi 3 mesi.

Se l’app è un gioco (ma non solo), posso decidere di sbloccare determinate caratteristiche (livelli, funzionalità avanzate, etc.) solo se l’utente decide di dare un feedback.

Mail di supporto tecnico
Come dicevo prima, per la certificazione è necessario inserire da qualche parte la vostra mail di contatto. Se per caso stiate sottovalutando questa cosa, non fatelo. Dalle mie quasi 100 app ho ricevuto diverse mail, di ogni tipo, dall’Italia e dall’Estero. Erano mail di chiarimento, di segnalazione bug, di suggerimento, di nuove proposte. Ne ricordo due in particolare: una tizia americana (il cui indirizzo e-mail era associato ad Intel Inc.) che mi faceva i complimenti per la mia app “Gps Coordinate Converter”; l’altra invece era di un italiano, che mi ha segnalato un errore di conteggio nella mia app “Deputati Italiani” per Windows Phone. Quindi, fatelo: inserite una mail di supporto tecnico, e fateci affidamento, perchè non si può mai sapere cosa potrebbero dirvi. Oltre a questo, molto meglio ricevere una mail piuttosto che un feedback sullo store con una sola misera stellina, giusto?

Un bel tutorial
Mi è capitato, a volte, di scaricare e di provare ad usare app semplici, ma che all’inizio mi facevano sentire spaesato, soprattutto se magari trattano di argomenti che non siete abituati a padroneggiare. Altre volte, invece, app complesse con cui mi sono trovato a mio agio.

Io vi do un piccolo consiglio. Indipendentemente dal fatto che stiate sviluppando un’app banale o complessa, inserite un tutorial, o comunque una Page che spieghi semplicemente come usare l’app. Io qui dentro spiego un po’ di tutto:

  • cosa fa l’app, in due parole
  • come “navigare” all’interno dell’app
  • eventuali limitazioni della versione trial, e le potenzialità di quella a pagamento
  • aprofittatene, ancora una volta, per sollecitare il contributo dell’utente: lasciare una review sul marketplace, di scrivere una mail in caso di problemi, invogliarlo in questo senso promettendogli di rilasciare nuovi e tanti aggiornamenti dell’app nel caso in cui l’app avrà un certo numero di download

App a pagamento? Invogliatelo all’acquisto, ma occhio a come lo fate!
Se la vostra app è a pagamento, ed avete sviluppato la versione trial, monitorate il numero di avvii che l’app fa. Ogni cinque avvii potreste proporre all’utente l’acquisto, mandandolo direttamente sulla pagina della vostra app pubblicata sul marketplace. Evitate, ma questo è un parere del tutto personale, di fare antipatici in-app purchase all’interno di app freeware: penso che sia una presa in giro. Vi faccio un esempio: non ricordo esattamente quale fosse l’app, so per certo che registrava video da pubblicare su Vine. L’app era gratuita, per cui ero bello soddisfatto e contento. L’ho usata a Parigi alcune volte. Poi una sera, di fronte a non so cosa, la lancio, registro il video e TAC: per pubblicare il video avrei dovuto “sbloccarla” pagando 2,49 euro. Non l’ho acquistata per principio, perchè mi sono sentito preso in giro. Se l’app fosse stata a pagamento, l’avrei magari acquistata senza problemi. Il fatto che fosse freeware, e senza alcun preavviso mi avesse chiesto dei soldi me l’ha resa automaticamente antipatica.
Perciò pensateci bene!

Fine
Tutto qua, spero di avervi dato qualche dritta interessante.

Send to Kindle
.NET World

Se siete dev Windows Phone, non potete non seguire WP Dev Fusion

Il 2014 si sta aprendo con un nuovo nome che gira attorno al mondo degli sviluppatori Windows Phone. Grazie al contributo del mio amico Matteo Pagani (MVP su Windows Phone e Nokia Developer Champion), ma non solo, sta nascendo il brand WP Dev Fusion, che porterà eventi ed altre iniziative importanti, in Italia e nel mondo.

Altre informazioni sulle vere origini di questa iniziativa le potete trovare direttamente sul blog di Matteo e chiaramente sul sito ufficiale http://www.wpdevfusion.com/. Sappiamo poche cose finora, e tutto questo non fa altro che accrescere ulteriormente la voglia di vedere cosa stiano organizzando dietro le quinte.

Ma l’attesa sta per finire, dal momento che il prossimo 22 Gennaio, alle 18 ora italiana, ci sarà il primo evento, esclusivamente online, in cui gli speaker ci illustreranno la tecnologia Windows Phone con una serie di sessioni riguardanti gli argomenti più interessanti. Per registrarvi andate direttamente a questa pagina su EventDay. Sarà tutto in inglese, chiaramente, perchè quando parliamo di WP Dev Fusion parliamo di qualcosa a livello internazionale, e non solo una cosa riguardante il panorama italiano.

Francamente non mi resta che consigliarvi di puntare la vostra attenzione su WP Dev Fusion. Sicuramente ne vedremo delle belle!

Send to Kindle
.NET World

Ricordare la posizione delle Window di WPF usando MVVM

Una delle caratteristiche che trovo simpatiche in un’applicazione Windows è quando si ricorda la posizione e la dimensione delle finestre. Questa cosa diventa ancora più utile se si utilizza più di un monitor, perchè a questo punto la nostra applicazione si ricorderà di aprire le finestre anche sull’eventuale monitor secondario, ridimensionate e nella stessa identica posizione in cui la avevamo lasciate l’ultima volta.

Fare questa cosa con il code-behind è piuttosto banale, perchè basta gestire gli eventi Closed e Loaded delle finestre: nel primo caso bisogna salvare da qualche parte posizione e dimensione, nel secondo caso bisogna leggerle e ripristinarle.

E se volessi implementare questo meccanismo in un’applicazione enterprise sviluppata con MVVM? Magari scrivendo un codice XAML di questo tipo:

<Window x:Class="AppDiProva.UI.WPF.Views.LoginWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:helper="clr-namespace:Helpers.Xaml"
        Title="Titolo" Height="370" Width="500" ResizeMode="NoResize"
        
        helper:WindowStateHelper.Active="True">
</Window>

 

Ho volutamente lasciato una riga spaziata per evidenziare l’helper che utilizzo, e che ovviamente mi sono scritto per gestire questo scenario. In pratica, si tratta di una classe WindowStateHelper, con una sola dependency property booleana, che imposto a “True”. Quando viene attivata, come nell’esempio qui sopra, internamente fa tutto quanto il lavoro, che può essere riassunto così:

  1. sottoscrive gli eventi Closed e Loaded della Window
  2. quando una finestra viene chiusa, salvo in un semplice file di testo la dimensione e la posizione della finestra; il nome del file viene generato prendendo in pratica il nome della classe, sostituendo ogni “.” con “-“, giusto per rendere il nome del file gradevole. Quindi lo stato di una Window con nome VivendoByte.MioSoftware.UI.LoginWindow verrebbe salvato nel file “VivendoByte-MioSoftware-UI-LoginWindow.txt”
  3. quando una finestre viene riaperta, controllo se esiste un file che contiene il suo stato (prendo il nome della classe, come nel punto 2): se esiste, lo leggo e lo decodifico, e reimposto dimensione e posizione. Se non esiste, significa che è la prima volta che è stata aperta, per cui non faccio nulla
  4. I files vengono salvati nella directory Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + "\Mio Programma\"; evitate la cartella di roaming, perchè in questo modo andreste a sincronizzare i files sugli altri PC con cui vi loggate con lo stesso Microsoft Account. E quindi significa che se su un PC avete due monitor Full HD, e su un notebook avete una vetusta 1366×768, le finestre potrebbero non comparire perchè al di fuori dell’area visibile

Lo trovo piuttosto elegante, e soprattutto molto trasparente, perchè il developer finale dell’applicazione non si accorge di nulla. Lui sa che lo stato delle finestre viene salvato e ripristinato, e tanto basta, senza troppe complicazioni e concentrandosi sulla sua applicazione finale.

Il codice dell’helper è scaricabile da qui. E’ sicuramente migliorabile, ma è un buon punto di partenza.

Send to Kindle
.NET World

Uploadare/Scaricare files da Windows Phone 8 su Skydrive

Una delle features a mio avviso che è poco sfruttata all’interno delle app Windows Phone è quella di poter uploadare/scaricare files dallo smartphone sul cloud (nel caso specifico Skydrive). A cosa potrebbe servire? Beh, immaginatevi un’app di qualsiasi tipo, che abbia impostazioni, files, fotografie, audio, qualsiasi contenuto. Se comprate un altro telefono Windows Phone, oppure se resettate il telefono, quei contenuti li perdete, perchè erano inclusi nell’Isolated Storage di quell’app specifica. Esempio concreto: immaginate Rowi, uno dei client Twitter più importanti ed utilizzati: voi lo acquistate la prima volta, lo impostate con i vostri account, e regolate le impostazioni come piacciono a voi. Poi sostituite il telefono, oppure resettate l’attuale, e perdete tutto quanto, e siete costretti a reimpostare daccapo tutto quanto. Oppure un gioco come Angry Birds: tutte le volte che lo installate, non c’è alcun modo per recuperare le partite che avevate. E così via, in generale il discorso si può applicare a bene o male tutte le app Windows Phone.

Grazie al Live Connect SDK, possiamo sfruttare le potenzialità del cloud Skydrive all’interno delle nostre app Windows Phone. Quindi: all’interno di una nostra app possiamo:

  • inviare su Skydrive qualsiasi files che abbia un senso (impostazioni, file di dati dell’utente, etc.)
  • scaricare i files per recuperare i vecchi contenuti

Il livello base l’ha già spiegato l’amico Matteo Pagani, in questo post sul suo blog in inglese. Qui viene spiegato quali reference aggiungere al progetto, come aggiungere il pulsante di login, e come inviare/scaricare files. Il tutto riguarda Windows Phone 7, ma va benissimo anche per Windows Phone 8: possiamo però sfruttare qualche miglioria, che ai tempi della stesura del post non esisteva (esempio: possiamo utilizzare le tecniche async/await, evitando le varie callback che complicano la leggibilità del codice). Però il 95% va più che bene.

Quello che non mi piace è che quel codice salva i files alla root di Skydrive.

Questo comporta che l’utente potrebbe inavvertitamente cancellare i files, perchè non li riconosce. Oppure potrebbe capitare che più app vadano a scrivere sugli stessi files: cosa un po’ assurda da pensare, ma mica tanto: non è poi così assurdo pensare che le impostazioni di un’app vengano salvate in un file chiamato Settings.xml, tramite serializzazione/deserializzazione. E quindi è assolutamente una cosa da evitare (almeno io la penso così).

La conclusione di tutto ciò è che si comincia a lavorare con i folder su SkyDrive.

Quindi, supponiamo: stiamo sviluppando un’app chiamato “La mia bella app”, che intenda inviare/scaricare files su Skydrive, dentro un folder chiamato “La mia bella app”. Cosa si realizza tutto ciò? Io mi sono inventato questo metodo helper, che in pratica fa una cosa molto semplice: dopo che ha ottenuto l’accesso al vostro account Skydrive, legge la root, e scansiona tutte le directory presenti, alla ricerca di quella che si chiama “La mia bella app”. Se la trova, ne recupera il Folder ID; se non la trova, la crea e ne recupera il Folder ID. Tramite questo Folder ID, possiamo utilizzare gli stessi metodi spiegati da Matteo Pagani nel suo post, solo che invece di lavorare alla root, lavoriamo all’interno del nostro folder.

private async Task EnsureSkyDriveFolderExists(string folderName)
{
    this.SkyDriveOperationWaiting.IsIndeterminate = true;
    this.SkyDriveOperationDescription.Text = "Controllo cartella su SkyDrive";
    var response1 = await client.GetAsync("me/skydrive/files");
    List<object> items = response1.Result["data"] as List<object>;

    foreach (object item in items)
    {
        IDictionary<string, object> directories = item as IDictionary<string, object>;

        if (directories["name"].ToString() == folderName)
        {
            this.SkyDriveOperationDescription.Text = "Cartella su SkyDrive ok";
            ApplicationContext.Instance.FolderIdSkyDrive = directories["id"].ToString();
            App.SaveSettings();
            return;
        }
    }

    this.SkyDriveOperationDescription.Text = "Creazione cartella su SkyDrive";
    
    var folderData = new Dictionary<string, object>();
    folderData.Add("name", folderName);

    var response4 = await client.PostAsync("me/skydrive", folderData);
    ApplicationContext.Instance.FolderIdSkyDrive = response4.Result["id"].ToString();
    App.SaveSettings();

    this.SkyDriveOperationDescription.Text = "Cartella su SkyDrive ok";
}

 

Il codice va un po’ ripulito, perchè ci sono riferimenti a controllo sulla UI, come ProgressBar e TextBlock, che mantengono informato l’utente su ciò che sta accadendo. La logica è questa:

  1. Grazie al path “me/skydrive/files” recupero l’elenco di file e directory presenti alla root di Skydrive
  2. Ottenuto l’elenco, lo ciclo alla ricerca della directory chiamata “folderName”, che è una stringa che arriva in input a questo metodo
  3. Se la trova, salva il Folder ID da qualche parte (io la memorizzo in una classe singleton AppicationContext), salva le nuove impostazioni ed esce
  4. Se il folder non viene trovato, allora viene creato (metodo PostAsync), viene recuperato il Folder ID, il tutto viene salvato e si esce dal metodo

Una precisazione è d’obbligo.

Teoricamente parlando, il codice potrebbe salvarsi il Folder ID al momento della prima generazione della cartella, in modo tale che si eviterebbe ogni volta di controllare se esiste oppure no. Sbagliato! Ricordiamoci che l’utente potrebbe cancellare il folder su SkyDrive (attraverso il sito, oppure attraverso una qualsiasi app Windows Phone, Windows 8, etc.). Quindi è importante andare a controllare l’esistenza del folder, ogni volta.

Una volta che si esce da questo metodo, si è pronti per inviare files all’interno di questo folder:

await client.UploadAsync(ApplicationContext.Instance.FolderIdSkyDrive, s,
    stream, OverwriteOption.Overwrite);

 

Il primo parametro del metodo UploadAsync è proprio il Folder ID che abbiamo ottenuto. Matteo nel suo post indicava “me/skydrive”, per uploadare nella root. Indicando il Folder ID, i files vengono uploadati all’interno del nostro folder.

Scaricare un files è un filo più complesso. Con questo metodo:

var response2 = await client.GetAsync(
    string.Format("{0}/files",
    ApplicationContext.Instance.FolderIdSkyDrive));

recuperiamo l’elenco dei files contenuti nel folder indicato da Folder ID. Una volta che abbiamo l’elenco, dobbiamo ciclare la lista e scaricare solo quello che ci interessa (oppure banalmente implementare un foreach per scaricarli tutti quanti). Per scaricare un file, si utilizza questo metodo:

var response3 = await client.DownloadAsync
    (string.Format("{0}/content",
    fileId));

Il risultato di tutto questo giro di codice è che sulo Skydrive del nostro utente ci sarà un folder chiamato come vogliamo noi, con tutto ciò che abbiamo deciso di uploadare. Se abbiamo dato un nome chiaro al folder, l’utente lo riconoscerà senza problemi: potrebbe decidere di cancellarlo oppure no (questo è chiaramente al di fuori del nostro controllo, per cui non ci dobbiamo fare troppo affidamento).

Send to Kindle
.NET World

WCF Service e Dependency Injection con Castle Windsor

Supponiamo di avere un servizio WCF, molto semplice in questo esempio, la cui interfaccia è la seguente:

[ServiceContract]
public interface ICalculation
{
    [OperationContract]
    int Calculate(int a, int b);
}

C’è un unico metodo che prende due interi e ne restituisce un terzo. Supponiamo adesso di scrivere il servizio WCF vero e proprio, cablando la logica del metodo Calculate per farlo funzionare come somma. Quindi:

public class Calculation : ICalculation
{
    public int Calculate(int a, int b)
    {
        return a + b;
    }
}

Primo refactoring. Spostiamo la logica della somma in una classe dedicata, che magari a sua volta implementa un’altra interfaccia che chiameremo IOperation.

public class Calculation : ICalculation
{
    public int Calculate(int a, int b)
    {
        IOperation operation = new SumOperation();
        var result = operation.Calculate(a, b);

        return result;
    }
}

Quello che accade è che ogni volta che viene invocato il metodo Calculate sul servizio WCF, viene creata una nuova istanza di una ipotetica classe SumOperation, che implementa IOperation, che effettua il calcolo ed il tutto torna al client. L’interfaccia IOperation è identica alla ICalculation, in questo caso, ma potrebbe avere una definizione diversa.

La cosa bella di questo approccio è che a questo punto posso creare classi come MultiplyOperation, SubtractOperation e così via. Basta cambiare il tipo istanziato nel servizio WCF, mentre tutto il resto rimane identico.

Passiamo al secondo refactoring.

public class Calculation : ICalculation
{
    IOperation calculationEngine;

    public Calculation()
    {
        this.calculationEngine = new MultiplyOperation();
    }

    public int Calculate(int a, int b)
    {
        var result = this.calculationEngine.Calculate(a, b);

        return result;
    }
}

Evitiamo di istanziare la classe ad ogni chiamata di Calculate. Definisco un field di tipo IOperation, la cui istanza concreta viene creata ed assegnata nel costruttore. Nell’esempio qui sopra creo un’istanza di MultiplyOperation, giusto per far capire che volendo posso switchare da un comportamento all’altro senza troppi problemi.

Quarto refactoring. Usiamo un motore di Dependency Injection, il cui scopo – detto in breve – è rimuovere tutte le new inserite nel codice (LoL).

Quello che mi piacerebbe ottenere è un codice come questo:

public class Calculation : ICalculation
{
    IOperation operationEngine;

    public Calculation(IOperation operation)
    {
        this.operationEngine = operation;
    }

    public int Calculate(int a, int b)
    {
        var result = this.operationEngine.Calculate(a, b);

        return result;
    }
}

In questo caso il costruttore stesso del servizio non è più parameter-less, ma prende in input un’istanza di un oggetto IOperation. Qualcuno deve fornire al servizio WCF questa istanza, e questo qualcuno è proprio un motore di Dependency Injection, nel nostro caso Castle Windsor.

La cosa non è così immediata, tra l’altro, perchè se provate adesso a mandare in esecuzione il servizio WCF qui sopra, sia attraverso il tool WcfTestClient.exe, oppure se tentate di raggiungere l’url del file .svc via browser, giustamente vi viene restituito un errore, perchè manca un costruttore parameter-less e quant’altro.

Quindi, ecco la soluzione.

  1. Con NuGet installate i pacchetti Castle Windsor e Castle Windsor WCF Integration Facility
  2. Al progetto aggiungete il file Global.asax

Modificate il codice della classe Global come segue:

public class Global : HttpApplication, IContainerAccessor
{
    public IWindsorContainer Container { get; private set; }

    protected void Application_Start(object sender, EventArgs e)
    {
        ServiceMetadataBehavior metadata = new ServiceMetadataBehavior();
        metadata.HttpGetEnabled = true;

        var Container = new WindsorContainer(new XmlInterpreter())
            .AddFacility<WcfFacility>()
            .Register(Component.For<ICalculation>()
            .ImplementedBy<Calculation>());
    }
}

La classe Global implementa l’interfaccia IContainerAccessor (di Castle Windsor), che richiede l’implementazione di una proprietà IWindsorContainer, che difatti abbiamo aggiunto. Nel codice di Application_Start viene istanziato il container di Windsor, e viene registrato il tipo ICalculation (l’interfaccia del servizio WCF), ed il tipo concreto Calculation. Il fatto di aver specificato XmlInterpreter nel costruttore del container ha un significato molto semplice: le registrazione dei tipi viene fatta leggendo il file web.config, che dobbiamo ancora gestire. Queste righe di codice vengono eseguite una sola volta, ovvero quando il servizio WCF parte.

Il web.config ha la seguente struttura:

<?xml version="1.0"?>
<configuration>
  <configSections>
    <section name="castle"
         type="Castle.Windsor.Configuration.AppDomain.CastleSectionHandler, Castle.Windsor" />
  </configSections>
  <castle>
    <components>
      <component id="calc" service="CalculationEngine.IOperation, CalculationEngine"
                 type="CalculationEngine.SumOperation, CalculationEngine" />
    </components>
  </castle>
  <appSettings>
    <add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
  </appSettings>
  <system.web>
    <compilation debug="true" targetFramework="4.5" />
    <httpRuntime targetFramework="4.5"/>
  </system.web>
  <system.serviceModel>
    <behaviors>
      <serviceBehaviors>
        <behavior>
          <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
          <serviceDebug includeExceptionDetailInFaults="false"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <protocolMapping>
        <add binding="basicHttpsBinding" scheme="https" />
    </protocolMapping>    
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
  </system.serviceModel>
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>
    <directoryBrowse enabled="true"/>
  </system.webServer>

</configuration>

Nulla di complicato. Abbiamo definito una sezione dedicata a Castle Windsor, e poi abbiamo registrato i tipi che vogliamo che vengano gestiti da questo motore di DI. Nel nostro caso il tipo è uno solo, quello a cui fa riferimento l’interfaccia IOperation. Lo riporto qui sotto per chiarezza:

<castle>
  <components>
    <component id="calc"
                service="CalculationEngine.IOperation, CalculationEngine"
                type="CalculationEngine.SumOperation, CalculationEngine" />
  </components>
</castle>

L’attributo service indica il nome completo dell’interfaccia. L’attributo type indica il tipo concreto che implementa l’interfaccia. Da questo momento in poi Castle Windsor sa risolvere questa dipendenza: ogni volta che nel codice il costruttore di una classe richiederà un’istanza di IOperation, verrà restituita la classe SumOperation. Chiaramente, possiamo modificare questo setting e specificare qualsiasi altra classe che implementi quell’interfaccia, senza ricompilare il nostro codice.

L’ultima cosa da fare è editare il file .svc, impostandolo come segue:

<%@ ServiceHost Language="C#" Debug="true" Service="CalculationEngine.Calculation"
    Factory="Castle.Facilities.WcfIntegration.DefaultServiceHostFactory, Castle.Facilities.WcfIntegration"
    %>

Qui è importante il parametro Factory, dove abbiamo specificato la factory che Castle Windsor utilizza per i servizi WCF. Basta, abbiamo finito.

Proviamo ad eseguire?

Se adesso proviamo ad eseguire il nostro progetto, vedrete che tutto funziona bene. Cosa intendo? Intendo che parte il browser, potete navigare verso il file Calculation.svc, e quindi il servizio WCF è pronto all’uso. Questo significa che per esempio possiamo utilizzare il tool WcfTestClient passandogli l’url del servizio. Quello che accade è che Castle Windsor:

  1. Legge il file web.config e registra i tipi nel suo container, così è pronto per risolvere le dipendenze
  2. Sa che deve istanziare il servizio WCF: quando tenta di farlo, trova un costruttore che richiede un’istanza di qualcosa che implementi IOperation. Sa risolvere questa dipendenza, per cui passa al costruttore un’istanza di ciò che è specificato nel web.config (nel nostro caso SumOperation)

Fine. Il WCF si mette in attesa di qualcuno che invochi il metodo Calculate. Quando qualcuno lo fa, viene effettuato il calcolo. Ovviamente, è sufficiente modificare il web.config, specificando un altra classe IOperation, per cambiare il comportamento della nostra classe senza ricompilare nulla.

Magie della Dependency Injection!!

Qualsiasi commento e/o correzioni è sempre ben accetta.

Download della solution con Visual Studio 2012.

Send to Kindle