Technology Experience

.NET World

Programmazione, libri, snippet di codice, articoli tecnici

.NET World

Migrare dalla vecchia versione di Lightswitch a quella nuova

Mi spiego meglio. Quella vecchia è quella usabile da Visual Studio 2010, la versione 1.0. Quella nuova è quella integrata in Visual Studio 2012.

In Brain-Sys abbiamo sviluppato un gestionale per un nostro cliente, proprio con la versione 1.0 di Lightswitch. Inutile dire che lo sviluppo è stato estremamente rapido, ed il deploy altrettanto. Seguire le continue richieste del cliente (compreso qualche leggero bug-fixing) è sempre un’operazione piuttosto semplice, compreso aggiornare l’applicazione sul server di produzione. Penso che Lightswitch sia lo strumento di sviluppo più RAD che abbia mai visto, dai tempi di…Access. Eppure le differenze con Access ci sono eccome, perchè in realtà l’interfaccia utente dell’applicazione web (che gira in browser in un’applicazione Silverlight) comunica con il database attraverso un servizio WCF, mettendo così in piedi – in modo totalmente automatico – un’applicazione three-tier. Ovvio che il servizio WCF è consumabile anche da app di altra natura (è un servizio esposto via http), come Windows Phone o Windows 8, e quindi…lascio immaginare a voi quali sono le piacevoli conseguenze di tutto questo.

Ma torniamo a noi.

In questi giorni ho dovuto affrontare un problema che magari potrebbe capitare anche a voi. Lo scenario è il seguente: supponiamo di aver sviluppato e messo online, un anno fa, un’applicazione Lightswitch 1.0, che il cliente ha cominciato ad usare con successo, riempiendo il database con anagrafiche, fatture, eccetera eccetera. Dopo un anno, oggi appunto, il cliente vi chiede una piccola modifica. Peccato che l’applicazione venne creata e compilata con VS2010, mentre oggi voi volete gestire il tutto con VS2012. Perchè? Per una serie di motivi, il più importante dei quali si può riassumere nella seguente frase.

In Brain-Sys crediamo fermamente che sia importante utilizzare gli strumenti di sviluppo più recenti, per non rimanere tagliati fuori, per usare sempre l’ultimo .NET Framework disponibile. Se si aspetta troppo, se si perde l’onda, se si lasciano “decantare” troppo le tecnologie, esse finiranno per diventare obsolete. Ed arriverà il momento in cui sarà troppo tardi, e magari dovremo ricreare l’applicazione da zero. Chiaramente questa filosofia si scontra con la pratica, con il web-server a disposizione, con le richieste del cliente, con vincoli e requisiti entro i quali dobbiamo stare. Ma facciamo di tutto per farcela, insomma.

Beh, insomma, come ho risolto la migrazione dell’applicazione Lightswitch 1.0 alla 2.0, senza perdere i dati del cliente, e facendo in modo che per lui sia stato tutto trasparente? Ecco una piccola scaletta.

  1. Backup dell’applicazione attuale (database SQL Server e file system)
  2. Conversione dell’applicazione Lightswitch 1.0 con Visual Studio 2012
  3. Deploy dell’applicazione sul vostro IIS locale
  4. Restore in locale del database del cliente e aggiornamento schema
  5. Test in locale dell’applicazione
  6. Messa in produzione della nuova applicazione

Dettagli punto (1)
In breve: ho un bel folder sul proprio PC con il .bak del database SQL Server corrente (pieno di dati dell’utente) e tutti i files che compongono l’applicazione (xap, dll, web.config e via dicendo). Ovviamente tutto questo è l’applicazione alla versione 1.0 di Lightswitch. Così in caso di problemi potremo tornare indietro senza troppi danni.

Dettagli punto (2)
Nulla di particolarmente complicato, in apparenza. Aprite la solution con VS2012: lui si accorgerà che l’applicazione è stata creata con una versione precedente di Lightswitch e vi proporrà la conversione. Accettate e siete a posto. Attenzione: assicuratevi di aver installato le stesse extension Lightswitch che avevate usato all’epoca, ed assicuratevi inoltre che esse siano compatibili con VS2012. Se tutto va bene, riuscirete a compilare e ad eseguire l’applicazione da Visual Studio con un semplice F5. Se questo avviene, siete già a buon punto, perchè forse è la parte più critica.

