Programming Languages Hacks

Importanti regole per linguaggi di programmazione rilevanti come Java, C, C++, C#…

  • Subscribe

  • Lettori

    I miei lettori abituali

  • Twitter

Task ContinueWith only if completed successfully

Posted by Ricibald on December 6th, 2015

Task ContinueWith only if completed successfully

When a Task is canceled it propagates a TaskCanceledException that can be handled using ContinueWith:


var tcs = new TaskCompletionSource<int> ();
tcs.SetCanceled ();


Task.Run (async () => await tcs.Task)
    .ContinueWith(antecedent => Console.WriteLine("Finalize my work"))
    .Wait();

// OUTPUT:
// Finalize my work


The problem is that ContinueWith works in these cases:

  • the task is completed successfully
  • the task is canceled (TaskCanceledException)
  • the task is faulted (Exception or AggregateException)

In other words ContinueWith is the finally part in a try/catch block.

For me it seems a little weird, it would sounds better to continue only in case of success.

You can continue only in case of success chaining the different cases in this way according to TPL guide:

var tcs = new TaskCompletionSource<int> ();
  
tcs.SetCanceled ();

   

Task.Run (async () => await tcs.Task)

    .ContinueWith(antecedent => Console.WriteLine("Finalize my work"), TaskContinuationOptions.OnlyOnRanToCompletion)

    .ContinueWith(antecedent => Console.WriteLine("Undo my work"), TaskContinuationOptions.OnlyOnCanceled)

    .ContinueWith(antecedent => Console.WriteLine("Abort my work"), TaskContinuationOptions.OnlyOnFaulted)

    .ContinueWith(antecedent => Console.WriteLine("Clean resources (finally part)")
    .Wait();

// OUTPUT:
// Undo my work
// Clean resources (finally part)


You can finally write your extension method to have this behavior compact and readable:

var tcs = new TaskCompletionSource<int> ();
  
tcs.SetCanceled ();

   

Task.Run (async () => await tcs.Task)
        
    .ContinueOnlyOnSuccessWith (antecedent => Console.WriteLine ("Finalize my work"))

    .Wait();
 

// OUTPUT:
// <empty>


This is the code for ContinueOnlyOnSuccessWith:

public static class Extensions
{
        
    /// <summary>
    
    /// Continues only if task is completed successfully.
        
    /// It handles the cancelled and failed state.

    /// </summary>
       
    public static Task ContinueOnlyOnSuccessWith(this Task task, Action<Task> continuationAction) 
    {
            
        return task
              
            .ContinueWith (continuationAction, TaskContinuationOptions.OnlyOnRanToCompletion)

            .ContinueWith(antecedent => {});
     
    }
}

Posted in .net | No Comments »

Convert Event-Based Asynchronous to Task

Posted by Ricibald on November 29th, 2015

Convert Event-Based Asynchronous to Task

The following example shows how to expose an arbitrary sequence of Event-Based Asynchronous Pattern (EAP) operations as one task by using a TaskCompletionSource<TResult>.

The example also shows how to use a CancellationToken to invoke the built-in cancellation methods.

When to use it:

  • you have a mix of Events and Tasks and you need to uniform them
  • you have an Event that needs to be treated using your already-done Task background processing
  • you have a complex flow of Events and you need to simplify the code readability

This extension method do the work:

public static class TaskExt
{
    public static async Task<TEventArgs> FromEvent<TEventArgs>(
        Action<EventHandler<TEventArgs>> registerEvent,
        Action action,
        Action<EventHandler<TEventArgs>> unregisterEvent,
        CancellationToken token)
    {
        var tcs = new TaskCompletionSource<TEventArgs>();
        EventHandler<TEventArgs> handler = (sender, args) => tcs.TrySetResult(args);
        registerEvent(handler);

        try 
        {
            using (token.Register(() => tcs.SetCanceled()))
            {
                action();
                return await tcs.Task;
            }
        }
        finally
        {
            unregisterEvent(handler);
        }   
    }
}

So if you have this class with this event:

public class LdapProvider {
    public event EventHandler<string> Authenticated;
    public void Authenticate(string username, string password) {
        // show the browser...
    }
    //... called back from the browser
    public void AuthenticateCallback(string token) {
        if(Autenticated != null)
            Authenticated(token);
    }
}

You can call this class using events in this way:

// save Token from ldapProvider when the event Autenticate fires
var ldapProvider = new LdapProvider();
ldapProvider.Authenticate("username", "password");
ldapProvider.Authenticated += (sender, token) => this.Token = ldapProvider.Token;
// wait for event be fired...

It can be converted in this way:

public static class LdapProviderExtensions {
    public static async Task<string> AuthenticateAsync(this LdapProvider ldapProvider, string username, string password) { 
        await TaskEx.FromEvent<string> (
            handler => ldapProvider.Authenticated += new EventHandler<string> (handler), 
            () => ldapProvider.Authenticate("username", "password"),
            handler => ldapProvider.Authenticated -= new EventHandler<string> (handler),
            CancellationToken.None);
    }
}


And used in this simple way:

// save Token from ldapProvider when the event Autenticate fires
var ldapProvider = new LdapProvider();
var token = await ldapProvider.AuthenticateAsync("username", "password");
// you have the token without saving it in a property...

Posted in .net | 1 Comment »

VS 2015: novità

Posted by Ricibald on July 24th, 2015

VS 2015: novità

Panoramica delle possibilità di VS 2015 esistenti/nuove:

  • mobile app ibride con javascript (Cordova) o native con C# (Xamarin), C++, Unity
  • integrazione con BaaS come Azure Mobile Services e Application Insight per il monitoraggio SaaS di app mobile o .NET
  • editor potente HTML5, CSS3, LESS/SASS, Javascript con Intellisense pronto per Angular, Bootstrap, Backbone, Express, Django
  • package manager: NuGet per .NET, Bower per JS client, NPM per JS server con node.js
  • grazie al nuovo progetto .NET basato su cartelle e non più su csproj è possibile utilizzare IDE diversi da VisualStudio, come Omnisharp che integra vari editor come Brackets e pubblicarli in web server cross-platform grazie all’integrazione con OWIN
  • test su differenti browser, reali o emulati (Windows Phone, Android, iOS)
  • integra diverse estensioni di VS per il web, come le anteprime Microsoft Web Essentials, compressioni automatiche di immagini, bundle e minificazione di JS+CSS+HTML, web compiler integrati in MSBuild LESS+Scss+CoffeeScript, unit test runner per JS, JS code analysis
  • supporto a unit test da JS, a TypeScript per la compilazione di JS,
  • debug locale, remoto e misto su C#, VB, C++, JS, Python, XAML, HTML. Debug offline tramite IntelliTrace. Breakpoint condizionali, debug di multithread, tracking performance tramite PerfTips
  • con i nuovi progetti Azure Resource Group si possono definire le caratteristiche di un gruppo di vm e deployarle in blocco tramite script o wizard integrato con VS
  • tramite l’integrazione con Docker si possono creare cloni di una stessa vm per rapidi continuous integration. Tali “cloni” o “immagini” contengono solo il software necessario per partire mantenendo lo stesso S/O e librerie condivise. Per ora supportato solo su macchine che consentono l’host di .NET Core come Ubuntu, in futuro sarà supportato anche da Windows Server
  • analisi del codice per rilevare porzioni di codice che bloccano la scalabilità sul cloud tramite il pacchetto NuGet Microsoft.VisualStudio.Azure.CodeAnalysis
  • deploy automatizzati tramite PowerShell o Release Management
  • applicazioni windows tramite WPF (con Expression Blend), Win32, DirectX. Tramite Windows 10 si può sfruttare un set unico di API per deployare su diversi device (anche IoT)
  • supporto nativo per estensioni di Office, Sharepoint grazie al debugging integrato, all’autocompletamento delle librerie JS correlate, al publish integrato
  • tramite Release Management è possibile impostare workflow di deploy e tracciare l’intero processo e gli step
  • riuso dello stesso codice su più piattaforme (es. C++ su Android)
  • grazie a Roslyn (.NET Compiler Platform) è migliorata l’analisi in tempo reale del codice grazie a suggerimenti in stile Resharper (light bulbs) includendo linee guida dagli stessi pacchetti NuGet scaricati (Compiler as a Service) come Microsoft.CodeDom.Providers.DotNetCompilerPlatform
  • supporto nativo a .NET Framework 4.6
  • supporto nativo a EF 7 che funziona anche su Windows Phone e Windows Store e si connette sia a db relazionali che non-relazionali (Azure Table Storage, Redis)
  • JSON editor integrato con supporto allo schema e IntelliSense
  • supporto nativo ad ASP.NET 5: soluzione ricostruita da zero, leggera e componibile eseguibile in host compatibili OWIN cross-platform (IIS su Windows o altri Linux/Mac), supporta ASP.NET MVC 6
  • IntelliTest: analizza il codice per generare dati di test sensibili
  • Supporto esteso in VS per GIT con il controllo di feature, history con multipli branch, rebase, …
  • oltre alle Service Reference, NuGet Reference ora è possibile creare Connected Service per aggiungere facilmente connettori verso Azure Application Insights, Azure Storage, Azure Mobile Services, Office 365, Salesforce

Posted in .net | No Comments »

OWIN e KATANA

Posted by Ricibald on March 14th, 2015

ASP.NET e OWIN

Nel tempo il framework ASP.NET si è trasformato. Inizialmente viveva unicamente nel contesto System.Web e le evoluzioni seguivano tempistiche di evoluzione dello stesso System.Web (annuali). In seguito l’approccio è evoluto verso componenti indipendenti da System.Web come le ASP.NET MVC e ASP.NET Web API le cui evoluzioni viaggiano indipendentemente grazie a NuGET iterando rapidamente e rimanendo "al passo".

Essendo indipendenti da System.Web sono quindi indipendenti anche da IIS: è infatti possibile fornire l’hosting di ASP.NET Web API all’interno di una semplice console o servizio windows.

La possibilità di avere un "host custom" leggero grazie ad ASP.NET Web API è stato voluto anche da numerosi altri framework, ognuno con le proprie esigenze di start/stop etc. Questo consente di non avere un IIS monolitico con tutte le funzionalità, ma avere un web server con i vari componenti indipendenti su NuGET che possono iterare indipendentemente. Avremo quindi update indipendenti per: static file serving, dynamic page generation, Web API, real-time/push notifications.

OWIN definisce un’interfaccia standard che consente di disaccoppiare il server dalle applicazioni (non sono legato fortemente a IIS o System.Web) consentendo lo sviluppo di moduli indipendenti e il deploy di applicazioni in differenti host, piattaforme e sistemi operativi. Diventa di fatto un framework generico per far interagire i framework web con i server attraverso una pipeline OWIN nota come middleware.

Tale standard, caratterizzato prevalentemente dallo scambio di strutture dati e delegati, deve poi essere implementato da un Web Server compatibile con lo standard OWIN.

Katana

L’implementazione Microsoft di tale standard open è Katana: la versione "portable" e leggera dei componenti ASP.NET. Include framework, server e host, è modulare (il size cresce solo a seconda dei moduli effettivamente utilizzati) e quindi più performante e scalabile. Porta in sostanza gli stessi benefici di Node.js mantenendosi in un contesto ASP.NET.

Nella pratica, implementeremo le nostre pipeline OWIN basandoci sul namespace generico Microsoft.Owin (indipendente dall’host) e tramite Katana potremo scegliere l’host:

  • IIS/ASP.NET: tramite package Microsoft.Owin.Host.SystemWeb in cui le pipeline OWIN sono eseguite in IIS come parte della pipeline standard ASP.NET (in pratica Katana diventa in IIS un HttpModule e un HttpHandler). Poiché server+host confluiscono nello stesso componente i due non sono separabili e non è quindi rimpiazzare nel server un’implementazione alternativa.
  • Custom Host: tramite package OwinHost in cui le pipeline OWIN sono eseguite in un nostro processo come una console, un servizio windows o un Azure Worker Role (in pratica Katana usa la classe .NET HttpListener). Nella classe Main dovremmo inserire il codice che avvia il server.
  • OwinHost.exe: come il Custom Host ma in una console indipendente pronta all’uso che avvia il server trovando la pipeline OWIN che abbiamo implementato tramite convenzioni

Si può creare un proprio modulo Katana (es. logging) semplicemente creando una pipeline che deriva da OwinMiddleware e aggiungendolo allo startup (o tramite convenzioni se si usa OwinHost.exe).

I moduli Katana già presenti sono numerosi come si nota da NuGET e vanno da SignalR a OAuth 2.0 allo stesso ASP.NET Web API. Spesso le pipeline (o moduli) creano gerarchie di dipendenze come evidente in questa immagine.

Approfondimenti

Per altre info si consulti l’articolo introduttivo mentre si rimanda al link OWIN ufficiale per la lista dei server (es. Katana), framework (es. ASP.NET o WebAPI) e implementazioni dei framework (es. ASP.NET 5)

Posted in asp.net | No Comments »

AOP e PostSharp: scenari d’uso

Posted by Ricibald on December 7th, 2014

Normalmente un software risolve problemi specifici di un certo layer e problemi trasversali che vanno a impattare tutti i layer e tipicamente costituiscono soluzioni difficilmente rimpiazzabili. Se ad esempio utilizziamo una tecnica di logging o di gestione delle eccezioni questa sarà spalmata su tutto il progetto e un’eventuale cambiamento di gestione diventa molto complesso, lungo e impattante.

L’aspect-oriented programming (AOP) si pone l’obbiettivo di modularizzare le problematiche trasversali abilitandone astrazione, riuso e sostituibilità.

L’AOP può essere implementato in diversi modi:

PostSharp è gratuito nella versione Express. Consente di implementare qualunque aspetto “elementare” in modo completamente free, ma si possono sfruttare pattern pronti all’uso pagando un costo aggiuntivo.

In questo articolo cercherò di descrivere i pattern che PostSharp implementa: lo scopo è quello di scoprire quali sono i pattern in cui ha senso utilizzare AOP, identificarli nel proprio progetto e modularizzarli in qualche modo (anche tramite le altre due tecniche prima descritte).

Diagnostica e monitoraggio

Tramite attributo Log viene tracciato start/end del metodo, relativi parametri (nome+tipo+valore) e ritorno scrivendo su un generico LoggingBackend (System.Diagnostics.Trace, System.Console, Log4Net, NLog, Enterprise Library, custom).

Se si vuole tracciare anche le eventuali eccezioni allora si deve aggiungere al metodo l’attributo LogException. In particolare una gestione del genere consente di realizzare una gestione dell’eccezione globale in modo da poter centralizzare una policy di gestione degli errori (es. rethrow in un’eccezione più astratta).

Performance e Caching

È possibile pensare di incrementare automaticamente performance counter allo start/end di un metodo per poter monitorare le performance dell’applicazione in specifici punti.

Inoltre si potrebbe implementare un meccanismo automatico di caching che:

  • allo start calcola la chiave di cache basata su nome metodo e relativi parametri e verifica se tale cache esiste:
    • in caso positivo restituisce la chiave di cache bypassando la reale esecuzione del metodo
    • in caso negativo esegue realmente il metodo e salva il ritorno in cache

Lo scope della cache potrebbe essere globale, per-session, per-request, transient.

Validazione e Contratti

Tipicamente ogni metodo dovrebbe verificare che i parametri passati siano coerenti con quanto atteso (es. non nulli, positivi, …). La verifica manuale di ogni campo ha il problema di duplicare il codice e di legare l’implementazione al concetto. In realtà ogni metodo dovrebbe essere progettato secondo il principio Design by Contract (DbC) descrivendo il contratto richiesto. Tale contratto si tradurrà in: documentazione, validazione a tempo di compilazione e, ovviamente, implementazione.

Sebbene .NET 4.0 implementi i Code Contracts, PostSharp ha comunque la sua soluzione (più immediata) mediante attributi nel namespace Contracts da applicare ai parametri dei metodi come Required, Range, RegularExpression, GreaterThan.

Notifica delle modifiche (trigger)

Tramite attributo NotifyPropertyChanged è possibile implementare senza scrivere codice ripetitivo l’interfaccia INotifyPropertyChanged sollevando automaticamente l’evento PropertyChanged per ogni variazione delle proprietà.

Rilascio delle risorse: commit/dispose/rollback

Mediante la decorazione di PostSharp è possibile realizzare un aspect che:

  • allo start crea una risorsa da rilasciare (WebService, Socket, UnitOfWork, TransactionScope, IDisposable)
  • in caso di successo esegua (se serve) la Commit (altrimenti la Rollback)
  • all’end esegue automaticamente la relativa Dispose

Metadati e aggregati

È possibile descrivere la composizione logica di una struttura decorando un aggregato logico tramite attributo (advice) Aggregatable che descrive i field come Child (e le relative collezioni AdvisableCollection e AdvisableDictionary), Parent o Reference (cioè non coinvolto nella relazione padre/figlio).

Questa struttura con i relativi metadati è ispezionabile tramite pattern Visitor mediante metodo esposto da PostSharp VisitChildren. Tramite l’analisi della struttura è possibile implementare determinati pattern (anche custom) che propagano o meno il proprio comportamento in tutto l’aggregato.

PostSharp basandosi sul concetto di Aggregatable implementa i seguenti pattern:

Rilascio “cascade” delle risorse

In PostSharp l’attributo Disposable consente di implementare IDisposable propagando (cascade) tale chiamata a tutti gli oggetti Child coinvolti

Undo/Redo

Tramite l’attributo Recordable i metodi invocati in un’istanza vengono registrati in un corrispondente Recorder che, tramite il salvataggio di vari restore point (pattern Memento) consente undo/redo dei restore point registrati (pattern Command), eseguendo eventualmente prima di undo/redo una corrispondente callback.

Per registrare le modifiche degli oggetti figli dipendenti l’attributo Recordable si affida sulle informazioni sull’aggregato logico provenienti da Child/Parent.

Di default tutti i metodi vengono registrati come potenziali cambiamenti che concorrono a undo/redo, ma la lista dei metodi è personalizzabile e componibile in “scope” personalizzati. Inoltre il Recorder di default può essere rimpiazzato con uno custom (ad es. su db).

Threading Model

Normalmente in un codice si implementa la gestione del thread senza ricondurre la problematica a uno specifico Threading Model. Infatti ricondurre un problema di concorrenza a una problematica ricorrente consente di parlare un vocabolario comune e, grazie all’AOP, di disinteressarsi dell’implementazione (normalmente ripetitiva e fragile) la quale, in quanto rimpiazzabile, può essere espressa in modo dichiarativa, “concettuale”.

Di seguito i threading model possibili:

  • Immutable: garantisce che la classe sia immodificabile dopo il costruttore, abilitando il multithread senza rischi (thread-safe). In caso di modifiche dopo il costruttore solleva una ObjectReadOnlyException
  • Freezable: garantisce che la classe sia immodificabile dopo aver invocato Freeze(). È simile a Immutable, ma meno aggressivo. Propaga il freeze nei corrispondenti Child/Parent definiti tramite aggregati
  • ThreadUnsafe garantisce che i metodi saranno eseguiti al massimo da un thread, altrimenti eccezione
  • ThreadAffine garantisce che i metodi saranno eseguiti dallo stesso thread che ha creato l’istanza (stessa affinity)
  • Synchronized garantisce che i metodi saranno eseguiti al massimo da un thread, altrimenti l’altro attende
  • ReaderWriterSynchronized: a seconda del livello di accesso dichiarato nei metodi (nelle property sono già automaticamente impostate) garantisce le seguenti:
    • Reader: legge concorrentemente fino all’arrivo concorrente di un Writer che blocca tutti i Reader
    • Writer: scrive in modo esclusivo attendendo gli ultimi Reader e bloccando i successivi che verranno
    • UpgradeableReader: legge concorrentemente (come Reader) ma se trova un punto nel suo metodo che implica un Writer acquisisce tale lock. Consente quindi di aumentare la concorrenza dei Reader e tipicamente viene usato nelle operazioni long-running dove si cerca di accorpare i cambiamenti di stato in un’unica istruzione finale
  • Actor: tecnica per evitare completamente le problematiche di concorrenza Reader/Writer andando a definire un altro modello di comunicazione tra le classi. Invece di invocare metodi standard su oggetti e sincronizzare l’accesso, si accodano messaggi che sono poi scodati nell’ordine di accodamento in modalità asincrona (async/await) e tramite thread-pool ottimizzando le performance (CPU). Questo garantisce che se eseguo una GetXXX ma prima è avvenuta una SetXXX la sequenza delle invocazioni verrà garantita e quindi la classe sarà race-free

Tutte le verifiche automatiche da PostSharp possono essere evitate per specifici metodi (opt-out) se definito l’attributo ExplicitlySynchronized o possono essere aggiunte esplicitamente nei metodi privati (opt-in) tramite EntryPoint.

PostSharp è inoltre in grado di eseguire la Runtime Verification per verificare che il codice sia coerente con quanto descritto negli attributi: se abbiamo definito l’attributo Reader in un metodo che altera lo stato allora PostSharp ci avviserà dell’incoerenza (disabilitato in Release).

Dispatch nel giusto thread

Spesso si ha necessità di eseguire determinati metodi nel thread corretto.
Quando si esegue un metodo in una applicazione windows si dovrebbe farlo solo in un BackgroundWorker e scrivere nella GUI solo rispondendo all’evento RunWorkerCompleted per garantire di farlo nel thread UI.

Tutto questo codice può essere evitato decorando i metodi con gli attributi Background (viene eseguito in background) e Dispatched (viene eseguito nel thread UI).

Deadlock detection

Un deadlock avviene quando thread multipli rimangono in attesa reciprocamente del processamento su una risorsa condivisa (attraverso un ciclo che può anche essere ampio e difficilmente individuabile). Tramite AOP si possono intercettare e monitorare (WatchDog) le occorrenze dei metodi .NET che sincronizzano i thread, come Mutex.WaitOne, Mutex.WaitAll, Mutex.Release, Mutex.SignalAndWait, Monitor.Enter, Monitor.Exit, Monitor.TryEnter, Thread.Join e altri. Quando l’attesa supera una soglia (es. 200ms) allora viene rilevato un deadlock e viene sollevata una eccezione in tutti i thread coinvolti nel ciclo tramite il grafo di dipendenze tra thread determinato.

PostSharp consente una gestione automatica applicando a livello di assembly l’attributo DeadlockDetectionPolicy.

Sicurezza

In .NET l’attributo PrincipalPermission consente alla CLR di verificare che l’utente corrente abbia il ruolo richiesto per invocare il metodo decorato. Quando però i check di sicurezza diventono più a grana fine non è possibile esprimere tutto con il concetto di ruolo: è necessario un if!

Per coprire queste casistiche si potrebbe richiedere alle classi che richiedono check di sicurezza di implementare obbligatoriamente un’interfaccia con il metodo IsUserInRole(role) che può eseguire check custom ove richiesto. Potremmo poi definire tramite PostSharp un attributo SecuredOperation(role) per richiamare tale metodo nelle classi che lo dichiarano (altrimenti comportamento standard tramite .NET).

A questa tecnica può essere abbinato anche il corrispondente auditing andando a scrivere in un Backend specializzato per l’auditing (event log).

Policy architetturali, convenzioni e patch di framework

AOP può essere usato per sollevare eccezioni a tempo di compilazione, per rinforzare l’utilizzo di determinati pattern architetturali o convenzioni e verificarli in modo automatico (da Visual Studio o mediante build server). Ad esempio potremmo stabilire la regola che un certo layer non è mai invocabile dai layer sottostanti.

Inoltre può essere sfruttato per “fixare” lacune del framework. Ad esempio in .NET per rendere serializzabile un oggetto esiste l‘attributo Serializable che però non è un’interfaccia e non può essere utilizzata per rinforzare determinati vincoli (es. un metodo clone che accetta solo oggetti serializable). Sarebbe utile il meccanismo usato in Java in cui esiste l’interfaccia “marker” Serializable. Tramite AOP e PostSharp potremmo dichiarare una nostra interfaccia “marker” ISerializable e fare in modo che le classi che implementano tale interfaccia abbiano automaticamente dichiarato l’attributo Serializable (per iniettare attributi in PostSharp si usa CustomAttributeIntroductionAspect).

Lo stesso meccanismo può essere sfruttato per rinforzare policy tramite convenzioni:

  • tutti i tipi non nullable sono automaticamente Required
  • tutti i tipi che terminano con CreditCard sono automaticamente soggetti all’attributo RegularExpression
  • tutti i tipi da un certo namespace in poi (es. company.application.domain.*) sono automaticamente Serializable
  • tutti i metodi del layer Application creano e committano automaticamente un relativo UnitOfWork
  • tutte le eccezioni catturate nel layer Appication vengono automaticamente convertite in un’eccezione di più alto livello (exception policy)
  • tutti le classi che terminano con ViewModel implementano automaticamente l’interfaccia INotifyPropertyChanged

Persistenza

Altri casi interessanti:

  • field virtualization: la semantica di un campo (read/write) potrebbe differire dallo store in cui viene memorizzato (memory, db, …). Tramite AOP possiamo disaccoppiare i due aspetti
  • lazy loading: a volte si dichiarano alcune proprietà come Lazy poiché costose da inizializzare. Come per il field virtualization, l’AOP consente di disaccoppiare il concetto di lazy loading dalla sua reale implementazione
  • change tracking: l’attributo Recordable consente di determinare le istanze dirty e propagare in blocco i cambiamenti verso lo store (lo stesso NHibernate internamente fa uso di AOP).

Posted in .net | 1 Comment »

.NET: convertire due tipi generici

Posted by Ricibald on November 4th, 2014

Come convertire in modo generico un tipo in un altro tipo?

Immaginiamo di dover convertire un tipo generico MyCustomType in un altro tipo (es. string). Ci sono diversi modi: dal semplice ToString() a un cast verso string. Finche si converte da MyCustomType verso string non è un problema, ma quando si procede al contrario questo non è possibile poiché string è fuori dal nostro controllo.

Per queste casistiche esiste da .NET 2.0 l’attributo TypeConverter da dichiarare all’interno di MyCustomType:

[TypeConverter(typeof(MyCustomTypeConverter))]
 public class MyCustomType {
    private string Data { get; set; }
    public static MyCustomType Parse(string data) {
        // convert code from string to MyCustomType here...
        return new MyCustomType { Data = data };
    }
    public override ToString() {
        // convert code from MyCustomType to string here...
        return this.Data;
    }
 }

public class MyCustomTypeConverter : TypeConverter {
    public override bool CanConvertTo (ITypeDescriptorContext context, Type destinationType)
    {
        return destinationType == typeof(string) || base.CanConvertTo (context, destinationType);
    }

    public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
    {
        return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);
    }

    public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
    {
        if (value is string)
            return MyCustomType.Parse ((string)value);  // YOUR CONVERT HERE

        return base.ConvertFrom(context, culture, value);
    }

    public override object ConvertTo (ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
    {
        var myCustomTypeToConvert = (MyCustomType)value;
        if (destinationType == typeof(string))
            return myCustomTypeToConvert.ToString ();   // YOUR CONVERT HERE

        return base.ConvertTo (context, culture, value, destinationType);
    }
}

Una volta costruito il converter si invoca nel seguente modo per convertire da/a un certo tipo:

MyCustomType myCustomType = new MyCustomType { Data = "MyData" };
TypeConverter myCustomTypeConverter = TypeDescriptor.GetConverter (typeof(MyCustomType));

string myCustomTypeAsText = (string) myCustomTypeConverter.ConvertTo(myCustomType, typeof(string));
MyCustomType myCustomTypeFromText = (MyCustomType) myCustomTypeConverter.ConvertFrom("MyData2");

Questo risolve il problema finquando sappiamo quale dei due tipi implementa il TypeConverter per quella particolare conversione, cosa che potremmo non sapere in una gestione completamente generica.

Per questo motivo ho implementato il seguente extension method che consente di convertire due tipi generici andando a inferire in automatico quale TypeConverter utilizzare:

/// <summary>
/// Converte l'istanza. Usa il TypeDescriptor di T
/// </summary>
public static TDestination ConvertSafe<TDestination>(this object value) {
    if (value == null)
        return default(TDestination);

    // se sono gia lo stesso tipo non fare nulla
    if (typeof(TDestination) == value.GetType ())
        return (TDestination)value;

    // prova a convertire usando il converter di T
    var targetConverter = TypeDescriptor.GetConverter (typeof(TDestination));
    if(targetConverter != null && targetConverter.CanConvertFrom(value.GetType())) 
        return (TDestination)targetConverter.ConvertFrom (value);

    // prova a convertire usando il converter di value
    var sourceConverter = TypeDescriptor.GetConverter (value);
    if(sourceConverter != null && sourceConverter.CanConvertTo(typeof(TDestination))) 
        return (TDestination)sourceConverter.ConvertTo (value, typeof(TDestination));

    throw new InvalidCastException (String.Format("Unable to convert {0} to {1}", value.GetType(), typeof(TDestination)));
}

Esempio di utilizzo:

MyCustomType myCustomType = "MyData".ConvertSafe<MyCustomType>();
string myCustomTypeAsText = myCustomType.ConvertSafe<string>();

Che abilita scenari come il seguente che converte un tipo string (in teoria non convertibile) in un generico tipo MetaData<T> sfruttando internamente il TypeConverter del tipo T determinato a tempo di compilazione:

public MetaData<T> GetMetaInfo<T>(string value) {
    var result = new MetaData<T>(value.ConvertSafe<T>());
    return result;
}

Posted in .net | No Comments »

Split using delimiter except when delimiter is escaped

Posted by Ricibald on September 11th, 2014

Split using delimiter except when delimiter is escaped

A common problem is to split a string handling escape characters.

This extension method handle the case of split considering the escape.
It uses the negative lookbehind feature of regular expressions.

Posted in .net | 73 Comments »

DDD semplificato nel mondo reale

Posted by Ricibald on July 29th, 2014

Il DDD è un ottimo pattern ma se si implementa al 100% si rischia di ottenere troppa complessità rispetto a domini quasi sempre non così complessi da giustificarne una totale aderenza.

Basti riflettere infatti sul numero di astrazioni introdotte per fare una semplice insert:

  1. Application inizializza lo Unit of work e coordina i vari Domain Service
  2. Domain Service ottiene dal suo Repository il proxy del Aggregate che ha attivo il change tracking. Se necessario esegue logica specifica del caso d’uso che non si rimappa nel dominio
  3. Aggregate coordina il comportamento desiderato delegando le varie sottofunzioni alle varie Entity o Value Object in stile OO
  4. Entity o Value Object alterano il proprio stato, registrato dal change tracking verso lo Unit of work
  5. Application richiede il commit dello Unit of work
  6. Unit of work apre una micro-transazione che riversa su db lo stato alterato tracciato

Domain Service: perché??

Riporto di seguito una frase di Martin Fowler su cui mi trovo d’accordo:

Any logic that’s particular to a single transaction or use-case is normally placed in Transaction Scripts, which are commonly referred to as use-case controllers. Behavior that’s used in more than one use case goes on the domain objects which are called entities.
Although the controller entity approach is a common one, it’s not one that I’ve ever liked much. The use-case controllers, like any Transaction Script tend to encourage duplicate code. My view is that if you decide to use a Domain Model at all you really should go the whole hog and make it dominant

Il Domain Service è sostanzialmente uno use-case controller che incoraggia alla duplicazione di codice. Se veramente un’operazione è specifica di un caso d’uso bisogna comunque sforzarsi di farla entrare a pieno titolo del dominio. In altre parole: il Domain Service non deve esistere…

Repository e Unit of Work: necessari??

Il Repository pattern consente di ottenere dati da un data source layer mimando una collezione in memoria nascondendo la complessità del sottostante accesso ai dati facendo uso internamente di uno o più oggetti DAO e del pattern Query Object. Nel pattern è importante notare che è normalmente assente il concetto di Update: questo viene inferito automaticamente dallo Unit of work grazie al change tracking sulle entità restituite dal Repository.

Il pattern è efficace poiché tratta il db come aspetto secondario e permette in una prima fase di concentrarsi esclusivamente su GUI, business e TDD. Il pattern è però applicabile solo in presenza di framework ORM che gestiscano in modo efficace il change tracking e il relativo Data Mapper.

A volte il Repository pattern non è però applicabile poiché il data source layer sottostante non è un db, bensì un web service REST o SOAP o una lista Sharepoint. Implementare un meccanismo custom di change tracking diventa veramente complesso e rischioso e non è praticabile.

Bisogna dire addio quindi al DDD e tornare al classico Transaction Script? In realtà si possono implementare versioni semplificate del Repository pattern.

Repository con Unit of Work “a grana grossa”

Ciò che rende complesso il change tracking è la granularità fine: ogni singola modifica viene registrata per contribuire in modo puntuale alla query finale.

Si potrebbero ridimensionare le aspettative e semplicemente marcare l’intera Entity o Aggregate come “dirty” e quindi da aggiornare. Questo può essere implementato in modo esplicito o trasparente:

  • (esplicito) Entity esegue ove richiesto il metodo UnitOfWork.Current.SetDirty(this)
    • tramite PostSharp si può implementare in modo automatizzato su tutte le proprietà
    • tramite T4 si possono autogenerare le Entity rimappando da un modello dati (db, xml, …) arricchendo le Entity con i vari SetDirty
  • (trasparente) Repository crea un proxy delle Entity e decora ove richiesto i metodi con UnitOfWork.Current.SetDirty(this)
  • (trasparente) Entity implementa ove richiesto l’interfaccia INotifyPropertyChanged e Repository gestisce gli eventi PropertyChanged registrando la modifica UnitOfWork.Current.SetDirty(item)

Al momento del Commit dello Unit of work questo avrà la lista delle entità da aggiornare. Sarà compito del nostro Unit of work custom di rimappare gli stati “dirty” con i rispettivi metodi nei vari DAO.

Repository senza Unit of Work: update espliciti

L’approccio precedente è una soluzione buona ma richiede persone esperte che sappiano rimappare lo Unit of work con i vari DAO. Un approccio più facilmente comprensibile è quello di annullare del tutto lo Unit of work e aggiungere nel Repository un metodo Update che opera sull’intero aggregato.

Non avendo nessun meccanismo di notifica dei cambiamenti, Application dovrà ricordarsi di invocare Update per riversare le informazioni contenute nelle Entity nel data source corrispondente altrimenti si otterrebbe un’inconsistenza.

Inoltre non avendo uno Unit of work dovremo farci carico della consistenza del blocco di aggiornamenti:

  • se si tratta di un singolo aggiornamento di un Aggregate in un Repository (caso comune) è sufficiente che la transazione sia definita dentro il Repository stesso
  • se si tratta di aggiornamenti di molteplici Aggregate di diversi Repository è necessario aprire una TransactionScope in Application prima di eseguire i vari Update
  • se si tratta di aggiornamenti di molteplici Aggregate con data source eterogenei è invece necessario prevedere un sistema di compensazione implementando il Command Pattern. Si potrebbe anche valutare l’uso del Distributed Transaction Coordinator

Lo svantaggio di questo approccio è che si delega al programmatore garantire che i metodi di update verso il repository siano 1) invocati correttamente 2) implementati correttamente. Per ridurre tale svantaggio si potrebbe trattare un solo singolo update per l’intero aggregato richiamato dall’Aggregate stesso (applicabile finquando salvare l’intero aggregato si mantiene in limiti di complessità accettabili e finquando abbiamo tutte le informazioni su cosa è cambiato).

