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)


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)


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)


Chiunque scriva buon codice sa che l'uso delle costanti è sicuramente auspicabile e io in questo non la penso certamente in modo diverso. In linea di massima le costanti pervadono il codice che scrivo e spesso ormai vi sono situazioni in cui viene automatico farne uso. Credo fermamente però, che vi siano situazioni nelle quali una costante non ha nessun significato; mi è capitato ad esempio di imbattermi in codice scritto da chi considera la "stringa", intesa come una valore costante hard-coded all'interno del codice, come una onta, un peccato originale da cui non si può essere assolti.

Vi sono situazioni in cui il è il contesto in cui viene usato che rende implicitamente un valore "costante" e quindi l'incapsularlo una volta in più non è giustificato. Vi faccio un esempio classico:

   1: public static string WorkingDirectory
   2: {
   3:     string workingDirectory = ConfigurationManager.AppSettings["WorkingDirectory"];
   4:  
   5:     if (string.IsNullOrEmpty(workingDirectory))
   6:         throw new ConfigurationErrorsException(Resources.WorkingDirectoryNotSpecified);
   7:  
   8:     return workingDirectory;
   9: }

In questo esempio l'uso di una stringa hard-coded (WorkingDirectory) è sicuramente ammissibile. In effetti la stringa è incapsulata all'interno di una proprietà e siamo matematicamente certi che sarà l'unico punto in cui stiamo esprimendo tale valore. E' altrettanto vero che questo valore non cambierà mai per tutta la durata del programma perciò questa "costante" è tale perchè è il contesto a renderla tale. Incapsulare il valore "WorkingDirectory" in Consts.WorkingDirectoryName è un plus che ci possiamo sicuramente risparmiare. Intendiamoci, male non ne fa, ma nemmeno bene.

Un'altro caso che mi è capitato di vedere, e invece considero sbagliato è l'uso di costanti per incapsulare le query SQL. Qualcosa del genere per intenderci:

   1: private const string SELECT_CATEGORIES_ORDERED_BY_ID = "SELECT * FROM Categories ORDER BY CategoryID";
   2:  
   3: ...
   4:  
   5: using (SqlCommand command = new SqlCommand(SELECT_CATEGORIES_ORDERED_BY_ID))
   6: {
   7:     // ...
   8: }

Questo uso delle costanti, per quanto a prima vista può sembrare sensato, rende il codice nettamente meno leggibile. Fatico a trovare una ragione per un codice del genere. Se l'intento è di gestire delle query che possano essere diverse perchè magari devono essere rivolte verso diversi RDBMS, non sarà l'uso delle costanti che mi risolverà il problema ma piuttosto una buona architettura ad adapter che mi consenta di scambiare il DAL agevolmente. L'unico risultato apprezzabile sarà che una volta che devo debuggare il codice sarò costretto a saltare avanti e indietro per il codice alla ricerca del valore delle costanti per cercare di capirne il significato.

In linea di massima, se il valore che state scrivendo verrà usato più di una volta è necessario incapsularlo in una costante. Se diversamente state scrivendo un valore una volta, con il sospetto che un giorno potreste usarlo altrove, ecco un altro buon motivo di metterci una costante. Ma se il valore è palese che rimarrà isolato ad una sola occorrenza, allora è già una costante, inutile ribadirlo :)

Mi raccomando, non prendete questo post come una mia personale crociata contro le costanti, è di certo meglio un codice in cui si abusi di esse piuttosto che una sola riga di codice in cui si manchi di usarne una opportunamente. Forse però, se una morale deve essere trovata, pensare a quello che si sta scrivendo è sicuramente la cosa migliore.


La scorsa settimana sono stati pubblicati due webcast su be-it - il sito di video di Microsoft Italia - che ho registrato recentemente. L'argomento è l'Entity Framework 4.0, che è stato rilasciato recentemente all'interno del Framework 4.0. I webcast sono i seguenti:

  1. Entity Framework 4.0: Introduzione
  2. Entity Framework 4.0: Le novità

Sono particolarmente contento del primo che è una semplice introduzione agli ORM, realizzata con poche slide animate per raccontare le problematiche dell'object realtional mapping attraverso la lente di Entity Framework. I vostri commenti su cosa migliorare sono ben accetti ovvaimente.


La scorsa settimana sono stati pubblicati due webcast su be-it - il sito di video di Microsoft Italia - che ho registrato recentemente. L'argomento è l'Entity Framework 4.0, che è stato rilasciato recentemente all'interno del Framework 4.0. I webcast sono i seguenti:

  1. Entity Framework 4.0: Introduzione
  2. Entity Framework 4.0: Le novità

Sono particolarmente contento del primo che è una semplice introduzione agli ORM, realizzata con poche slide animate per raccontare le problematiche dell'object realtional mapping attraverso la lente di Entity Framework. I vostri commenti su cosa migliorare sono ben accetti ovvaimente.


Recentemente ho avuto la necessità di scrivere un batch in C# che nottetempo facesse delle operazioni un po' pesanti su un database, attingendo ai dati, compiendo elaborazioni e alla fine salvando i risultati nel medesimo database. Dopo un po' di test mi sono reso conto che il problema principale era dato dai timeout che saltuariamente il batch otteneva su alcune query con il rischio di compromettere l'integrità del lavoro.