Dettagli punto (3)
Io mi sono trovato comodo così, ovvero: ho installato IIS sul mio PC locale, e da Visual Studio 2012 ho deployato l’applicazione Lightswitch in locale, quindi ad un url tipo http://localhost/mia_applicazione. Ricordo che Visual Studio deve essere avviato come Administrator. Il wizard si occuperà di chiedervi tutte le informazioni necessarie, compreso il database da utilizzare. Io ho utilizzato l’istanza di SQL Server Express locale, fornendo le connection string di un database completamente vuoto. Il wizard crea lo schema del database. Fatto questo, potete aprire un browser, navigare all’url, avviare ed usare l’applicazione Lightswitch installata localmente sul vostro PC. Chiaramente il database sottostante è completamente vuoto, perchè è stato appena creato ex-novo da Visual Studio. E’ ora di importare i dati del cliente!

Dettagli punto (4)
Ok, allora. Prendete il .bak di cui avete fatto il backup al punto (1) e restoratelo sul database che avete creato al punto (3). Attenzione, però. C’è una piccola ma grande differenza tra una tabella creata da Lightswitch 1.0 e da Lightswitch 2.0. Ogni tabella contiene un campo RowVersion di tipo timestamp. Quindi, per esempio, se nella vostra applicazione Lightswitch 1.0 avevate un’entità Person, con Surname e Name, la tabella conterrà i campi ID, Surname, Name. La stessa entità creata con Lightswitch 2.0, oltre a questi campi, ha anche RowVersion.

Quindi, facciamo mente locale. L’applicazione Lightswitch deployata sul vostro IIS è alla versione 2.0, quindi si aspetta che tutte le tabelle abbiano questo famigerato campo RowVersion. Ma il database che abbiamo appena restorato ha uno schema che fa riferimento a Lightswitch 1.0, per cui quello che dobbiamo fare è banalmente andare ad aggiungere il campo con una semplice ALTER TABLE:

ALTER TABLE [dbo].[NomeTabella]
ADD [RowVersion] [timestamp] NOT NULL
GO

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

Io ho creato uno script che fa questa semplice operazione su tutte le tabelle che compongono la mia applicazione. Ho preferito uno script perchè verrà molto, molto comodo quando sarà il momento di mettere on-line la nuova applicazione Lightswitch, perchè basterà eseguirlo per aggiornare il database.

Dettagli punto (5)

Fatto questo, siete a posto. Avete migrato l’applicazione da Lightswitch 1.0 a Lightswitch 2.0, con tutti i vantaggi del caso, e senza perdere alcun dato inserito dal nostro cliente. Provate l’applicazione in locale, fate tutte le prove possibili ed immaginabili. Tanto state usando un database locale, sul vostro PC, perciò niente danni per il cliente, no? Se siete soddisfatti, potete mettere tutto on-line davvero.

Dettagli punto (6)

Ok, come si aggiorna l’applicazione Lightswitch sul server di produzione? Come qualsiasi altra applicazione .NET, ovvero: aggiornando un po’ di files sul server, magari trasferendoli via ftp. Io di solito sto molto attento a questo. Non faccio un “seleziona tutto”, “trasferisci”. Copio le dll, il nuovo xap, etc. etc. Evito il web.config (che magari contiene qualche configurazione particolare, soprattutto le connection string). Prima di provare l’applicazione, ricordatevi il database. Eseguite lo script con le ALTER TABLE sul database di produzione, che andrà ad aggiungere il campo RowVersion su tutte le tabelle: esattamente ciò che avete fatto prima sul vostro database locale.

Un’ultima osservazione 

Ho notato una cosa strana. La nostra applicazione chiede un login, all’avvio. Con Lightswitch 1.0, la pagina Silverlight che permette il login è piuttosto spartana. C’è una casella per l’inserimento del nome-utente, una per la password ed un bottone Accedi. Basta. Niente loghi, niente immagini. Essenziale, diciamo. Una volta migrata l’applicazione in Lightswitch 2.0, questa pagina è cambiata, ed a me appariva un enorme rettangolone giallo, che proprio non ho capito da dove arrivasse. Praticamente occupava il 90% della pagina, giusto sopra le due caselle sopra citate. Alla fine ho capito. Sono andato nelle proprietà del progetto Lightswitch, sotto “General Properties”, e qui c’è una voce “Logo image”, che puntava ad un file “ResourcesBackground.png”. E guarda caso questa immagine .png era proprio un rettangolo giallo. Ho sostituito questa png con qualcosa di più gradevole (ad esempio…il logo dell’applicazione, il logo dell’azienda del cliente) et voilà: a questo punto la pagina di login non mostra più il rettangolo giallo di prima, ma la nuova immagine che abbiamo impostato.

