L1040139

Ma questa non è una di quelle... il giorno dello scorso settembre, in cui mia moglie mi convinse a iscrivermi ad un corso di ballo, non avrei potuto essere lontano meno di 1000 anni luce dall'idea di calcare un palco per qualcosa di diverso da una presentazione con power point. Invece ieri sera, in compagnia di mia figlia Gaia ho affrontato un pubblico di circa 400 persone assieme ad un gruppo di amici che ha condiviso con noi il lavoro di questi ultimi mesi per scatenarci nei pochi minuti più emozionanti della nostra vita.

Si tratta probabilmente della cosa più folle, e per qualcuno senza senso, che io abbia mai fatto ma, vi sembrerà impossibile, la rifarei domani stesso. La capacità di unire le persone, il lavorare con mia figlia ad un allenamento comune, il supporto di mia moglie che purtroppo ha dovuto rinunciare per un problema alla spalla, è un qualcosa di impagabile che consiglio a tutti. Da ieri questa stranezza entra a tutto diritto nella hit parade delle 10 cose migliori della mia vita... Se volete gustare i momenti di questo saggio andate a vedere qui:

https://www.facebook.com/groups/rhpositivosalsa/

Un grazie immenso alla pazienza di Maria Rodriguez e alla forza di suo fratello Alay, a mia figlia Gaia, a mia moglie Daniela... e a tutto il gruppo dell'Intermedio Salsa!


Nel precedente articolo abbiamo visto rapidamante l'espressività che ci è consentita da Typescript nella dichiarazione di nostri tipi ed interfacce. Abbiamo anche evidenziato che il compilatore applica lo structured typing consentendoci di lavorare minimizzando le dichiarazioni, proprio perchè esso è in grado di identificare ricorrenze nella struttura dei tipi e verificare che siano soddisfatte. E' chiaro tuttavia che conoscere bene la semantica del linguaggio ci permette di sfruttarene al meglio l'espressività e adottare una migliore tecnica object oriented. L'obbiettivo di questo articolo è di approfondire l'utilizzo dei tipi, a partire dai semplici parametri fino alla definizione di classi e interfacce e nella loro ereditarietà.

I tipi e il loro utilizzo