Così, LINQ alla mano mi sono create un piccolo script che, presa in carico una operazione effettua un numero dato di tentativi intervallati da un ragionevole timeout così da dare il tempo al database di fare il suo lavoro.

   1: /// <summary>
   2: /// Does the retry.
   3: /// </summary>
   4: /// <param name="maxRetry">The max retry.</param>
   5: /// <param name="waitTimeout">The wait timeout.</param>
   6: /// <param name="action">The action.</param>
   7: public static void DoRetry(int maxRetry, int waitTimeout, Action<int> action)
   8: {
   9:     for (int current = 1; current <= maxRetry; current++)
  10:     {
  11:         try
  12:         {
  13:             action(current);
  14:             return;
  15:         }
  16:         catch (SqlException ex)
  17:         {
  18:             // TIMEOUT | DEADLOCK
  19:             if (ex.Number != -2 && ex.Number != 1205)
  20:                 throw ex;
  21:         }
  22:  
  23:         Thread.Sleep(waitTimeout);
  24:     }
  25: }

Lo script è davvero semplice e pulito. Chiede in ingresso il numero massimo di tentativi e il tempo di attesa, oltre ad una Action<int> ovvero una lambda expressione con l'azione da compiere. Poi fa un semplicissimo ciclo for che ad ogni iterazione chiama l'Action. Nel caso vada tutto bene esce altrimenti - in caso di timeout o di deadlock - attente il timeout e riprova. Naturalemente in caso di diversa eccezione il metodo notifica l'eccezione al chiamante. Ecco come usarlo:

   1: public void ExecuteLongRunningQuery(int parameter)
   2: {
   3:     Operations.DoRetry(5, 10000,
   4:         n =>
   5:         {
   6:             DataStore.LongRunningQuery(parameter);
   7:         });
   8: }

Poche righe e otteniamo di ripetere la query 5 volte intervallata di 10 secondi l'una dall'altra. Il parametro "n" che viene passato alla lambda è il numero di iterazione corrente e permette di scrivere in un ipotetico log il numero di tentativi effettuati.

Technorati Tags: ,

Da un po' di tempo lavoro con e, nonostante tutti i conosciuti problemi, in azienda siamo riusciti ad addomesticarlo (o forse lui ha addomesticatio noi :P) e riusciamo a trarne vantaggio, nei limiti da esso imposti. In attesa della prossima versione che pare risolva buona parte dei problemi (ma al momento lo dico solo per sentito dire e non per esperienza diretta), vorrei darvi un tip su come gestire il merge di file EDMX (il Model di Entity Framework per intenderci) che se preso nel verso sbagliato è prolifico di errori.

L'origine del problema è da individuarsi in una formattazione "allegra" del file XML per cui il tag di chiusura di alcune sezioni viene messo in coda all'ultimo elemento figlio e non sulla riga successiva. Un esempio lo si vede nella parte superiore della seguente figura.

Comparazione Per quanto strano possa sembrare questo fatto mette in crisi il merge (io mi riferisco a Team Foundation Server) e spesso (o soprattutto) la persona che lo sta compiendo. Può accadere che aggiungendo una property ad una entità ci si trovi nel caso della parte inferiore della figura soprastante. Come si vede la proprietà Date diventa l'ultima dell'EntityType. Un merge manuale comporta la copia di entrambe le righe 107 e 108 ma come spesso accade (e direi "umanamente accade") si tende a copiare solo la riga 108 ottenendo quanto segue:

merged Inutile dire che il risultato è un errore di compilazione che (complice l'entity designer di Visual Studio) si traduce nel fallimento della generazione del codice e in qualche centinaio di incomprensibili errori... tutto ciò significa solo una cosa: tempo perso.

Dopo esserci caduto svariate volte ho elaborato una mia "strategia" personale per il merge di file edmx. L'unica cosa "sana" da fare è prevenire questo genere di errori aprendo manualmente da Visual Studio i due file da comparare nell'editor XML e grazie alla preziosa combinazione di tasti CTRL+SHIFT+D riformattare l'XML correttamente. Una operazioni di pochi istanti, che non richiede nemmeno l'apertura della solution, che però fa evitare errori inutili e forieri perdite di tempo. Una volta riformattati i file con questa combinazione infatti il codice sarà lineare e, sembra impossibile ma è così, si otterranno anche meno merge manuali.


E' passata una settimana durante la quale ho un po' staccato. Naturalmente ho dimenticato di pubblicare i sorgenti e le slide dei meeting. Viste le incalzanti richieste eccomi finalmente a pubblicare il materiale che vi avevo promesso. Si tratta più o meno di una serie di esempi riguardanti l'Entity Framework che ho messo assieme mentre lo studiavo. Questi esempi poi sono diventati la base per la sessione dello scorso 12 Dicembre.

Approfitto per ringraziare i partecipanti che hanno dimostrato di apprezzare la sessione - nonostante l'argomento fosse un po' pesante - sia per mezzo dei feedback che contattandomi durante questi giorni per pormi qualche domanda.

Ed ecco il link al materiale: http://blog.boschin.it/download/entityframework.rar

Ancora grazie.

Technorati Tags: ,