Direi che la missione è compiuta!!

Send to Kindle
.NET World

VS2012, Web Api, Twitter e Feed RSS

Questo post può essere considerato una “seconda parte” di quest’altro mio post, di qualche giorno fa. Ho ricevuto un solo commento, dicendomi che la cosa era per “smanettoni”. Troppo complicato, insomma. Ho quindi creato una solution Visual Studio 2012, ridotta all’essenziale, che esprime tutti i concetti base spiegati l’altra volta. Gli ingredienti sono i seguenti:

  1. Visual Studio 2012
  2. ASP.NET MVC 4, specificatamente Web Api (non ci sono view, insomma, ma le action restituiscono dati puri, via http)
  3. Json.Net
  4. qualche riga di C#

La solution è scaricabile dal mio account SkyDrive.

L’unica modifica che dovete apportare è modificare il file JsonDownloader.cs, valorizzando correttamente le variabili stringa oauth_token, oauth_token_secret, oauth_consumer_key e oauth_consumer_secret. Queste quattro stringhe servono per l’autenticazione oAuth obbligatoria per le nuove API Twitter. Per ottenere le vostre credenziali dovete registrare la vostra app sul sito https://dev.twitter.com/ (l’account per il login è lo stesso del vostro utente Twitter, chiaramente). Una volta inserite le vostre credenziali, siete a posto. Eseguendo il progetto, verrà aperto il browser all’indirizzo http://localhost:5279/api/rss/GetRssFeedTwitter?id=IgorDamiani: il codice non farà nient’altro che prelevare il JSON da Twitter e restituirvi sul browser l’XML del feed RSS. Chiaramente è sufficiente passare un utente diverso come id per ottenere altri feed.

Nota bene
In base alle vostre esigenze, vorreste modificare il codice delle classi RssParser e RssItem. Queste classi sono le responsabili della conversione tra JSON e XML. Le mie esigenze non sono troppo complesse: visualizzando i tweet su device mobili (app per Windows Phone e Windows 8), mi serve solamente il testo del tweet, la data di pubblicazione, e poco altro. Il testo contiene chiaramente il messaggio, l’eventuale link contenuto, e basta. Ma – ripeto – più che sufficiente, nel mio caso. Voi magari avete altre esigenze, più o meno complesse, quindi potrà essere necessario adattarle: ma questo dipende da voi.

Send to Kindle
.NET World

Come ottenere un feed RSS con le Twitter API in versione 1.1

Da circa una decina di giorni, Twitter ha apportato grossi cambiamenti alle proprie API, cambiamenti che hanno afflitto me – come developer di app per Windows Phone e Windows 8 – e non solo me. Basta una googlata per venire a sapere che chiunque abbia sviluppato app (per OS mobile, quindi iOS ed Android, ma non solo) che accedono a Twitter sia rimasto pesantemente fregato.

Prima infatti era possibile effettuare una chiamata via http al seguente url:
http://api.twitter.com/1/statuses/user_timeline.rss?screen_name=IgorDamiani

Con questo url si otteneva un bel feed RSS dell’utente Twitter passato come parametro, in questo caso “IgorDamiani”, cioè me stesso. Il feed era quindi consumabile dalle app per visualizzare tutti i tweet di un certo utente. Questa cosa era valida fino a 10 giorni fa, appunto. Adesso dà un messaggio inequivocabile: “The Twitter REST API v1 is no longer active. Please migrate to API v1.1.”. Morale: bisogna usare le API 1.1, che sostanzialmente hanno introdotto due cambiamenti:

Bella fregatura, vero? Ovviamente la soluzione c’è, basta adeguarsi, e fortunatamente io sono partito con qualche mese di anticipo, facendo prima di tutto in modo di far puntare tutte le mie app ad un unico url, hostato sui miei server, in modo tale da diventare trasparente rispetto ai cambiamenti apportati da Twitter. Quindi, diciamo, se ho 60 app che utilizzano Twitter, non ho cablato in ciascuna app l’url di Twitter, ma un mio url, che sarà sempre valido, dal momento che sono io a gestirlo e farò di tutto per non cambiarlo mai! Quindi, supponiamo, io ho un url nel formato seguente:

http://mioserver/Dammi_Il_FeedRssTwitter?id=<TwitterUsername>

Ho rimosso il collegamento perchè comunque non sarebbe valido. Questo url è un entry-point per tutte le mie app che devono mostrare un feed Twitter. Quindi, l’app “I Love Milan” per Windows Phone chiamerà l’url usando “acmilan”, l’app “Nove Colli” chiamerà l’url con “novecolli”, mentre l’app “Piloti Virtuali Italiani” (per Windows Phone e Windows 8) chiamerà l’url usando “pvi_org”. Questo è un mio servizio, che fa da adapter tra ciò che Twitter espone con le sue API e ciò che le mie app si aspettano. Quindi: con le API 1.0 invocavo Twitter, ottenevo un RSS e lo passavo così com’era alle mie app. Cone le API 1.1 invoco Twitter con l’autenticazione, ottengo un JSON, costruisco da zero un feed RSS in formato XML e lo restituisco a chi di dovere.

Passo 1 – Come ottenere il JSON

Il primo passo è utilizzare questa classe JsonDownloader che ho scritto questa mattina (e basandomi su questo articolo su CodeProject), molto semplice, che fa la chiamata verso Twitter, in modo autenticato, che vi restituisce una string, che in pratica è il JSON da parserizzare.

Lo zip contiene un file JsonDownloader.cs, da includere nel verso progetto e modificare come necessario. L’unica accortezza – cosa che prima non era necessaria – è che dovete necessariamente registrare la vostra app su https://dev.twitter.com/, per ottenere quattro key da inserire nel codice per l’autenticazione OAuth, ovvero:

  • Consumer Key
  • Consumer Secret
  • Access Token
  • Access Token Secret

Nel .cs che scaricate gli oggetti string ci sono già, pronti all’uso, vanno solo valorizzati correttamente.

Passo 2 – Parserizzare lo JSON ed ottenere l’XML del feed RSS

Usando la libreria Json.NET, reperibile su Twitter, le cose sono semplici, ma mica tanto. Innanzitutto, immaginiamo una chiamata del genere:

string rss = RssParser.GetRss(json, id);

Da questo si evince che abbiamo una classe statica RssParser, che espone un metodo pubblicato GetRss. Il cui codice è il seguente:

public static string GetRss(string json, string screenName)
{
    try
    {
        if (!string.IsNullOrEmpty(json))
        {
            json = "{"root": " + json + "}";

            var result = JObject.Parse(json);
            var elements = (JArray)result.Children().Children().FirstOrDefault();
            var first = ((JObject)elements.FirstOrDefault()).Property("created_at").Value.ToString();
            var firstDate = RssItem.ParseDateTime(first);

            StringBuilder bld = new StringBuilder();
            string feed = GetRssHeader();
            string itemBlock = GetRssItemBlock();
            bld.AppendFormat(feed, screenName, firstDate, screenName);

            foreach (JObject elem in elements)
            {
                RssItem item = RssItem.Get(elem);

                if (item != null)
                {
                    bld.AppendFormat(itemBlock, item.Title, screenName, item.Id,
                        item.FormattedDate, item.FormattedDate,
                        screenName, item.Id);
                }
            }

            bld.Append("</feed>");

            return bld.ToString();
        }
        else
        {
            return string.Empty;
        }
    }
    catch (Exception exc)
    {
        return exc.ToString();
    }
}

Questo metodo esplora lo JSON e restituisce la string del feed RSS. Navigando sugli oggetti JObject e JArray, e nelle relative proprietà, costruisco di fatto. Ci sono due metodi GetRssHeader() e GetRssItemBlock() che non fanno altro che recuperare delle embedded resource del progetto: di fatto contegono rispettivamente lo XML di intestazione del feed XML:

<?xml version="1.0" encoding="utf-8" ?>
<feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom">
<title>Twitter / {0}</title>
<id>tag:twitter.com,2007:Status</id>
<link type="text/html" rel="alternate" href="http://twitter.com"/>
<updated>{1}</updated>
<subtitle>Twitter updates from {2}.</subtitle>

e del blocco da ripetere per ciascun tweet:

<item>
<title>{0}</title>
<content type="html">content</content>
<id>tag:twitter.com,2013:http://twitter.com/{1}/status/{2}</id>
<pubDate>{3}</pubDate>
<updated>{4}</updated>
<link type="text/html" rel="alternate" href="http://twitter.com/{5}/status/{6}" />
</item>

All’interno del ciclo foreach viene costruito un oggetto RssItem:

public class RssItem
{
    static CultureInfo culture = new CultureInfo("en-US");

    public string Id { get; set; }
    public string Title { get; set; }
    public DateTime Date { get; set; }
    public string FormattedDate { get; set; }

    public static RssItem Get(JObject obj)
    {
        RssItem result = new RssItem();
        result.Id = obj.Property("id").Value.ToString();
        result.Title = obj.Property("text").Value.ToString();
        result.Date = ParseDateTime(obj.Property("created_at").Value.ToString());
        result.FormattedDate = result.Date.ToString("dd/MM/yyyy HH.mm.ss");

        return result;
    }

    public static DateTime ParseDateTime(string value)
    {
        // Fri Jun 21 10:22:17 +0000 2013
        try
        {
            int index = value.IndexOf('+');

            if (index != -1)
            {
                // Devo rimuovere il "+0000 "
                string partToRemove = value.Substring(index, 6);
                value = value.Replace(partToRemove, string.Empty);
            }

            return DateTime.ParseExact(value, "ddd MMM dd H:mm:ss yyyy", culture, System.Globalization.DateTimeStyles.None);
        }
        catch (Exception)
        {
            return DateTime.Now;
        }
    }
}

Il metodo pubblico Get restituisce un’istanza di RssItem, valorizzata in base al JObject corrente. All’interno ci sono un po’ di operazioni di parsing, soprattutto sulle date, che andrebbero magari riviste per essere ottimizzate, ma per adesso funzionano!

Passo 3 – Fine!

E fine. A questo punto abbiamo una string che in pratica è il feed RSS da dare in pasto alle nostre applicazioni. Se avete qualche decina di app che improvvisamente avevano smesso di funzionare a causa di questa breaking change di Twitter, le vedrete riprendere vita di colpo! La cosa molto interessante che il tutto è gestito in modo centralizzato, e non sarete obbligati a rilasciare nuove versioni delle vostre app, inseguendo i cambiamenti di Twitter. Qualsiasi modifica che si renderà necessaria è centralizzata con questo codice, e per le app è del tutto trasparente.

Send to Kindle
.NET World

Inizializzare un byte[] con N elementi

Ci saranno tanti modi per ottenere un array di byte, di N elementi, tutti valorizzati con lo stesso valore. Io ho trovato questo, che utilizza Linq:

var array = Enumerable.Repeat<byte>(0xFF, 100).ToArray();

Con una sola rapida riga di codice, otteniamo un bell’array, in questo caso di 100 elementi, tutti valorizzati a 0xFF (ovvero 255 decimale). Comodo. Grazie Linq!

Send to Kindle
.NET World

Installazione di Visual Studio 2012 Update 1 offline (con pre-download)

Uno degli installer più lunghi che abbia mai visto nella mia vita è sicuramente l’Update 1 di Visual Studio 2012. Lo sto eseguendo su un PC Desktop, senza SSD, e dopo 70 minuti non ha ancora terminato. Il problema principale sembra essere il fatto che l’installer è di circa 1,1MB: i pacchetti vengono scaricati sul momento dalla Rete.

Stasera ho scoperto che non esiste l’installer in formato .ISO, ma è possibile comunque effettuare il download preventivo di tutti i pacchetti richiesti. Dopo il download è possibile mettere il tutto su chiavetta, oppure masterizzare, e procedere così in modo molto più veloce.

Come? Semplice!