Quale usare?

Questa tabella non scientifica cerca di riassumere i pro/contro dell’approccio

Repository standard Repository grana grossa Repository con update
Applicabilità Solo db, buon ORM Code gen (PostSharp, T4) Poco refactoring (no XP)
Skill Alto Medio Basso
Investimento Alto Medio Basso
Manutenibilità Alta Media Bassa

Mettiamo insieme i pezzi…

Vediamo come si rimappa il flusso esposto all’inizio con la soluzione “Repository con update” facendo a meno del Domain Service e immaginando il caso in cui nel caso d’uso si debba aggiornare molteplici Aggregate:

  1. Application ottiene dai Repository i vari Aggregate richiesti
  2. Aggregate coordina il comportamento desiderato delegando le varie sottofunzioni alle varie Entity o Value Object in stile OO. Se necessario esegue logica specifica del caso d’uso
  3. Entity o Value Object alterano il proprio stato
  4. Application apre un TransactionScope e richiede a seconda del caso d’uso l’update o add/remove dai Repository
  5. Repository esegue la corrispondente query
  6. Application richiede il commit del TransactionScope e lo chiude

Se invece ci limitiamo a considerare il semplice caso di aggiornamento di un singolo Aggregate il flusso si riduce come segue:

  1. Application ottiene dai Repository i vari Aggregate richiesti
  2. Aggregate coordina il comportamento desiderato delegando le varie sottofunzioni alle varie Entity o Value Object in stile OO. Se necessario esegue logica specifica del caso d’uso
  3. Entity o Value Object alterano il proprio stato
  4. Application richiede a seconda del caso d’uso l’update o add/remove dai Repository
  5. Repository esegue la corrispondente query nella transazione del DAO sottostante
    • Se coinvolge più aggregati si potrebbe sempre creare un unico metodo nel repository Update(AggregateA a, AggregateB b) che aggiorna entrambi gli aggregati senza dover introdurre lo Unit of work o il TransactionScope