Il caso più semplice e ricorrente nelle dichiarazioni è rappresentato da variabili e parametri di un metodo e da qui partiremo analizzando le peculiarità del linguaggi. Typescript ammette pochi e semplici tipi di base:

      1. number: numero reale. esso è trattato sempre come se si trattasse di un "double"

      2. string: stringa alfanumerica

      3. bool: valore booleano (true o false)

      4. any: è l'equivalente di una dichiarazione di tipo "variant" in quanto annulla il controllo del compilatore sui membri. Su un membro "any" può essere invocato qualunque metodo ma è onere del programmatore assicurarsi che esso esista.

      5. function: così come avviene per javascript, il compilatore ammette anche la dichiarazione di metodi che ammettano una funzione, consentendo ad esempio l'uso di callback.

    Tralasciano di tipi ovvi quali number, string e bool che dovrebbero essere di uso comune a chiunque e che obbiettivamente non presentano sorprese, vale la pena approfondire l'utilizzo di any e delle dichiarazioni di funzione:

       1: var theWindow : any = <any>window;
       2: theWindow.execute();

    La precedente dichiarazione rende la variabile myObject generica a tal punto che è possibile chiamare su di essa un metodo di cui typescript non conosce l'esistenza. Il caso illustrato è abbastanza comune quando in una pagina convive il codice javascript di una libreria di terze parti e il nostro typescript. Se una ipotetica libreria avesse dichiarato una funzione nel documento, Typescript non potrebbe conoscerla e di conseguenza il compilatore si interromperà con un errore. Ecco quindi che si effettua il cast di "window" ad "any" (il cast si indica con le parentesi angolari <any>) e a questo punto è possibile chiamare la funzione senza che il compilatore si impunti.

    Un altro caso particolare sono le variabili che ammettono come valore una funzione:

       1: var callback : (number) => string;
       2:  
       3: callback = function(n) 
       4: { 
       5:     return "The answer is " + n; 
       6: };
       7:  
       8: var result = callback(42);

    La variabile callback in questione viene dichiarata con una sintassi che mima quella delle lambda expression. La sintassi "(int) => string" identifica una funzione che ha un parametro intero e un valore di ritorno di tipo stringa.

    Inutile dire che è ammissibile avere funzioni senza parametri

    var callback : () => string

    con un valore di ritorno void

    var callback : (mynum: number) => void

    oppure con parametri multipli

    var callback : (mynum: number, mystring: string, mybool: bool) => string

    Interessante comunque notare che il compilatore non richiede che la funzione passata abbia esplicitato il tipo dei parametri ma, per mezzo dell'inferenza, applica automaticamente i tipi attesi. E' comunque sempre ammesso esplicitarli. Per passare una funzione alla variabile callback è possibile operare come nell'esempio, oppure utilizzare la sintassi lambda-expression come segue:

       1: var callback : (number) => string;
       2:  
       3: callback = (n) => { return "The answer is " + n };
       4:  
       5: var result = callback(42);

    Fin'ora per semplicità abbiamo visto le dichiarazioni applicate alle variabile, ma i medesimi tipi possono essere utilizzati anche per dichiare i parametri di un metodo piuttosto che le proprietà di una interfaccia o di una classe. Vediamo alcuni esempi:

       1: // metodo
       2:  
       3: function getRemoteData(callback: (result) => void) : void
       4: {
       5:     // download here
       6: }
       7:  
       8: // interfaccia
       9:  
      10: interface IHandler
      11: {
      12:     value: number;
      13:     callback : (result) => void;
      14: }
      15:  
      16: // costruttore di classe
      17:  
      18: class MyHandler implements IHandler
      19: {
      20:     value: number;
      21:  
      22:     constructor(public callback: (result) => void)
      23:     {}
      24: }

    In ordine di apparizione, nel primo esempio viene utilizzato un parametro denominato "callback" che è richiesto sia una funzione che accetta un parametro "result" ("any" visto che è omessa la dichiarazione di tipo) e non ritorna alcun valore. Nel secondo esempio invece abbiamo la definizione di una interfaccia che accetta una proprietà numerica e una seconda proprietà "callback" che richiede una function. Infine nel terzo esempio di da implementazione alla precedente interfaccia con una classe. In questo caso il metodo callback verrà fornito nel costruttore e la keyword public sul parametro da automaticamente implementazione alla proprietà pubblica (e questo basta per soddisfare l'interfaccia).

    Parametri opzionali

    Un problema ricorrente nella definizione di metodi sono i parametri opzionali. E' tipico, soprattuto di Javascript, l'avere funzioni i cui parametri non forniti sono automaticamente valorizzati a "null" e quindi con un semplice controllo è possibile simulare l'overloading che esiste nei linguaggi di più alto livello. In Typescript l'overloading dei metodi non esiste, se non nelle dichiarazioni delle interfacce, ma vige invece la possibilità di definire opzionali alcuni o tutti i parametri. Partendo da questa ultima abbiamo:

       1: function addItem(name: string, value?: number): void
       2: {
       3:     if (value == null)
       4:         value = 0;
       5: }

    L'indicazione di un "?" dopo il nome del parametro lo rende opzionale. E' chiaro che a questo punto abbiamo l'onere di verificare che esso sia valorizzato per evitare errori. Nell'esempio il parametro "value" viene valorizzato con un valore di default nel caso non sia stato specificato.

    La cosa interessante è che possiamo fare uso delle interfacce per simulare l'overload del metodo, fornendo una descrizione nell'intellisense che è di grande aiuto per lo sviluppatore. Prima di tutto dichiariamo una classe con il precedente metodo:

       1: class List
       2:     implements IList
       3: {
       4:     addItem(name: string, value?: number): void
       5:     {
       6:         if (value == null)
       7:             value = 0;
       8:     }
       9: }

    A questo punto, nell'interfaccia IList possiamo dare la definizione di due metodi con il medesimo nome. Attenzione che questa operazione nella classe darà adito ad un errore di compilazione mentre è perfettamente ammessa nell'interfaccia:

       1: interface IList
       2: {
       3:     addItem(name: string): void;
       4:     addItem(name: string, value: number): void;
       5: }

    In seguito a questa dichiarazione potremmo sfruttare l'interfaccia e l'intellisense di Visual Studio 2012 ci fornirà una descrizione del tutto simile a quella cui siamo abituati con C#:image

     

     

     

    Conclusione

    Il ridotto numero di tipi disponibile in Typescript non deve trarre in inganno. Così come in Javascript siamo in grado di trattare qualunque tipo abbastanza semplicemente, tanto più in Typescript saremo in grado di gestire agilmente qualunque informazione, con il supporto di una libreria di classi che sopperisce alla ristrettezza di tipi primitivi. E' il caso ad esempio del tipo "Date" che, come accade in Javascript, non è nativo del linguggio. Nella libreria automaticamente linkata dal compilatore troviamo le definizioni del tipo in termini di interfaccia e possiamo gestire correttamente il tipo in questione.


    Pur se lo static type checking è un elemento importante nell'utilizzo di Typescript, tanto da essere già una ragione più che valide nella sua adozione, è chiaro che si può fare di più nella semplificazione del codice Javascript e nella sua organizzazione. Nel corso degli anni si sono consolidate alcune pratiche comuni nella stesura di Javascript, per venire incontro alla carenza dei concetti di base dell'object orientation che sono particolarmente labili e limitati. Tra essi si possono annoverare alcune naming convention - ad esempio prependere un underscore ad una variabile la identifica come privata - e dei veri e propri pattern quali le closure. Tutto ciò in effetti è più che altro una notazione stilistica che una vera e propria caratteristica del linguaggio e spesso e volentieri tali pratiche tendono a renderlo di difficile comprensione e manutenzione. Typescript ha tra i suoi costrutti alcuni che hanno proprio lo scopo di semplificare nettamente il codice mascherando la vera e propria complessità che origina dalla sua compilazione.

    Interfacce e classi

    Nel precedente articolo abbiamo visto che grazie allo structured typing, Typescript è in grado di riconoscere i tipi semplicemente analizzando la corrispondenza delle proprietà. L'esempio seguente riassume in breve la questione:

       1: function getArea(s: { width: number; height: number; }): number
       2: {
       3:     return s.width * s.height / 2;
       4: }
       5:  
       6: var area = getArea({ width: 20, height: 30 });
       7: console.log(area.toString());

    E' del tutto chiaro che questo tipo di notazione, pur se tutelata dal compilatore, è eccessivamente prolissa e a lungo andare puà essere oggetto di errori e incomprensioni. Per questa ragione Typescript ammette innanzitutto la creazione di interfacce, che altro non sono che la definizione del contratto di un tipo, cui il valore deve conformarsi. Un concetto più che normale per chi mastica programmazione ad oggetti. Vediamo un esempio:

       1: interface Shape
       2: {
       3:     width: number;
       4:     height: number;
       5: }
       6:  
       7: function calculateArea(s: Shape): number
       8: {
       9:     return s.width * s.height  / 2;
      10: }
      11:  
      12: var area = calculateArea({ width: 20, height: 30 });
      13: console.log(area.toString());

    Nelle prime righe dello snippet è visibile la dichiarazione di una interfaccia "Shape". Essa riporta le proprietà "width" e "height" e viene usata come parametro della funzione calculateArea, al posto della precedente notazione estesa. L'argomento passato alla calculateArea è rimasto invariato, ma se provate a modificarne i nomi vi renderete contro che lo structured typing continua a funzionare come prima, validando il parametro contro la definizione dell'intefaccia. Le interfacce ammettono anche metodi e proprietà opzionali (usando il ?). Ecco un esempio:

       1: interface Shape
       2: {
       3:     width: number;
       4:     height: number;
       5:     color?: string;
       6:     getArea(): number;
       7: }
       8:  
       9: function calculateArea(s: Shape): number
      10: {
      11:     return s.getArea();
      12: }
      13:  
      14: var area = calculateArea(
      15:     {
      16:         width: 20,
      17:         height: 30,
      18:         getArea: function() { return this.width * this.height / 2; }
      19:     });
      20:  
      21: console.log(area.toString());

    L'esempio in questione estremizza la definizione dell'interfaccia Shape richiedendo una proprietà opzionale "color" (che poi non viene passata più sotto) e un metodo che effettua il calcolo dell'area. In tal modo la funzione calculateArea non deve fare altro che chiamare il metodo getArea dell'interfaccia per ottenere il valore calcolato. Si tratta di un primo passo verso una conversione object oriented dell'esempio. A questo punto potremmo voler implementare l'interfaccia Shape in diverse figure e fornire una diversa formula per il calcolo. Lo possiamo fare grazie alla presenza delle classi. Vediamo come:

       1: interface Shape
       2: {
       3:     width: number;
       4:     height: number;
       5:     getArea(): number;
       6: }
       7:  
       8: class Triangle implements Shape
       9: {
      10:     constructor(
      11:         public width: number,
      12:         public height: number) { }
      13:  
      14:     getArea(): number {
      15:         return this.width * this.height / 2;
      16:     }
      17: }
      18:  
      19: class Square implements Shape
      20: {
      21:     constructor(
      22:         public width: number,
      23:         public height: number) { }
      24:  
      25:     getArea(): number {
      26:         return this.width * this.height;
      27:     }
      28: }
      29:  
      30: function calculateArea(s: Shape): void
      31: {
      32:     var area = s.getArea();
      33:     console.log(area.toString());
      34: }
      35:  
      36: calculateArea(
      37:     new Square(20, 30));
      38: calculateArea(
      39:     new Triangle(20, 30));

    Grazie alla keyword "class" è possibile creare delle vere e proprie classi che, a differenza di quello che succede per le interfacce, che spariscono nel codice Javascript, generano una struttura che chi è avvezzo a Javascript riconoscerà sicuramente.

       1: var Triangle = (function () {
       2:     function Triangle(width, height) {
       3:         this.width = width;
       4:         this.height = height;
       5:     }
       6:     Triangle.prototype.getArea = function () {
       7:         return this.width * this.height / 2;
       8:     };
       9:     return Triangle;
      10: })();

    Nel precedente snippet abbiamo anche la dimostrazione che una classe può implementare una specifica interfaccia, per mezzo della keyword "implements" e così facendo il compilatore verificherà a tempo di compilazione che la classe supporti i metodi e le proprietà da essa richieste. Siamo a questo punto arrivati ad una programmazione ad oggetti del tutto raffinata, che poco ha a che vedere con la complessità cui si è abituati con Javascript, totalmente mascherata dal compilatore Typescript.

    Oltre all'implementazione di interfacce è del tutto possibile estendere classi esistenti. Per fare questo dovremo utilizzare la keywork "extends" al posto di "implements". Vediamo come usare l'ereditarietà per create una classe "Cube" derivando da "Square":

       1: class Cube
       2:     extends Square
       3: {
       4:     constructor(
       5:         width: number,
       6:         height: number,
       7:         public depth: number)
       8:     {
       9:         super(width, height);
      10:     }
      11:  
      12:     getArea(): number
      13:     {
      14:         return (super.getArea() * 2) +
      15:                (this.depth * this.width * 2) +
      16:                (this.depth * this.height * 2);
      17:     }
      18: }
    In questo esempio vediamo che al costruttore della classe viene aggiunto un ulteriore parametro "depth" che identifica l'altezza del parallelepipedo. Avendo modiificato la firma il compilatore richiede che la prima chiamata nel body del costruttore sia la funzione "super" che ha lo scopo di chiamare il costruttore della classe base. Questa deve essere specificata come faremmo usando "base" in C#. La medesima keyword può essere usata anche per chiamare i metodi della classe base. Ad esempio il metodo getArea richiama l'omonimo della classe base per poi sfruttare il risultato integrando la rimanente parte dell'area.

    Usare i moduli

    Una volta che abbiamo classi e interfacce i benefici che ne derivano sono numerosi, soprattutto in termini di organizzazione logica del codice e di manutenzione. Il passo successivo è di organizzare il codice in moduli - i programmatori C# li conosceranno meglio come "namespace" - per riuscire a creare vere e proprie librerie i cui nomi siano univoci. Anche in questo Typescript ci aiuta; grazie alla keyword "module" infatti sarà possibile creare dei veri e propri namespace:

       1: module Shapes
       2: {
       3:     export class Square implements Shape
       4:     {
       5:         constructor(
       6:             public width: number,
       7:             public height: number) { }
       8:  
       9:         getArea(): number
      10:         {
      11:             return this.width * this.height;
      12:         }
      13:     }
      14: }

    Interessante notare che la classe definita nel modulo "Shapes" è stata decorata con "export". Infatti, una volta che abbiamo messo una classe (o qualunque altro costrutto) in un modulo possiamo renderlo visibile o invisibile all'esterno beneficiando di un incapsulamento che in termini di librerie riutilizzabili è prezioso.

    Come si è abituati a fare con i namespace in C#, anche in Typescript i moduli possono essere annidati in modo del tutto analogo, creandoli effettivamente l'uno nell'altro:

       1: module Shapes
       2: {
       3:     export class Square implements Shape
       4:     {
       5:         constructor(
       6:             public width: number,
       7:             public height: number) { }
       8:  
       9:         getArea(): number
      10:         {
      11:             return this.width * this.height;
      12:         }
      13:     }
      14:  
      15:     export module ThreeD
      16:     {
      17:         export class Cube extends Square
      18:         {
      19:             // ... omissis
      20:         }
      21:     }
      22: }

    Oppure usando una notazione puntata

       1: module Shapes.ThreeD
       2: {
       3:     export class Cube extends Square
       4:     {
       5:         // ... omissis
       6:     }
       7: }

    Ciascuna delle due notazioni può essere tranquillamente utilizzata assieme all'altra creando vere e proprie composizioni in cui i moduli si combinano. Una volta che i moduli sono stati creati sarà possibile raggiungere i tipi definiti nei moduli specificando l'intero namespace:

       1: var square: Shapes.Square;
       2: var cube: Shapes.ThreeD.Cube;

    Data la notevole lunghezza e ridondanza che i nomi completi di namespace possono raggiungere è del tutto possibile creare degli shortcut che siano in grado di semplificare la scrittura del codice:

       1: import sh = Shapes;
       2: import sh3d = Shapes.ThreeD;
       3:  
       4: var square: sh.Square;
       5: var cube: sh3d.Cube;

    Come a casa propria

    Sono convinto che i programmatori C#, ma in generale qualunque sviluppatore sia avvezzo all'uso di un linguaggio evoluto basato sui paradigmi della programmazione ad oggetti, leggendo il codice Typescript si senta bene come a casa propria. In effetti se si da uno sguardo veloce al codice generato dal compilatore si comprende come Typescript sia in grado di fornire strumenti che la programmazione Javascript può dare solo a caro prezzo. Per intenderci vediamo un esempio di cosa sia possibile fare:

       1: module Shapes
       2: {
       3:     export interface Shape
       4:     {
       5:         width: number;
       6:         height: number;
       7:         getArea(): number;
       8:     }
       9:  
      10:     export enum ShapeType
      11:     {
      12:         Square,
      13:         Triangle
      14:     }
      15:  
      16:     export class ShapeFactory
      17:     {
      18:         static create(type: ShapeType, width: number, height: number): Shape
      19:         {
      20:             switch (type)
      21:             {
      22:                 case ShapeType.Square:
      23:                     return new Square(width, height);
      24:                 case ShapeType.Triangle:
      25:                     return new Triangle(width, height);
      26:             }
      27:  
      28:             return null;
      29:         }
      30:     }
      31:  
      32:     class Triangle implements Shape
      33:     {
      34:         constructor(
      35:             public width: number,
      36:             public height: number) { }
      37:  
      38:         getArea(): number
      39:         {
      40:             return this.width * this.height / 2;
      41:         }
      42:     }
      43:  
      44:     class Square implements Shape
      45:     {
      46:         constructor(
      47:             public width: number,
      48:             public height: number) { }
      49:  
      50:         getArea(): number
      51:         {
      52:             return this.width * this.height;
      53:         }
      54:     }
      55: }
      56:  
      57: import sh = Shapes;
      58: var sq = sh.ShapeFactory.create(sh.ShapeType.Square, 20, 30);
      59: console.log(sq.getArea());
    Credo che la combinazione di moduli, classi, interfacce ed enumeratori di questo esempio, assieme con l'applicazione di metodi statici e dell'incapsulamento nei moduli sia molto significativa di come si possa scrivere con proprietà un codice molto efficace.

    Come indica il nome "TypeScript", una delle principali ragioni dell'introduzione di questo linguaggio, è la necessità di risolvere uno dei maggiori problemi di Javascript, ovvero la mancanza si un sistema di tipi verificato staticamente. Dire che Javascript non sia tipizzato è un errore, infatti nella realtà esso dispone di un certo numero di tipi, i quali però vengono risolti a tempo di esecuzione e non a tempo di compilazione. Questo può portare a errori comuni che si possono verificare come vere e proprie eccezioni oppure come più subdoli errori logici. Vediamo il seguente esempio:

       1: var a = 10;
       2: var b = '32';
       3: console.log(a + b);

    Il risultato di questo snippet Javascript è la implicita concatenazione di stringhe che deriva dalla conversione del valore numerico 10 in stringa per ottenere il risultato finale "1032" anzichè, come ci si potrebbe attendere 42. In un linguaggio che ha il controllo dei tipi a tempo di compilazione, questo tipo di operazione non sarebbe mai arrivata all'esecuzione e il problema non si sarebbe posto. L'intervento del compilatore sarebbe intervenuto indicando che è impossibile applicare l'operatore '+' tra numerici e stringhe.

    Pur prendendo origine da codice Javascript e producendo come output sempre Javascript, Typescript ha l'intento di aggiungere questa verifica statica, a tempo di compilazione, che prevenga gli errori suddetti consentendo così la realizzazione di applicazione real-world in cui sarebbe inamissibile/costoso il rischio di arrivare con un errore in produzione. Il supporto al type-checking in Typescript inizia fin da subito grazie alla capacità di inferire i tipi dall'utilizzo e applicare il risultato di questa inferenza come vere e proprie dichiarazioni di tipo. Vediamo uno snippet di esempio:

       1: function getArea()
       2: {
       3:     var width = 20;
       4:     var height = '30';
       5:     var area = width * height / 2;
       6:     alert(area);
       7: }

    Il risultato della compilazione di questo codice - che ad una attenta analisi contiene due palesi errori che Javascript rivelerebbe solo a runtime - come facilmente intuibile è il seguente:

    (5,15): Operator '*' cannot be applied to types 'number' and 'string'
    (6,4): Supplied parameters do not match any signature of call target

    In buona sostanza avviene proprio che il compilatore inferisce il tipo delle variabili width, height e area e sulla base del risultato determina che l'operazione di moltiplicazione "width * height" e il passaggio di un valore numerico ad "alert" sono errati. Possiamo ovviamente correggere rapidamente l'errore e beneficiare dell'aiuto offerto dal compilatore ma in Typescript possiamo anche tutelarci da ulteriori errori esprimendo esplicitamente il tipo delle variabili come segue:

       1: function getArea()
       2: {
       3:     var width: number = 20;
       4:     var height: number = 30;
       5:     var area: number = width * height / 2;
       6:     alert(area.toString());
       7: }

    La differenza in questo caso non è immediatamente apprezzabile se non nel fatto che, riproducendo l'errore precedente esprimendo il valore '30' come stringa, l'errore sarà evidenziato nell'esatto punto in cui si verifica:

    (4,25): Cannot convert 'string' to 'number'

    Il beneficio diventa più evidente se introduciamo dei parametri di ingresso della funzione, ai quali venga applicato il calcolo:

       1: function getArea(width, height)
       2: {
       3:     return width * height / 2;
       4: }
       5:  
       6: var area = getArea(20, '30');
       7: alert(area.toString());

    Il problema in questo caso passa inosservato anche all'inferenza in quanto i due parametri vengono interpretati di tipo "any". Quest'ultimo è il tipo che Typescript adotta come "nativo" delle variabili Javascript  e ad esso è impossibile applicare alcuna verifica. Per questo motivo l'operazione "width * height" passa il controllo perchè "any" potrebbe contenere un "number". A tutela di questa situazione esprimere il tipo dei parametri è essenziale:

       1: function getArea(width: number, height: number) : number
       2: {
       3:     return width * height / 2;
       4: }
       5:  
       6: var area = getArea(20, '30');
       7: alert(area.toString());

    "any", "number", "string" and "bool" sono i soli tipi primitivi disponibili in Typescript ma grazie ad essi il codice, come dimostra la funzione qui sopra, risulta decisamente più solido e al sicuro da sorprese.

    Tuttavia Typescript è in grado di fare molto di più applicando il concetto di "structural typing". Questo concetto è in grado, con il minimo dispendio in termini di codice, di gestire anche i tipi impliciti tipici di Javascript. Facciamo un esempio per chiarezza:

       1: function getArea(s: { width: number; height: number; }): number
       2: {
       3:     return s.width * s.height / 2;
       4: }
       5:  
       6: var area = getArea({ width: 20, height: 30 });
       7: console.log(area.toString());

    In questo esempio la dichiarazione del parametro "s" impone che esso debba avere almeno le proprietà "width" e "height". A questo parametro sarà possibile passare l'istanza di qualunque tipo che soddisfi questo requisito minimo. Nelle riga 6 ad esempio viene fornito un JSON che rispetta questo vincolo. Rimuovendo l'uno o l'altro delle proprietà il compilatore ci avviserà che il tipo non è conforme alle aspettative:image

    Inutile rimarcare l'utilità di questa caratteristica che ha un valore decisamente importante nella tutela del codice. Ricordo che, pur se in questo esempio l'intervento di Visual Studio rende più leggibile la condizione di errore, è chiaro che essa è attribuibile al compilatore perciò sarà evidenziata con un messaggio di errore anche se il codice è scritto con un editor alternativo (notepad, Vim, Emacs, SublimeText, etc...).

    Interessante notare che, nella dichiarazione del parametro possiamo rendere opzionale uno dei campi, salvo poi avere l'onere della verifica. A titolo di esempio modifichiamo il tipo di cui sopra aggiungendo la proprietà "color".

       1: function getArea(s: { width: number; height: number; color?: string; }): number
       2: {
       3:     if (typeof color !== "undefined")
       4:     {
       5:         // qui posso usare "color".
       6:     }
       7:  
       8:     return s.width * s.height / 2;
       9: }
      10:  
      11: var area = getArea({ width: 20, height: 30 });
      12: console.log(area.toString());

    La proprietà color, grazie all'utilizzo del carattere "?", è a tutti gli effetti opzionale e di conseguenza alla riga 11, una istanza che contiene solo "width" e "height" è perfettamente ammissibile. Naturalmente all'interno del metodo sarà necessario effettuare il controllo per "undefined" allo scopo di evitare errori.

    La potenza dello "structural typing" è tale che potremmo applicarla non solamente a proprietà, ma anche a funzioni e metodi. una delle caratteristiche dei metodi Javascript, è spesso di richiedere il passaggio come argomento di funzioni di callback. Mediante una opportuna dichiarazione sarà possibile verificare la firma del metodo passato come gestore del callback:

       1: function getArea(
       2:     s: { width: number; height: number; },
       3:     callback: (area: number) => void): void
       4: {
       5:     callback(
       6:         s.width * s.height / 2);
       7: }
       8:  
       9: getArea({ width: 20, height: 30 },
      10:     function (area)
      11:     {
      12:         console.log(area.toString());
      13:     });

    In questo esempio è simulato una chiamata asincrona, in cui il metodo gestore deve ricevere un valore di tipo "number". Il requisito è espresso mediante la dichiarazione con l'operatore "=>" (arrow), da non confondere con le lambda expression di C#. Passando come argomento un metodo che non rispetti il requisito, il compilatore ci avviserà puntualmente dell'anomalia:

    image

    E' del tutto evidente che i costrutti che abbiamo visto finora sono propri di Typescript. Tali dichiarazioni rispettano i dettami delle nascenti specifiche Ecmascript 6.0 ma a tutti gli effetti sono poi trasformate in un codice che sarà compatibile con Ecmascript 3.0 o 5.0 a scelta. Dato che queste ultime specifiche non supportano il controllo di tipo al suo interno questo sarà rimosso ma lavorando sempre con Typescript potremo beneficiare di un controllo "not provably safe" ma sufficiente a consentirci una sicurezza molto più vicina a quella di un linguaggio di alto livello.


    Mi è stato segnalato che talvolta il debug di typescript sembra non funzionare. ll debugger mostra i breakpoint con il classico pallino bianco anzichè con quello rosso pieno, ad indicare che non è in grado di trovare le informazioni di debug.

    Il problema è capitato a me stesso e sono arrivato a comprenderne la ragione, almeno quella relativa la mia problematica. Per fare in modo che il debug funzioni correttamente è necessrio referenziare il file "non minimizzato" nella pagina html. Infatti la mappa generata dal compilatore (il file .map) fa riferimento a questo file. Se invece, come ho fatto io referenziate il file ".min.js" Visual Studio non è in grado di trovare la corrispondenza e il debug non funziona.

    A questo punto rimane però il dubbio... dato che non esistono direttive di compilazione che si possano applicare all'HTML, come faccio a referenziare il file ".min.js" al momento del deploy della release?


    Se mi guardo indietro mi vedo, numerosi anni fa, seduto sulla panchina del binario 3 della stazione di Venezia Mestre - probabilmente in attesa del treno che mi portava al lavoro - mentre leggo avidamente di un interessante linguaggio che Netscape aveva realizzato e Microsoft aveva introdotto in Internet Explorer 3.0; tale Javascript. La lettura, del tutto tecnica e didascalica ebbe la capacità di svegliare quelle attenzioni per le questioni "Rich Internet" che tutt'oggi mi accompagnano in varie esperienze.

    Javascript, infatti, fu allora la risposta alle necessità che fin da subito permearono l'esperienza dello sviluppo di applicazioni web, in cui il gap nella user experience era talmente ampio rispetto quella della classiche applicazioni desktop da risultare indigesto ai più. Poter in qualche modo accedere alla dinamicità della pagina sul client e migliorare l'interazione con l'utente, era una necessità sentita e in qualche modo Javascript, in compagnia di DHTML, apriva un barlume di speranza.

    Paradossalmente, oggi a distanza di almeno 17 anni da allora - in termini informatici almeno un paio di ere geologiche - Javascript è assurto al linguaggio per eccellenza, non esclusivamente dedicato allo sviluppo "rich" ma ormai con ampi spazi anche server-side. Dopo essere passati per numerose esperienze, che hanno visto alti e bassi, corsi e ricorsi, parziali abbandoni e ritorni, alla fine l'unico vero linguaggio che può vantare l'aggettivo "cross-platform" è Javascript.

    Ma nonostante la longevità, anche nella sua più recente standardizzazione che va sotto il nome di EcmaScript 5.0, Javascript soffre dei problemi tipici dei linguaggi di scripting. In particolare la mancanza di tipi e la sua peculiare visione dell'object-orientation che omette concetti importanti quali l'incapsulamento e l'ereditarietà. A causa di questi problemi, nello sviluppo di applicazioni reali Javascript diventa un linguaggio ostico e, troppo spesso, pericoloso per la sua capacità di digerire qualunque cosa salvo poi scoppiare nel momento peggiore e cioè dopo il rilascio in produzione.

    Dn163601.78CFF275500F1DB4436598BF65141A6A(it-it,MSDN.10).png

    E' questa la ragione per cui molti si stanno orientando ad un nuovo tipo di strumenti, che abbia la capacità di tutelare lo sviluppatore mediante la type-safety e una programmazione object oriented vera, senza però perdere tutti gli indiscutibili vantaggi di Javascript con il cross-platform in testa a tutti. Microsoft in questo campo si sta muovendo rapidamente con la presentazione di un nuovo linguaggio denominato Typescript, giunto oggi alla versione 0.8.2.

    Pur trattandosi di una preview e omettendo ancora molti costrutti che uno sviluppatore normalmente si potrebbe aspettare, Typescript è un linguaggio sofisticato che ha la preziosa caratteristica di estendere Javascript, senza però richiedere un "interprete" nuovo nel browser, perchè il risultato della sua compilazione è Javascript. Un sorgente Javascript è a tutti gli effetti un sorgente Typescript perfettamente valido. Un sorgente Typescript genera comunque e sempre un sorgente Javascript valido. La parte del leone la fanno qui il compilatore "tsc.exe" e l'IDE di sviluppo, che anche se non necessariamente deve essere Visual Studio 2012, qualora lo si utiizzi è in grado di portare l'esperienza di sviluppo a livelli del tutto paragonabili a quelli che si hanno con linguaggi di alto livello come C#.

    Ma andiamo con ordine: le prime prove con Typescript si possono già fare online nel playground. Il compilatore Typescript infatti è scritto in Typescript - per inciso è anche open source - perciò è in grado di girare perfettamente all'interno del browser e in questa pagina è possibile scrivere, compilare e provare le prime righe di questo linguaggio, vedendone al contempo il risultato in termini di javascript prodotto. In alternative è possibile scaricare i tool per Visual Studio e avere così una esperienza integrata, garantita da alcuni template e da un editor suddiviso in due aree che mostrano assieme sorgente e compilato.

    Possiamo quindi sperimentare facilmente, e per farlo proviamo ad immettere il seguente codice nell'editor online oppure se preferite in Visual Studio 2012:

       1: function calculateHypotenuse()
       2: {
       3:    var c1 = 5;
       4:    var c2 = '2';
       5:    var hy = Math.sqrt(c1 * c1 + c2 * c2);
       6:    alert(hy);
       7: }

    Ad un occhio attento appare evidente che, purtrattandosi di codice perfettamente legale per Javascript, esso poi genererà un errore di runtime dovuto al fatto che il valore di c2 è impostato come una stringa invece che come un valore numerico, richiesto dalla funzione Math.sqrt(). Inoltre, un po' meno evidente ma anch'esso sorgente di un ulteriore errore, il valore hy ritornato è un numerico e non può essere passato direttamente alla funzione alert() che richiede una stringa. Il codice così com'è incollato nell'editor di Visual Studio ci metterà immediatamente in guardia proprio a causa dei suddetti problemi:

    Dn163601.8B3D2FD3F499553C04C1E790E9A91B60(it-it,MSDN.10).png

    Visual Studio 2012, mediante le sottolineature in rosso evidenzia il problema, pur trattandosi di codice Javascript senza alcun costrutto particolare di Typescript.

    Il compilatore Typescript infatti è in grado di inferire il tipo delle variabili dal loro utilizzo e di conseguenza segnala l'anomalia. Ovviamente, nella parte laterale, il codice Javascript non sarà generato ma sarà sostituito da un commento che riporta gli errori riscontrati.

    Piuttosto che correggere semplicemente gli errori, lavorando con typescript, però possiamo blindare il codice dichiarandone i tipi.

    Qui sotto vediamo il codice modificato e possiamo notare che a questo punto l'errore, visualizzato da Visual Studio, si è spostato nel punto, più opportuno, in cui avviene l'assegnazione. Il tooltip stesso evidenzia la causa dell'errore molto chiaramente. Poco sotto, parzialmente nascosto dal tooltip, viene usato toString() per fornire una stringa ad alert.

    Dn163601.87DF99060FE245829E025F8DB6D090ED(it-it,MSDN.10).png

    La sintassi di Typescript è piuttosto semplice e leggera rispetto a javascript, lasciando per quanto possibile inalterato il codice originario. Il proposito del team è di mantenere per quanto possibile una compatibilità con lo standard Ecmascript 6.0 in corso di definizione, così da mantenere sempre inalterato il paradigma che sostiene che un sorgente Javascript è un Typescript valido. Una volta corretto l'ultimo errore nell'esempio avremo finalmente un output Javascript come segue:

       1: function calculateHypotenuse() 
       2: {
       3:      var c1 = 5;
       4:      var c2 = 2;
       5:      var hy = Math.sqrt(c1 * c1 + c2 * c2);
       6:      alert(hy.toString());
       7: }

    Questo esempio banale, è però significativo e dà la misura di come, grazie al supporto di uno strumento di sviluppo quale il compilatore e in parte dell'IDE di Visual Studio 2012 in grado di sfruttarlo opportunamente, saremo in grado di scrivere codice di qualità che tuteli il nostro operato evitando che i normali errori si presentino nei momenti meno opportuni.

    Typescript contiene una serie di altre feature molto importanti, come la definizione di interfacce e tipi custom, che lo arricchiscono di una espressività che spesso è limitata dai costrutti molto arzigogolati di Javascript. Spesso tali feature sono del tutto sostitutive e simulano a compile time feature che Javascript non include. E' il caso ad esempio dei metodi e delle proprietà private che, pur non essendo supportate da Javascript in alcun modo, in Typescript trovano applicazione e un eccellente supporto di intellisense in Visual Studio 2012. Il codice compilato naturalmente perderà questa caratteristica ma solo dopo che essa ha perso la sua utilità.


    Signori, ci siamo. Domattina sul presto, accompagnato da Andrea "doc" Dottor e Mirco "gadget" Vanini (ok, il suo soprannome l'ho inventato sul momento ma rende l'idea), partirò alla volta di Seattle per il mio terzo MVP Global Summit. Dopo il primo nel 2008 e il successivo nel 2010, ci sono voluti ben tre anni prima di riuscire a tornarci e sinceramente non vedo l'ora. L'agenda è piena, meeting, sessioni, parties e anche qualche giorno da dedicare a fare il turista e il cicerone al drappello di Veneti al seguito.

    Al solito, vista la NDA sarà difficile io possa condividere qualcosa ma cercherò di non mancare qualche post di colore se non mi sarà permesso di parlare di tecnologia. Da parte mia voglio cogliere l'occasione per approfondire alcuni argomenti che ho trascurato da parte negli ultimi anni. Il web è sempre stato la mia passione ma non c'è dubbio che Silverlight abbia assorbito la maggior parte delle mie risorse. Quindi, a lato di Windows Store apps, XAML, WPF & Co., spero di tornare su argomenti come Javascript, Typescript e il web.

    Ma ora c'è da riposare. La partenza é prevista per le 4:00… grazie a chi vorrà seguirmi.

    tags: - categories: News

    Siamo all'ultimo giorno del 2012 e giá a prima vista molte cose son cambiate. Non fosse altro che sto scrivendo questo post, comodamente accovacciato sul divano, con nelle mani un tablet Windows 8 che un anno fa pochi avrebbero immaginato potesse esistere.

    Ma il device spettacolare che sto usando é davvero nulla se paragonato a una serie di altri cambiamenti che hanno segnato il 2012. Poco prima dell'inizio dell'anno avevo postato la mia intenzione di perdere qualche chilogrammo… ebbene ora sono giunto a 29. Mi sono fatto prendere la mano, ma ne valeva la pena dato che da 15 anni a questa parte non mi sentivo cosí bene… A chi mi chiede come ho fatto rispondo: tre volte a settimana in palestra e dieta ferrea, ma non è proprio tutto. La vera chiave è un cambiamento radicale senza compromessi e il cercare soddisfazioni in altro che non sia la forchetta. In realtà la gran parte del successo la devo all'incrollabile pazienza e perizia di mia moglie… giusto per mettere i puntini sulle "i".

    E qui entra in gioco l'altro cambiamento, che chi mi conosce bene giudica ancora piú rivoluzionario della mia dieta: il ballo. Da qualche mese mi sto impegnando nella Salsa (e fra qualche ora saró ad una festa danzante). Chi dice di saper lavorare in team non puó ragionevolmente esserne certo se non ha provato almeno una volta il ballo di coppia, e la salsa con la numerosa serie di figure complesse è, a mio parere, uno degli stili piú indicati, che richiede collaborazione, sincronia e fiducia gli uni negli altri. Sinceramente, la vita di coppia mia e di mia moglie è nettamente migliorata da quando balliamo, grazie al continuo allenamento nell'intesa che la salsa richiede.

    Quello che non sono riuscito a portare a compimento, purtroppo, è il tornare a postare regolarmente. Gli impegni di lavoro rendono davvero difficile trovare il tempo per bloggare con la dovuta continuitá. Peró non mi do per vinto e ci riproveró…

    Lascio gli altri buoni propositi che avrei voluto scrivere per il primo post del 2013. Per il momento mi fermo per iniziare una bella serata in famiglia, ma permettetemi di augurare a tutti un eccellente 2013!

    tags: - categories:

    Nel mio precedente post ho mostrato una semplice soluzione per separate entità da DbContext, ottenuta "scorporando" i template T4 che sono usualmente generati dall'EDMX. Nella soluzione proposta in pratica ci saremmo trovati nella soluzione riportata nella figura qui accanto.

    Tale soluzione, per quanto semplice da ottenere ed efficace, soffre di un problema che chiamaerei "logico". Se avete provato a manipolare un po' le entità mediante l'utilizzo del designer, dopo aver separato i t4, vi sarete resi conto che il diagramma delle entità è situato nell'assembly denominato "Data" anzichè, come ci si potrebbe aspettare, nell'assembly "Entities".

    Dico che ce lo si potrebbe aspettare perchè logicamente appare abbastanza ovvio che il diagramma delle entità sia situato nel medesimo progetto in cui sono situate le entità che ne derivano. In realtà la questione è meramente di gusto personale. In effetti la presenza delle entità generate nell'assembly "Entities" non implica che esso debba avere un riferimento a "EntityFramework.dll", infatti tali entità sono "POCO" e quindi non portano alcun legame con l'EDM, se non il fatto di esserne generate. In effetti, potremmo benissimo decidere di scriverle manualmente ed Entity Framework le inghiottirebbe senza colpo ferire.

    imageTuttavia, se questa questione vi causasse qualche problema, è del tutto possibile effettuare lo scorporamento nel modo diametralmente opposto. In tal caso sarà opportuno aggiungere il file EDMX al progetto "Entities" e in un secondo momento estrapolare il Samples.Context.tt e portarlo nell'assembly "Data". A questo punto, modificati path e referenze come spiegato nel post precedente (ma nell'assembly contrario) otterremo nuovamente una soluzione compilabile come nella figura successiva.

    Il tutto con l'indiscutibile comodità di trovarsi con il designer nello stesso progetto delle entità. Ci troveremmo però ad avere una referenza a EntityFramework.dll indesiderata. Ma tale referenza dipende solo dalla genesi del progetto. Se la rimuovete manualmente vi renderete conto che il progetto compila alla perfezione anche senza.

    A questo punto, la scelta tra le due ipotesi è del tutto personale. Lascio a voi ragionarci e magari fatemi sapere le ragioni delle vostre eventuali scelte.

    Download: Elite.Samples.Architecture.zip (2,32MB)


    Vi è mai capitato di avere la necessità di assicurare che il contenuto di un file, scaricato dal vostro server, non debba essere modificato ma allo stesso tempo debba essere leggibile dalla vostra applicazione? Mi spiego meglio: diciamo che dovete fornire un file che contiene una configurazione, la quale deve essere leggibile dall'applicazione che state configurando ma non dovrebbe essere modificabile dall'utente che maliziosamente voglia ottenere "qualcosa di più" manipolandone il contenuto. Qualcuno potrebbe pensare che la soluzione stia nel cifrare il file ma questo è solo un ostacolo per i più pigri e meno motivati, ma qualcuno potrebbe agevolmente superarlo decompilando il vostro codice e scoprendo dove avete messo la chiave da usare per decifrarla. Chi conosce il framework sa che si tratta di un'operazione tutt'altro che complessa.

    Una possibile soluzione è quella di aggiungere una firma digitale che assicuri l'applicazione che il contenuto non è cambiato rispetto a quello originario. Con "firma digitale" qui intendo un hash che rappresenti il contenuto del file e che lo accompagni. L'applicazione potrebbe rigenerare l'hash prima di usare il contenuto del file e verificare che quello nel file corrisponda a quello generato. Ora, dato che gli algoritmi di hash sono pochi e ben conosciuti, tutto questo sarebbe una mera speculazione se non esistesse quello che pare essere un miracolo della crittografia: le chiavi asimmetriche.

    Per chiave asimmetrica si intende una chiave suddivisa in due parti, dette pubblica e privata, in cui una viene usata per cifrare (quella pubblica) e solo l'altra può decifrare (quella privata). Nelle applicazioni della cifratura asimmetrica (l'SSL ad esempio) la chiave privata rimane segreta mentre quella pubblica serve per cifrare i contenuti che solo il detentore della chiave privata può decifrare. Ma questo cosa c'entra con gli hash?

    Beh, giusto oggi ho fatto qualche prova ed ho scoperto che l'implementazione dell'algoritmo asimmetrico RSA nel framework, può essere usato per effettuare una "blind signature" ovvero una firma digitale generata con una chiave privata e verificata con la chiave pubblica. Per intenderci la verifica non si limita a controllare che l'origine della firma sia la chiave privata corrispondente, ma anche che il contenuto che ha dato origine all'hash non sia cambiato... ed ecco la soluzione di cui sopra; Il codice qui sotto genera una firma digitale corrispondente alla stringa passata in input:

       1: private static string SignData(string value, out string publicKey)
       2: {
       3:     byte[] valueToSign = Encoding.UTF8.GetBytes(value);
       4:     HashAlgorithm sha1 = HashAlgorithm.Create("SHA1");
       5:     RSACryptoServiceProvider provider = new RSACryptoServiceProvider();
       6:     byte[] hash = provider.SignData(valueToSign, sha1);
       7:     publicKey = provider.ToXmlString(false);
       8:     return Convert.ToBase64String(hash);
       9: }

    In breve: la stringa viene dapprima convertita in un array di byte, poi si sceglie l'algoritmo di hashing SHA1 (MD5 non vale perché è stato recentemente violato). Poi si crea un provider RSA per la cifratura e si genera l'hash con SignData. Infine il metodo ToXmlString estrae la parte pubblica della chiave privata che viene automaticamente generata quando si crea l'istanza del provider RSA. Tale chiave ritorna come argomento di output perchè dovrà essere usata nella parte di verifica:

       1: private static bool VerifyData(string value, string hash, string publicKey)
       2: {
       3:     byte[] hashBytes = Convert.FromBase64String(hash);
       4:     byte[] valueToVerify = Encoding.UTF8.GetBytes(value);
       5:     HashAlgorithm sha1 = HashAlgorithm.Create("SHA1");
       6:     RSACryptoServiceProvider provider = new RSACryptoServiceProvider();
       7:     provider.FromXmlString(publicKey);
       8:     return provider.VerifyData(valueToVerify, sha1, hashBytes);
       9: }

    Il metodo qui sopra invece prende l'hash (la firma risultante dal metodo precedente), il valore originario da verificare (nel caso in esame sarebbe il contenuto del file da verificare) e la famosa chiave pubblica. Dopo che FromXmlString ha caricato nel provider RSA la parte pubblica il metodo VerifyData fa la magia e ritorna "true" se tutto corrisponde. In tal caso quindi nessuno avrà modificato la sorgente (o la chiave di cifratura). Come si usa?

       1: string value = "Andrea Boschin";
       2: string publicKey = string.Empty;
       3:  
       4: // genero la firma
       5: string hash = SignData(value, out publicKey);
       6:  
       7: // verifico il valore con la firma e la chiave pubblica
       8: bool success = VerifyData(value, hash, publicKey);
       9:  
      10: Console.WriteLine(success);
      11:  
      12: Console.ReadLine();

    A questo punto potremmo pure compilare la chiave pubblica all'interno dell'applicazione (tanto è pubblica...) e verificare che firma e contenuto siano corrispondenti l'uno con l'altro sollevando una bella eccezione qualora un malintenzionato cambi anche solo una virgola.

    Il sistema è violabile? Dato per scontato che la violabilità di un sistema è probabilemente inversamente proporzionale al tempo a disposizione, anche questo sistema lo è. Ma il malintenzionato dovrebbe  quindi generarsi una chiave privata con cui firmare il file e sostituire la chiave pubblica all'interno del vostro codice (a quel punto però non aggiorna più l'applicazione...). Come dicevo, il sistema non è infallibile, ma probabilmente se lo accoppiate con un assembly firmato allora il tempo necessario per violarlo cresce a sufficienza.


    Da qualche tempo sono tornato a sperimentare con l’Entity Framework. Nonostante prima Silverlight e recentemente le applicazioni Windows Phone e Windows Store mi stiano impegnando parecchio, soprattutto dal punto di vista della User Interface, mi capita molto spesso di avere a che fare con le problematiche di backend e architetturali. In questo post e nei prossimi vorrei mostrarvi una soluzione che ho adottato tempo fa con Entity Framework e sulla quale non ho mai avuto tempo di scrivere approfonditamente, ma che recentemente ho provato anche con EF5.0 scoprendo che è perfettamente applicabile.

    Nel primo post vorrei dimostrarvi come sia possibile, con pochi e semplici passi, spostare le entità generate a partire dall’EDMX in un assembly separato. Usare Entity Framework ci regala un sistema di generazione del codice davvero potente, ma spesso ci fa scordare le buone pratiche e il rischio di mischiare le cose è sempre dietro l’angolo. Dal mio punto di vista, una volta scelto che le entità debbono essere POCO (cioè oggetti leggeri che non hanno dipendenze) la scelta di spostarle in un assembly dedicato è praticamente imprescindibile, non fosse altro che per mantenere ordine. Ecco quindi come procedere con EF5.0.

    imageDiamo per scontato di aver generato una solution simile a quella riportata nella figura qui a lato. Il primo progetto "Data" è quello che conterrà il DataContext mentre il secondo progetto, denominato "Entities" servirà a contenere le entità generate da Entity Framework. L'unica accortezza preliminare è quella di creare un riferimento da "Data" a "Entities" dato che come intuibile la parte che rimane nel primo assmbly dovrà referenziare le entità. Come secondo passo è il momento di generare un EDMX, all'interno del progetto "Data", usando il template di Visual Studio 2012 (ma funziona anche con il 2010). Lascio a voi la scelta del database, basta che alla fine vi troviate con almeno una entità generata come riportato nella figura sottostante.

    imageCon Entity Framework 5.0 il template automaticamente seleziona per noi una modalità di generazione del codice "DbContext", cioè delle entità che sono del tutto "pulite" da ogni riferimento a qualsivoglia classe base. Se infatti si apre il file "Person.cs", generato a partire dalla tabella "People" (sì, avete capito bene, People è plurale di Person e quindi il designer sceglie una entità del nome opportuno) vedrete che contiene esclusivamente le proprietà derivanti dalle colonne del database e null'altro.

    Un'altra caratteristica di EF5.0 è che implicitamente installa I file .tt (template t4) che generano il codice ma questi file sono a nostra disposizione per eventualmente customizzare come il codice viene generato. Samples.Context.tt genera il DbContext mentre Samples.tt genera tutte le entità necessarie.

    Ora, se si apre la cartella dei file del progetto "Data" e si prende il file Samples.tt, è possibile copiarlo nell'assembly "Entities". Questa operazione va fatta dal filesystem perchè Visual Studio non ci consente il cut & paste su questo item. Ma se poi, una volta copiato il file torniamo nel progetto "Data" ci sarà consentito di cancellare il file "Samples.tt". imageSulla sinistra riporto come appare il progetto dopo l'operazione.

    Se si prova a compilare però ci si rende subito conto che la generazione delle entità fallisce con un errore. Il fatto è che il file TT che abbiamo spostato contiene un riferimento al file EDMX dal quale estrae le informazioni che gli servono per generare le entità. Avendo spostato il file dobbiamo correggere questa referenza e per farlo occorre modificare manualmente il file Samples.tt.

    Modificare un file TT non è la cosa più semplice e intuitiva. Tanto per cominciare il codice non appare colorato e quindi pare di essere tornati a "emacs". In secondo luogo nemmeno l'intellisense ci viene in aiuto. L'unico sistema è quello "empirico" per cui si modifica e si genera provando a vedere se il risultato ottenuto è quello atteso. Solo in Visual Studio 2012 abbiamo un ottimo "Debugger" per I file TT che ci viene in aiuto quando proprio non ne veniamo fuori. Se proprio ne avete bisogno, potete scaricare l'ottimo "Tangible T4 editor" dalle estensioni di Visual Studio e sarete graziati da un editor decente. A questo punto, aprendo il file "Samples.tt" vedrete quanto segue nelle prime righe del file:

    image

    In particolare la linea che ci interessa è quella evidenziata. In questa riga dovremo riportare un path relativo cosicchè anche spostando il progetto in un'altra cartella esso sarà perfettamente compilabile. Nel mio caso il path è il seguente:

       1: const string inputFile = @"..\Elite.Samples.Architecture.Data\Samples.edmx";

    Una volta modificata la linea e salvato il file Visual Studio ci mostrerà immediatamente i file delle entità generate diligentemente. Ma se si prova a compilare ci si scontra con un nuovo errore. L'errore è facilmente comprensibile: al DbContext generato nell'assembly "Data" mancano i riferimenti all'assembly delle entità. Non si tratta della referenza di progetto che dovremmo aver già creato ma banalmente dello "using". Apriamo quindi il file Samples.Context.tt, troviamo la riga dove appare "using System.Data.Entity.Infrastructure;" e aggiungiamo subito sotto le using all'assembly delle nostre entità. Nel mi caso "using Elite.Samples.Architecture.Entities;". In questo modo:

       1: using System;
       2: using System.Data.Entity;
       3: using System.Data.Entity.Infrastructure;
       4: using Elite.Samples.Architecture.Entities;

    A questo punto il compilatore non si lamenta più. Due semplici modifiche ai template di generazione e ci ritroviamo DbContext ed entità in asembly separati, che compilano alla perfezione. Esattamente quello che stavamo cercando. Per I più pigri ecco il progetto ottenuto dai passi che vi ho riportato. Ricordate solo di modificare la password nel file di configurazione, laddove trovate YOURPASSWORDHERE. Poi tenetelo da parte per il prossimo post...

    Download: Elite.Samples.Architecture.zip (2,32MB)


    Dopo un anno di assenza, nel quale mi sono recato in Provenza, quest’anno ho deciso di riportare la famiglia in Puglia, questa volta sul Gargano mentre nella precedente vacanza avevo raggiunto le coste del Salento. Dopo alcuni giorni di permanenza devo dire che c'è un netto contrasto tra la bellezza del luogo. che offre degli scorci davvero suggestivi, e l'aspetto trasandato delle località turistiche, contrasto che non avevo avvertito invece nel Salento due anni fa.

    La cittadina di Mattinata, presso cui siamo alloggiati, è collocata in una delle zone più belle, a poca distanza da Vieste e Manfredonia e qualcuno si potrebbe aspettare una zona baciata dal benessere del turismo oltre che dal sole. Invece sono tre serate che preferiamo rimanere a poltrire nella terrazza al fresco della collina, anzichè recarci in un paesello ornato da costruzioni fatiscenti, disordinato e vittima dell'incuria dell'amministrazione comunale che si dimostra incapace di organizzare minimamente l'arredo urbano o perlomeno la pulizia urbana al di fuori del perimetro ristretto del centro.

    Nella mia vita ho visitato molti luoghi del meridione d'Italia, e vi ho sempre trovato una cortesia inarrivabile accompagnata da una grande dignità anche nella povertà. Qui invece vedo spesso persone che ormai hanno l'aspetto "sconfitto" di chi ha smesso di combattere da tempo. Aspetto che sinceramente non mi sarei aspettato in una delle più belle zone d'Italia.

    Segui la vacanza su twitter: #apulia2012