L’Update 1 (scaricabile da qui) consiste in un unico file chiamato vsupdate_KB2707250.exe. E’ sufficiente lanciare questo .exe con il parametro /layout. L’installer parte in modo interattivo, e vi viene chiesta la cartella in cui effettuare il download dei pacchetti. Poi basta avere più o meno pazienza in base alla vostra velocità di download…

Tutto qua!

Send to Kindle
.NET World

Windows 8: occhio a cio’ che fate nei Background Task

Sviluppando una mia app Windows 8 mi è capitata una cosa strana riguardante i Background Task. Se volete capire cosa sono, a cosa servono e come si sviluppano i Background Task vi rimando a questi due post (in inglese) dell’amico Matteo Pagani: post 1 e post 2.

Quello che mi è accaduto è che il debugging effettuato tramite Visual Studio 2012 non è veramente la stessa cosa che accade quando invece il codice gira realmente tramite l’app deployata. Ora vi spiego.

Immaginate di sviluppare un’app che vi fa il countdown relativamente ad un certo evento. Oggi è il 14 Gennaio. Supponiamo di voler impostare un countdown per San Valentino. Il countdown appare sulla tile dell’app stessa. Quindi oggi apparirebbe una cosa tipo “mancano 30 giorni a san valentino”, domani vedreste “mancano 29 giorni a san valentino”, e così via.

In pratica, il Background Task della mia app, che gira ogni 15 minuti, non fa altro che aggiornare la tile riportando il tempo rimanente. Le informazioni sull’evento sono banalmente scritte in un file .txt, che viene creato nel momento in cui scegliete l’evento. Quindi, per riassumere, ecco il codice contenuto nel metodo Run del Background Task.

public async void Run(IBackgroundTaskInstance taskInstance)
{
    BackgroundTaskDeferral deferral = taskInstance.GetDeferral();

    try
    {
        var container = Windows.Storage.ApplicationData.Current.LocalFolder;
        var file = await container.GetFileAsync("File.txt");
        var lines = await Windows.Storage.FileIO.ReadLinesAsync(file);
        var header = lines[0];
        var time = DateTime.Parse(lines[1]);

        if (time > DateTime.Now)
        {
            var ts = time.Subtract(DateTime.Now);
            string content = ts.TimeSpanDescription(" all'evento scelto. Non mancare!");
            TileHelper.UpdateTileWidePeekImage01("Assets/WideLogo.reminder.png", header, content);
        }
        else
        {
            TileHelper.UpdateTileWideImage("Assets/WideLogo.scale-100.png");
        }
    }
    catch (Exception)
    {

    }

    deferral.Complete();
}

 

Questo è il codice corretto, che gira senza problemi, per cui sa volete prendere ispirazione, fatelo pure. Occhio però a come usate la keyword await, necessaria per eseguire i metodi asincroni. Stupidamente, io in una prima versione del codice non la usavo, ed usavo invece il metodo GetResults(). Per spiegarmi meglio, ecco il pezzetto di codice incriminato:

var lines = Windows.Storage.FileIO.ReadLinesAsync(file).GetResults();

Ripeto il concetto: invece di usare await, ho chiamato GetResults(), convinto – chissà perchè – che facessero la stessa cosa. Purtroppo questa cosa è stata ereditata da un pezzetto di codice scritto mesi fa, quando avevo ancora a che fare con le versioni beta di Windows 8 e Visual Studio 2012 11. La cosa bella è proprio questa: questo codice qui sopra quando eseguito da Visual Studio gira senza problemi (dentro l’oggetto lines avete la List<string> delle righe contenute nel file di testo appena letto), mentre quando gira “in produzione” si schianta. Ci ho litigato per un weekend prima di raggiungere la soluzione, proprio perchè dovevo aspettare realmente 15 minuti prima di verificare il comportamento.

Anche in questo caso, tutto è bene ciò che finisce bene.

Send to Kindle
.NET World

App per lo Windows Store che fanno uso delle Bing Map

Sono incappato in un problema realizzando un’app Windows 8 per lo Windows Store. L’app è Gps Coordinate Converter, e ad oggi è regolarmente pubblicata. In pratica accadeva che sui sistemi Windows 8 x86 e x64 (in pratica i classici PC desktop, notebook ed ultrabook) girava senza presentare problemi, mentre sui device Windows RT (con architettura ARM) l’app si schiantava all’avvio.

La cosa è allo stesso tempo chiara ma insidiosa.