Tramite questa strategia si riesce a ottenere il DDD anche in condizioni non ideali (data source eterogenei, ORM non possibili, team non skillato) senza appesantire eccessivamente la gestione, pur pagando in prospettiva in costi di manutenibilità. Questo implica che un modello di programmazione agile come l’XP non è proponibile poiché non è possibile essere aggressivi con il refactoring.

Appendice: esempio di codice

Si riporta un esempio di codice della soluzione “Repository con update” senza unit of work, con un metodo nel Repository che coinvolge più aggregati e che fa uso del Dependency Injection senza interfacce come illustrato nel precedente articolo:

Posted in .net | 7 Comments »

Performance in Left Join e Condizioni Multiple (COALESCE)

Posted by Ricibald on February 25th, 2014

A volte SQL Server produce degli execution plan, come dire… discutibili??

Un esempio è dato dall’operatore COALESCE e LEFT JOIN. Quando si lavora con tabelle molto grandi la query si traduce in un TableScan di milioni di righe laddove non previsto.

Esempio concreto:

SELECT *
    FROM BigTable X
    LEFT JOIN BigTable Y ON X.Id = COALESCE(Y.ParentId, Y.Id)
    WHERE X.Name = 'Something'

La query produce un execution plan che prevede un TableScan su una tabella di milioni di record. Il risultato sono minuti e minuti di attesa…