Dunque: innanzitutto, quando in un’app per lo Windows Store aggiungiamo nelle reference il componente Bing Map, siamo costretti ad impostare nelle proprietà del progetto stesso un’architettura: o x86, o x64 oppure ARM. Non possiamo impostare Any CPU, dal momento che il progetto a questo punto non compila proprio. Io evidentemente a suo tempo selezionai x64: in questo modo compilavo e potevo tranquillamente far girare l’app sul mio notebook.

Quando poi arriva il momento di produrre il package da uploadare sullo Store, bisogna nuovamente selezionare l’architettura del package stesso. Questa cosa può magari sfuggirvi come è sfuggita a me, perchè siete convinti che il package viene prodotto in base a ciò che viene impostato nelle proprietà del progetto, ma non è così. Perciò ricordatevi che a seconda di cosa selezionate in questo momento, l’app potrà essere trovata sullo Store dai diversi device Windows. Mi spiego meglio. Supponiamo di aver fatto la build per x64, e poi di produrre il package selezionando Any CPU. Se approvata, l’app potrà essere trovata anche da tablet Windows RT (Asus Vivo RT o Surface RT, per intenderci): il risultato è che l’app verrà scaricata ed installata, ma si schianta quasi immediatamente…il tempo di vedere lo splash screen. Quindi bisogna stare attenti: se nelle proprietà del progetto mettete x64, dovete poi produrre il package per x64. Se nelle proprietà mettete ARM, dovete produrre il package per ARM.

Come gira il Windows App Cert Kit ?
Ok, passiamo oltre. Come ben sapete, prima di uploadare un’app sullo Store dovete farla validare dal WACK, che vi trova eventuali problemi prima di passare dalla trafila della certificazione. Ovviamente, il WACK è in grado di mettere sotto torchio la vostra app solo quando state producendo il package corrispondente all’architettura del vostro pc che state usando per sviluppare. Morale: quando compilate l’app e producete il package per x64, il WACK sarà in grado di testare l’app, altrimenti no. Nel primo caso, una volta terminata la creazione del package, vi verrà chiesto se volete far girare il WACK. Nel secondo caso, invece, vi verrà solamente fornito il link alla cartella nel quale è contenuto il package.

Upload dei diversi package differenziati per architettura del processore
Ok, supponiamo di aver prodotto due package differenti per la stessa app: un package è specifico per x64, l’altro package per ARM. Come si fanno ad uploadare sullo Store? E’ molto semplice: andate nel dashboard del vostro Windows Store Dev Center, create l’app (o semplicemente una nuova release come ho dovuto fare io per risolvere il mio problema) e quando dovete uploadare i package (files con estensione .appxupload) semplicemente fate l’upload di tutti i package per le diverse piattaforme. Direi nulla di più semplice.

Send to Kindle
.NET World

Creare uno UserControl per Windows 8 app e distribuirlo

Nei giorni scorsi mi sono scontrato con il problema indicato dal titolo del post. La procedura non è poi così diversa da quella a cui ero già abituato:

  • Creare un progetto di tipo Class Library (Windows Store apps)
  • Aggiungere un “New Item” al progetto e selezionare “User Control”
  • Sviluppare il controllo, scrivendo XAML, codice, code-behind, etc. etc.: tutto ciò che volete

Il bello arriva quando volete distribuire il vostro controllo. Normalmente, infatti, compilereste il progetto di cui sopra e dareste in giro l’assembly che avete ottenuto. Quindi, se avete creato un progetto chiamato “CheBelloIlMioControllo”, quando compilate ottenete un assembly chiamato “CheBelloIlMioControllo.dll”.

Non è sufficiente. La sola dll non è sufficiente. Dovete distribuire anche lo XAML relativo ai vostri controlli, e lo dovete fare in un modo piuttosto particolare.

Rispetto alla location in cui si trova l’assembly, dovete:

  • Creare un folder chiamato esattamente come la dll (nel nostro esempio “CheBelloIlMioControllo”)
  • Nel folder di cui sopra dovete copiare i files XAML relativi al controllo

Se il controllo nel vostro progetto è stato creato all’interno di un folder, la struttura di folder diventa: NomeAssembly/NomeFolder/NomeFileXaml.

Ultima cosa assolutamente importante: dovete distribuire anche il file con estensione .PRI, che ha lo stesso nome del nostro assembly.

Ecco un piccolo esempio:

L’assembly si chiama VivendoByteToolkit. I controlli sono stati creati dentro il folder Controls, che quindi contiene i tre files XAML relativi ai tre controlli: CurrencyPicker.xaml, DatePicker.xaml e NumberPicker.xaml.

All’interno del folder VivendoByteToolkit ho inserito il file VivendoByteToolkit.dll e VivendoByteToolkit.pri.

Direi che è tutto.

Send to Kindle
.NET World

WinRT: catturare una foto e salvarla nel roaming folder

Con qualche riga di C# è possibile utilizzare la webcam o la fotocamera del nostro PC/tablet/ultrabook e salvarla all’interno della cartella roaming, che viene automaticamente sincronizzata tra tutti i vostri device Windows 8.

Il codice è piuttosto semplice.

StorageFolder folder =
     Windows.Storage.ApplicationData.Current.RoamingFolder;
CameraCaptureUI dialog = new CameraCaptureUI();

Qui sopra ho istanziato due oggetti che ci serviranno nel codice.

private async void Button_Click_1(
   object sender, Windows.UI.Xaml.RoutedEventArgs e)
{
    var file = await dialog.
      CaptureFileAsync(CameraCaptureUIMode.Photo);

    if (file != null)
    {
        string filename = string.Concat
          (Guid.NewGuid().ToString(), file.FileType);
        await file.MoveAsync(folder, filename);
    }
}

La prima cosa che faccio è invocare il metodo CaptureFileAsync. Questo metodo avvia la fotocamera del device, e vi permette di catturare una foto od un video. Se concludete l’operazione con successo (ovvero: se non annullate l’operazione), il vostro file media viene salvato in una cartella temporanea che – stando a ciò che ho letto in giro sul Internet – può venir ripulita dal sistema.

La prima cosa che faccio quindi è spostare il file nella cartella roaming, rinominando il file, dandogli un nome univoco – nel mio caso genero un nuovo Guid, voi potete applicare qualsiasi logica vi venga in mente.

Questo approccio ha diversi vantaggi:

  • salvandola nel roaming folder, le vostro foto/video vengono sincronizzate tra tutti i vostri device Windows 8 (ovviamente se fate login con il vostro Microsoft Account)
  • Se avete MediaElement o Image nel codice XAML, potete far riferimento alle immagini salvate nel roaming folder tramite l’url “ms-appdata:///roaming/nomefile”. Facile e veloce, senza troppi fronzoli

Detto questo, ricordatevi solamente nelle Capabilities della vostra app per abilitare la webcam.

Send to Kindle
.NET World

SwipeCommandHelper, una piccola solution di esempio

Ho messo a disposizione questa piccola solution, da poter scaricare liberamente, per provare in due secondi le funzionalità della SwipeCommandHelper che mi sono creato.

Chiaramente dovete avere Windows 8, Visual Studio 2012 e – volendo – un bel monitor touch (ma non è indispensabile).

L’esempio è chiaramente molto semplice. Il viewmodel espone un’unica proprietà Number, un numero intero, che viene visualizzata sulla UI. Facendo le gesture sulla Grid (che è la parte evidenziata dal colore beige) eseguite i command associati in base alla gesture stessa:

  • Verso l’alto, incrementate il valore di 1
  • Verso il basso, decrementate il valore di 1
  • Verso sinistra, dividete il valore per 2
  • Verso destra, moltiplicate il valore per 2

L’esempio è chiaramente stupido e banale, ma il succo del discorso non è certamente questo. Il punto centrale è poter assegnare dei command in base alla gesture: la complessità dei command dipende chiaramente dal vostro viewmodel. Questo è solo un sample. E – lo ripeto – posso agganciare la gestione dello swipe a qualsiasi FrameworkElement, che sia una Grid, un Button, un’Image, qualsiasi controllo, insomma.

Una cosa importante che voglio aggiungere è che lo swipe funziona anche con il mouse, quindi non è indispensabile avere un display touch per poterlo provare ed usare. Basta trascinare il puntatore del mouse verso una qualsiasi delle quattro direzioni, e secondo WinRT avviene comunque una manipulation.

Send to Kindle