La stessa query potrebbe essere riscritta come segue per migliorare il risultato:

SELECT *
    FROM BigTable X
    LEFT JOIN BigTable Y ON 
        (Y.ParentId IS NOT NULL AND X.Id = Y.ParentId)      -- condizione 1
        OR
        (Y.ParentId IS NULL AND X.Id = Y.Id)                -- condizione 2
    WHERE X.Name = 'Something'

A volte questo workaround funziona, altre volte no. In questi casi sfortunati dovremmo scrivere la query come segue:

SELECT *
    FROM BigTable X                                         -- condizione 1
    JOIN BigTable Y ON Y.ParentId IS NOT NULL AND X.Id = Y.ParentId
    WHERE X.Name = 'Something'
UNION ALL
SELECT *
    FROM BigTable X                                         -- condizione 2
    JOIN BigTable Y ON Y.ParentId IS NULL AND X.Id = Y.Id
    WHERE X.Name = 'Something'
UNION ALL
SELECT X.*, Y1.*                                            -- no match
    FROM BigTable X
    LEFT JOIN BigTable Y1 ON Y.ParentId IS NOT NULL AND X.Id = Y1.ParentId
    LEFT JOIN BigTable Y2 ON Y.ParentId IS NULL AND X.Id = Y2.Id
    WHERE X.Name = 'Something' AND Y1.Id IS NULL AND Y2.Id IS NULL

Riscrivendo in questo modo (semplicissimo) la query avremo delle ottime performance. E meno male che dicono che SQL è un linguaggio dichiarativo…!!

Posted in .net | 1 Comment »

Quick Debug a Value (Chaining)

Posted by Ricibald on January 24th, 2014

This code fails on method Pay:

Customer customer = repository.GetCustomer(id);
customer.GetOpenOrders().GetLatestOrderItem().Pay();

You have to debug the result value of the method GetOpenOrders. To accomplish this you have to add one row to split the statement:

Customer customer = repository.GetCustomer(id);
IEnumerable<Order> openOrders = customer.GetOpenOrders();   // BREAKPOINT HERE
openOrders.GetLatestOrderItem().Pay();

Having one more row we can now add a breakpoint on row 2. This approach requires to rewrite the statement.
Just adding this extension method we can now debug every value:

[System.Diagnostics.DebuggerStepThrough]
public static T Break<T>(this T t) {
    Debugger.Break();
    return t;
}

Just use in this way:

Customer customer = repository.GetCustomer(id);
customer.GetOpenOrders().Break().GetLatestOrderItem().Pay();

No new rows, just chaining :-)!!

Posted in .net | 22 Comments »