Versione per la stampa       Invia     
Valuta il contenuto e lascia un commento
Related Articles

In questo articolo viene illustrato in che modo .NET Services all'interno di Azure Services Platform consente di semplificare il flusso di lavoro delle applicazioni per il cloud computing.

Aaron Skonnard

MSDN Magazine Aprile 2009

...

Read more!

Udi Dahan spiega il modo in cui il suo team ha identificato e superato problemi imprevisti durante lo sviluppo di un software su larga scala e l'applicazione finanziaria dei servizi.

Udi Dahan

MSDN Magazine Aprile 2009

...

Read more!

In questo articolo viene spiegato come integrare una soluzione basata sui Servizi Windows con SharePoint. Il risultato consente il provisioning, l'avvio, l'interruzione e la rimozione delle istanze di servizio tramite Amministrazione centrale SharePoint 3.0.

Pav Cherny

MSDN Magazine Aprile 2009

...

Read more!

Il bus del servizio .NET è probabilmente l'elemento più accessibile, potente e utile della nuova iniziativa di cloud computing di Windows Azure. Ecco come è in grado di gestire le comunicazioni cloud.

Juval Lowy

MSDN Magazine Aprile 2009

...

Read more!

L'utilizzo della memoria può influire direttamente sulla velocità di esecuzione delle applicazioni ed è pertanto un fattore importante da ottimizzare. In questo articolo vengono illustrate le nozioni di base sull'ottimizzazione della memoria per programmi .NET.

Subramanian Ramaswamy e Vance Morrison

MSDN Magazine Giugno 2009

...

Read more!

Also by this Author

Questo mese Dino affronta il problema relativo ai download di grandi dimensioni per le applicazioni Silverlight e spiega quando utilizzare lo streaming, quando dividere il download e altre tecniche per ottenere le prestazioni migliori in rete.

Dino Esposito

MSDN Magazine Gennaio 2009

...

Read more!

Dino Esposito confronta l'uso di modelli AJAX e manipolazioni del DOM con l'uso del motore di rendering parziale di ASP.NET.

Dino Esposito

MSDN Magazine Agosto 2008

...

Read more!

AJAX è stato pensato per molto più del semplice rendering della pagina parziale. Ecco il futuro delle pagine dinamiche con ASP.NET AJAX secondo Dino Esposito.

Dino Esposito

MSDN Magazine Giugno 2008

...

Read more!

Nel numero di questo mese vengono presi in esame i moduli nel contesto di applicazioni AJAX e vari approcci all'implementazione di funzionalità quali: salvataggio automatico, convalida just-in-time e limitazione dell'invio.

Dino Esposito

MSDN Magazine Giugno 2009

...

Read more!

Tra le applicazioni Silverlight 2 basate su Web e le applicazioni desktop WPF esiste una forte somiglianza. In questo articolo Dino si occupa di come riutilizzare con facilità il codice tra le due applicazioni.

Dino Esposito

MSDN Magazine Ottobre 2008

...

Read more!

Popular Articles

È ora possibile eseguire un'analisi del testo efficace e altamente sofisticata utilizzando le espressioni regolari in SQL Server 2005.

David Banister

MSDN Magazine February 2007

...

Read more!

Chris Tavares spiega come il modello Model View Controller di ASP.NET MVC Framework aiuti a creare applicazioni Web flessibili e facilmente verificabili.

Chris Tavares

MSDN Magazine March 2008

...

Read more!

Le password OTP offrono soluzioni per gli attacchi con dizionario, phishing, l'intercettazione e molte altre violazioni della sicurezza. Di seguito ne viene illustrata la modalità di funzionamento.

Dan Griffin

MSDN Magazine May 2008

...

Read more!

In questo articolo vengono presentati i vantaggi della creazione delle applicazioni composite con l'ausilio del documento Composite Application Guidance for WPF, pubblicato dal team Microsoft responsabile dei modelli e delle procedure.

Glenn Block

MSDN Magazine Settembre 2008

...

Read more!

C# allows developers to embed XML comments into their source files-a useful facility, especially when more than one programmer is working on the same code. The C# parser can expand these XML tags to provide additional information and export them to an external document for further processing. This article shows how to use XML comments and explains the relevant tags. The author demonstrates how to set up your project to export your XML comments into convenient documentation for the benefit of other developers. He also shows how to use comments ...

Read more!

Cutting Edge
Flussi di lavoro transazionali
Dino Esposito

Download codice disponibile in: CuttingEdge2007_06.exe (182 KB)
Browse the Code Online
Windows® Workflow Foundation, un pilastro di Microsoft® .NET Framework 3.0, fornisce il modello di programmazione, il motore di runtime e una serie di strumenti per lo sviluppo dei flussi di lavoro che è possibile incorporare in applicazioni basate su .NET o esporre come servizi in client interessati. Quando è necessario un flusso di lavoro in una soluzione personalizzata?
Un flusso di lavoro è utile quando la logica aziendale e le regole sono soggette a frequenti modifiche e cioè quando si personalizza un'applicazione in base alle esigenze dei clienti o se il cliente ha richiesto specificatamente questo tipo di flessibilità. Un flusso di lavoro può stare alla base di un server BPM (Business Process Management) per la gestione di servizi aziendali esposti ai moduli di un'applicazione distribuita e complessa. Infine, un flusso di lavoro consente di supportare l'implementazione di un qualsiasi tipo di logica aziendale a lungo termine.
Dal punto di vista di uno sviluppatore, un flusso di lavoro rappresenta un insieme di attività che esprimono un comportamento desiderato. Quando richiamato per modellare una logica aziendale, un flusso di lavoro si riduce inevitabilmente a un insieme di attività transazionali. Come è possibile codificare la semantica transazionale in Windows Workflow Foundation?
Quasi tutti i sistemi aziendali dispongono di un flusso di lavoro per occuparsi di problemi particolarmente complessi e quasi tutti i problemi complessi includono una transazione. Esistono due tipi principali di transazioni da gestire. Un tipo contiene le classiche transazioni brevi che spesso sono indicate come transazioni ACID. L'altro tipo può essere descritto come transazione globale, aziendale a esecuzione prolungata. Questo genere di transazione fa spesso parte di un processo aziendale e può essere composto da più transazioni ACID. L'esito positivo o negativo di queste transazioni ACID contribuisce ai risultati globali del processo aziendale rappresentato dal flusso di lavoro.
Windows Workflow Foundation fornisce attività ad hoc per rendere l'implementazione di transazioni aziendali e ACID non solo efficace ma semplice da codificare e aggiornare. In quest'articolo, mi occuperò delle attività che forniscono operazioni transazionali che è possibile creare in un flusso di lavoro Windows Workflow Foundation.

Classificazione delle attività transazionali
Un flusso di lavoro di Windows Workflow Foundation può contenere uno o più blocchi di attività da considerare come attività atomiche. Una volta racchiuse queste attività in un blocco transazionale più esterno, il runtime di Windows Workflow Foundation garantisce l'esito positivo o negativo di tutte le attività in esso contenute. Tali transazioni vengono definite transazioni ACID, acronimo derivante dalla descrizione del comportamento previsto: Atomic (atomica), Consistent (consistente), Isolated (isolata) e Durable (duratura) (vedere la Figura 1).

Funzionalità Descrizione
Atomic Tutte le operazioni della transazione vengono completate o con esito positivo o con esito negativo.
Consistent Le risorse interessate dalla transazione devono trovarsi in uno stato adeguato quando la transazione inizia e quando termina. La transazione non può violare i vincoli di integrità o le regole aziendali.
Isolated Le operazioni nella transazione vengono visualizzate separatamente da tutte le altre operazioni. Nessuna operazione esterna alla transazione visualizza i dati in uno stato intermedio.
Durable Una volta terminata la transazione, gli effetti sono permanenti e non possono essere annullati.
Un intero flusso di lavoro di Windows Workflow Foundation può essere anche considerato come un'unica transazione a esecuzione prolungata (LRT). In questo caso, è possibile utilizzare la semantica del flusso di lavoro per descrivere un processo aziendale o una sua parte, in cui sono coinvolti più servizi, piattaforme di software distinte e aziende diverse. Una transazione LRT può impiegare minuti, giorni o anche settimane prima di restituire un risultato. Il processo può implementare un'operazione a più fasi ed essere suddiviso su sistemi di informazioni di più società. In genere, una transazione LRT è composta da una o più transazioni ACID che riescono o meno indipendentemente l'una dalle altre. Tuttavia, considerato che il processo è lungo e complesso, può accadere che una fase ulteriore nel processo determini una condizione incompatibile con il risultato di una transazione ACID precedente. A questo punto è troppo tardi per eseguire il rollback dei risultati di una transazione già eseguita, ma gli effetti devono essere compensati.
Sebbene il termine "transazione" venga comunemente utilizzato per definire sia processi ACID che a esecuzione prolungata, esiste una differenza netta tra i due. Il termine transazione fa riferimento solitamente a una sequenza di operazioni da eseguire e considerare come un'unità di lavoro. L'operazione termina generalmente in pochi secondi e non prevede mai una sospensione né un'attesa prolungata per l'input utente o altri interventi. Non richiede persistenza e viene considerata come un'unica operazione "all-or-nothing". Come si noterà in seguito, la descrizione di cosa costituisce una transazione tipica è essenzialmente la descrizione di una transazione ACID.
Cos'è esattamente una transazione a esecuzione prolungata? È essenzialmente una transazione ACID che dura più a lungo e può essere sospesa e ripresa quando richiesto? Una transazione a esecuzione prolungata è un'estensione più flessibile del termine transazione. Una LRT è una serie coesiva di azioni che coinvolgono sistemi indipendenti e associati.
L'aspetto dell'esecuzione prolungata di alcune transazioni può rendere la gestione di queste transazioni come transazioni ACID più complessa se non del tutto impossibile. Le transazioni ACID richiedono spesso che alcuni dati critici siano bloccati per la durata della transazione, il che non è un problema per le transazioni che impiegano solo pochi secondi. Ma se una delle risorse coinvolte in una determinata transazione aziendale non può essere bloccata per l'intera durata del processo, il modello ACID non è adatto. Le diverse operazioni devono essere completate come operazioni indipendenti con una certa logica per poter gestire le azioni e i risultati e devono essere pronte a compensare eventuali errori, se necessario. La logica di orchestrazione può essere generata in un flusso di lavoro di Windows Workflow Foundation che agisce da server BPM o in un'attività complessa di Windows Workflow Foundation che viene utilizzata in seguito come un flusso di lavoro esterno.

Transazioni ACID nei flussi di lavoro
Una transazione ACID è una transazione breve nella quale la decisione di eseguire il commit o il rollback viene presa in pochi secondi. La logica di rollback deve essere in grado di annullare l'operazione in corso e tutte le relative fasi intermedie e deve compensare l'effetto delle operazioni precedenti. L'utente non si accorge di nulla. La transazione di database tipica codificata in una stored procedure che funziona in modo atomico su due o tre tabelle rappresenta l'esempio perfetto di una transazione ACID.
Una transazione ACID può essere locale o distribuita. Una transazione locale coinvolge una sola risorsa, ad esempio il database al quale è connessa. Una transazione distribuita utilizza più risorse eterogenee e richiede un monitor dell'elaborazione delle transazioni. Il coordinatore DTC (Distributed Transaction Coordinator) è il monitor dell'elaborazione delle transazioni per Microsoft Windows 2000 e per le versioni successive di Windows.
Per creare un segmento transazionale in un flusso di lavoro, è possibile utilizzare l'attività TransactionScope (vedere la Figura 2). Tutte le attività composte nell'ambito della transazione formano un'unità di lavoro che rispetta il classico schema ACID. Una volta che tutte le attività figlio sono state completate correttamente, la transazione riesce e il flusso di lavoro procede. Se viene generata un'eccezione da una delle attività figlio, l'attività TransactionScope esegue un'operazione di rollback.
Figura 2 Attività TransactionScope in Visual Studio 2005 (Fare clic sull'immagine per ingrandirla)
Il flusso di lavoro di esempio illustrato nella Figura 2 accetta un numero d'ordine e procede con il pagamento. La somma di denaro viene ritirata dal conto del cliente e aggiunta al conto del fornitore. L'operazione deve essere eseguita in modo atomico perché entrambe le fasi abbiano esito positivo o negativo. In entrambi i casi, le risorse coinvolte devono trovarsi in uno stato consistente nel quale nessun vincolo viene violato e l'integrità dei dati è garantita.
Le fasi interne sono trasparenti sia per lo sviluppatore che per l'utente finale. In teoria, nessun componente software esterno dovrebbe accedere allo stato di nessuna risorsa transazionale prima che questo venga finalizzato (questo vincolo viene a volte ignorato per motivi legati alle prestazioni a spese della correttezza). L'isolamento, quindi, richiede una transazione serializzabile sottostante che è il tipo più costoso di transazione che i database e i gestori di risorse simili supportano.

Esplorazione dell'attività TransactionScope
In Windows Workflow Foundation, l'attività TransactionScope viene utilizzata come contenitore di attività figlio che vengono eseguite in sequenza e in pieno rispetto della semantica ACID. Se si utilizza l'attività Parallel in una transazione, le attività vengono eseguite contemporaneamente nell'ambito dell'attività e in sequenza nel resto della transazione.
L'attività TransactionScope espone due proprietà che è possibile utilizzare in modo dichiarativo per configurare la transazione: IsolationLevel e TimeoutDuration. La proprietà IsolationLevel è di tipo IsolationLevel: una numerazione definita nello spazio dei nomi System.Transactions. Il livello di isolamento di una transazione determina il livello di accesso di cui altre transazioni dispongono ai dati interni prima del completamento di una transazione. Nella Figura 3 viene illustrato cosa accade con i livelli più comunemente utilizzati.

Livello Descrizione
READ UNCOMMITTED Il livello meno restrittivo che ignora i blocchi impostati da altre transazioni. È possibile leggere i dati modificati non ancora sottoposti a commit da altre transazioni (letture improprie).
READ COMMITTED Il livello di isolamento predefinito per SQL Server che impedisce le letture improprie. Tuttavia, consente alle transazioni di modificare, inserire o eliminare i dati nella transazione corrente. Ciò può produrre letture non ripetibili e righe fantasma.
REPEATABLE READ Questo livello evita le letture improprie e impedisce alle altre transazioni di modificare o eliminare i dati letti dalla transazione corrente. È possibile inserire nuovi dati.
SERIALIZABLE Il livello più restrittivo che mantiene i blocchi finché la transazione viene completata. Non sono consentite letture né aggiornamenti finché la transazione viene completata.
SNAPSHOT Soltanto per SQL Server 2005 questo livello specifica che i dati letti all'interno di una transazione non rifletteranno mai le modifiche apportate da altre transazioni simultanee.
CHAOS In questo caso, non è possibile sovrascrivere le modifiche in sospeso apportate da transazioni più isolate.
Il valore predefinito per IsolationLevel è Serializable. Si tratta dell'opzione più sicura e costosa, che non è necessariamente richiesta in tutti i casi. Una transazione serializzabile blocca i dati per la durata della transazione evitando alle altre transazioni eseguite contemporaneamente di accedere agli stessi dati. L'attività TransactionScope, tuttavia, ridimensiona gli effetti di quest'opzione impostando un timeout di 30 secondi. Se la simultaneità è fonte di preoccupazione e si desidera eseguire transazioni in SQL Server™ 2005, è possibile scegliere il nuovo livello di isolamento dello snapshot. A differenza di altri livelli di isolamento, l'isolamento dello snapshot non viene impostato solo a livello di programmazione. È possibile applicarlo ai database SQL Server 2005, se l'amministratore lo configura utilizzando la seguente istruzione:
ALTER DATABASE <name> SET ALLOW_SNAPSHOT_ISOLATION ON
L'attività TransactionScope è un wrapper creato su un'istanza della classe TransactionScope di .NET Framework 2.0, una delle classi più semplici per i programmatori mai progettata. È sufficiente racchiudere tutto in un oggetto TransactionScope e il gioco è fatto. L'oggetto si occupa di tutto il resto. Determina se è necessaria una transazione locale o distribuita, integra tutte le risorse distribuite necessarie e procede con l'elaborazione locale. Quando il codice raggiunge un punto in cui non può essere eseguito localmente, l'oggetto passa al DTC interessato.
È possibile integrare qualsiasi oggetto con una transazione che implementa l'interfaccia ITransaction. L'elenco contiene tutti i provider di dati ADO.NET 2.0, così come Microsoft Message Queue (MSMQ).
Quando il codice richiama il metodo Complete dell'oggetto TransactionScope, indica che tutte le operazioni nell'ambito della transazione sono state completate correttamente. Si noti che il metodo non completa fisicamente una transazione distribuita, poiché l'operazione di commit si verifica al momento dell'eliminazione di TransactionScope. Tuttavia, una volta richiamato il metodo Complete, è possibile non utilizzare più la transazione distribuita.
L'attività TransactionScope rende le attività transazionali altrettanto facili rispetto alle attività di raggruppamento nella finestra di progettazione di Visual Studio®. Si prenda in considerazione il codice presente nelle attività illustrate nella Figura 2. Il codice principale è illustrato nella Figura 4.
private void WithdrawFunds_ExecuteCode(object sender, EventArgs e)
{
    Console.WriteLine(“Funds withdrawn to process order: #” + 
        orderNo.ToString());

    // Execute a SQL operation on ClientAccount
    SqlHelper.ExecuteNonQuery(conn,
        System.Data.CommandType.Text,
        “use bank update ClientAccount set Balance = Balance - 100”);
}

private void AddFunds_ToVendor_ExecuteCode(object sender, EventArgs e)
{
    Console.WriteLine(“Funds added to the vendor’s account for order #” + 
        orderNo.ToString());

    // Execute a SQL operation on VendorAccount
    SqlHelper.ExecuteNonQuery(conn,
        System.Data.CommandType.Text,
        “use bank update VendorAccount set Balance = Balance + 100”);
}
Il codice transazionale contiene tre attività Code. La prima esegue un comando di database e aggiorna il bilancio del conto client sottraendo una determinata somma. In seguito, la stessa somma viene aggiunta al conto del fornitore. Considerate le caratteristiche dell'oggetto TransactionScope sottostante, i database possono essere distribuiti facilmente.
Ancora più importante, il trasferimento dei fondi deve essere un'operazione atomica. Se il flusso di esecuzione raggiunge la fine dell'attività TransactionScope, la transazione termina con esito positivo ed esegue il commit. Se viene generata un'eccezione in qualsiasi momento, la transazione esegue automaticamente il rollback del lavoro eseguito. Tutte queste operazioni sono visibili allo sviluppatore del flusso di lavoro. In qualità di sviluppatore del flusso di lavoro, non è necessario occuparsi della compensazione o della gestione degli errori.
Il codice di esempio genera un'eccezione se il numero d'ordine è strano, come mostra il codice dell'ultima attività nella Figura 2:
void CheckConsistency_ExecuteCode(object sender, EventArgs e)
{
    if (orderNo % 2 > 0)
        throw new DiscontinuedProductException();
}
L'eccezione generata è un oggetto eccezione personalizzato che descrive una determinata situazione nell'applicazione. È sufficiente attivare il meccanismo di rollback dell'oggetto TransactionScope di .NET sottostante. Nella Figura 5 viene illustrata l'applicazione in azione e il messaggio ricevuto in caso di rollback. Nella Figura 6 viene illustrata una transazione che termina con esito positivo sottoposta a commit.
Figura 6 Commit del trasferimento di denaro (Fare clic sull'immagine per ingrandirla)
Figura 5 Annullamento del trasferimento di denaro (Fare clic sull'immagine per ingrandirla)
Se si desidera rilevare le eccezioni che derivano dal flusso di lavoro e in particolare dall'attività TransactionScope, passare alla vista dei gestori di errori e aggiungere un'attività FaultHandler. È possibile in seguito configurare l'attività in modo da rilevare determinati tipi di eccezioni e aggiungere le attività necessarie per gestire l'eccezione. Questo non ha molto senso in uno scenario ACID, ma in generale è possibile eseguire un'altra transazione mentre si gestisce l'eccezione. Lo scopo del gestore di errori è di eliminare il lavoro parziale e inutile di un'attività in cui si è verificata un'eccezione. Tuttavia, per quanto riguarda l'ambito di una transazione, il rollback è automatico e non è necessario scrivere comandi SQL ad hoc per annullare gli effetti delle operazioni di database precedenti.

Configurazione di un flusso di lavoro per l'esecuzione
Esistono poche restrizioni all'uso dell'attività TransactionScope di cui è necessario essere a conoscenza. Primo, non è possibile sospendere il flusso di lavoro da una transazione utilizzando l'attività Suspend. Inoltre, non è possibile nidificare un'attività TransactionScope in un'altra attività TransactionScope o in altre attività che implementano l'interfaccia ICompensatableActivity. Le attività CompensatableTransactionScope e CompensatableSequence nella casella degli strumenti sono due esempi di queste attività.
Un flusso di lavoro transazionale richiede un servizio di persistenza. Se non è disponibile nessun servizio viene generata un'eccezione. È possibile registrare un servizio di persistenza con il runtime del flusso di lavoro nell'applicazione client nel seguente modo:
string conn = “...”;
workflowRuntime.AddService(
    new SqlWorkflowPersistenceService(conn));
La classe SqlWorkflowPersistenceService è il servizio di persistenza predefinito ed è basata su un database SQL Server. La persistenza si verifica quando una transazione ACID termina o quando l'istanza del flusso di lavoro viene interrotta o scaricata a livello di programmazione. Il motore di runtime del flusso di lavoro richiama i metodi sul servizio di persistenza per salvare lo stato dell'istanza del flusso di lavoro. Il motore di runtime del flusso di lavoro determina quando e come eseguire la persistenza. Il servizio si occupa di salvare e caricare lo stato del flusso di lavoro nell'archivio e dall'archivio dati scelto.
Il database utilizzato dalla classe SqlWorkflowPersistenceService non viene creato al momento dell'installazione ma gli script vengono copiati sul computer client per un uso futuro. Il percorso dello script è:
%WINDOWS%\Microsoft.NET\Framework\v3.0\Windows Workflow Foundation\SQL
È possibile modificare il nome predefinito del database. Tuttavia, non è possibile modificare la struttura delle tabelle figlio. Per utilizzare una struttura differente del database, è necessario un servizio di persistenza personalizzato. Essenzialmente un servizio di persistenza personalizzato è una classe che eredita da WorkflowPersistenceService.

Modellamento dei processi aziendali con Windows Workflow Foundation
Una transazione ACID è soltanto una piccola parte di un flusso di lavoro. Più transazioni ACID sono generalmente combinate in un unico flusso di lavoro per esprimere un determinato processo aziendale. Può capitare che un'attività transazionale termini con esito positivo, ma viene generata un'eccezione in un'altra attività del flusso di lavoro. In questo caso, non è possibile alcun rollback automatico. Il rollback è possibile nel contesto di una transazione poiché esiste una funzione di gestione risorse che consente di rilevare le operazioni ed eliminarle se necessario. I flussi di lavoro, tuttavia, non supportano la semantica transazionale, ma solo le attività transazionali.
Quando si utilizza Windows Workflow Foundation per modellare un processo aziendale, è possibile che si verifichino diversi blocchi durante il flusso di lavoro. Windows Workflow Foundation mette a disposizione due tipi di attività transazionali: le transazioni ACID e le transazioni compensabili. Le transazioni ACID sono rappresentate dall'attività TransactionScope. Eseguono generalmente il commit o il rollback e i relativi risultati vengono mantenuti. Ma cosa accade se è necessario implementare le attività transazionali nel contesto di un processo più esteso nel quale non è possibile bloccare dati troppo a lungo ed è necessario eseguire il rollback dei commit precedenti? Per questo, è necessario un tipo speciale di attività transazionale: CompensatableTransactionScope.
CompensatableTransactionScope supporta un meccanismo di compensazione. La compensazione è una logica che viene eseguita in un qualsiasi momento per annullare, ridurre o compensare gli effetti di operazioni precedenti. Il punto è che la transazione compensabile potrebbe contenere transazioni ACID figlio che, una volta sottoposte a commit, non possono essere più sottoposte a rollback. Tuttavia, in caso di un'ulteriore operazione non riuscita, gli effetti devono essere compensati. La compensazione è simile al rollback con la differenza che lo sviluppatore viene richiamato per scrivere qualsiasi codice utilizzato per compensare il lavoro eseguito. Non tutte le attività transazionali devono essere compensabili. Ad esempio, le attività che possono essere rappresentate con le transazioni ACID non richiedono la compensazione. L'attività TransactionScope, infatti, non supporta la compensazione.
Nella Figura 7 viene illustrato un flusso di lavoro di esempio che utilizza un paio di ambiti della transazione compensabile. Il processo aziendale consente di modellare il ciclo di vita di un ordine. Una volta collocato, l'ordine provoca la modifica della carta di credito del cliente (attività denominata Scope_ChargeCreditCard) e sposta il denaro sul conto bancario del fornitore (attività denominata Scope_PayOrder). Entrambe le attività sono transazionali e compensabili. Supponiamo che successivamente si verifichi un'eccezione nel flusso di lavoro perché, ad esempio, il prodotto ordinato non è più disponibile. A questo punto, si verifica un'eccezione aziendale e tutte le operazioni eseguite fino a quel momento devono essere annullate. L'effetto di una qualsiasi transazione ACID sottoposta a commit e sequenza non transazionale di attività deve essere compensato. Ogni attività della sequenza o transazione compensabile include una logica che consente di annullare completamente o in parte il lavoro eseguito.
Figura 7 Transazioni compensabili 
In Windows Workflow Foundation, è possibile definire il codice di annullamento per ciascuna attività compensabile passando dalla vista dell'attività alla vista del gestore di compensazione (vedere la Figura 8). Nella vista del gestore di compensazione è possibile elencare tutte le attività necessarie per annullare l'effetto dell'operazione.
Figura 8 Aggiunta di logica di compensazione alle sequenze del flusso di lavoro (Fare clic sull'immagine per ingrandirla)
Il concetto di compensazione è simile al concetto di rollback. Tuttavia, mentre il rollback è un'operazione puramente transazionale, la compensazione si applica alle sequenze transazionali e non transazionali di operazioni. Se si confrontano le Figure 7 e 8, si noterà un'interfaccia leggermente diversa per i due ambiti transazionali compensabili. Nella Figura 8, invece del codice diretto, si vede il codice di compensazione.

Informazioni sulla compensazione
Una domanda da porsi è perché è necessario eseguire la compensazione. Non basta eseguire un'unica grande transazione ACID con il rollback automatico? Una transazione ACID è più adatta quando le operazioni si verificano nello stesso database o nello stesso sistema di informazioni. E lo è anche quando le operazioni durano poco. Quando sono coinvolti diverse aziende e servizi, la definizione del processo in termini di semantica ACID può essere difficile. Perché il processo sia isolato e solido, è necessario tenere bloccate tutte le risorse delle diverse aziende per la durata dell'attività. Questo è spesso impossibile, specialmente se l'attività richiede molto tempo. Perché il processo sia consistente e atomico, è necessario un codice di compensazione ad hoc.
Un'altra domanda da porsi è chi attiva il codice di compensazione. Grazie alla gestione degli errori, è possibile gestire una o più eccezioni generate dal flusso di lavoro. Il gestore di tali eccezioni è un'altra attività speciale: l'attività Compensate (vedere la Figura 9). L'attività Compensate attiva il codice che consente di modificare i vincoli e le regole aziendali messe a rischio da un'eccezione aziendale. È necessario associare l'attività Compensate a un'attività compensabile del flusso di lavoro. A tal fine è possibile utilizzare la proprietà TargetActivityName nella finestra di progettazione di Visual Studio 2005 Workflow Extensions. Se si imposta la proprietà TargetActivityName sul nome di una determinata transazione o sequenza, verrà compensata solo tale transazione o sequenza. È possibile aggiungere più attività Compensate e stabilire l'ordine e la granularità con cui deve verificarsi la compensazione. Se si desidera eseguire la logica di compensazione che richiama la logica di rollback di una transazione ACID classica, è necessario associare l'attività Compensate all'intero flusso di lavoro. In questo caso, la compensazione procede dal basso verso l'alto partendo dal punto in cui si è verificata l'eccezione alla radice del flusso di lavoro.
Figura 9 Attività Compensate 
Il codice di compensazione può avviare transazioni ACID aggiuntive per bilanciare gli effetti del flusso di lavoro. Inoltre, la compensazione potrebbe non riuscire. Quindi, per essere al sicuro, è necessario preparare gestori eccezioni adeguati anche per il codice di compensazione.

Prestazioni e transazioni del flusso di lavoro
Uno dei fattori che ha l'impatto maggiore sulle prestazioni di un flusso di lavoro di Windows Workflow Foundation è la persistenza. Un flusso di lavoro può avere diversi punti di persistenza, alcuni definiti esplicitamente dai programmatori, altri implicitamente richiesti dalle attività incorporate e personalizzate. Il servizio di persistenza viene automaticamente richiamato quando il flusso di lavoro diventa inattivo, quando viene richiamato il metodo Unload sull'istanza del flusso di lavoro o quando un'attività dotata dell'attributo PersistOnClose viene completata. Entrambe le attività transazionali incorporate definite in Windows Workflow Foundation, TransactionScope e CompensatableTransactionScope, richiedono la persistenza al termine delle operazioni. Pertanto, un servizio di persistenza efficace e, essenzialmente, un ambiente di runtime efficace sono elementi critici per le prestazioni.
Un flusso di lavoro transazionale presenta alcuni requisiti che riguardano gli strumenti di runtime: supporto della persistenza e delle transazioni. Per impostazione predefinita, la classe di servizio DefaultWorkflowCommitWorkBatchService viene utilizzata per gestire le transazioni tramite la classe TransactionScope di .NET. In questo modo, si passa a DTC automaticamente e solo quando richiesto. Tuttavia, esiste uno scenario particolare nel quale il servizio predefinito non va utilizzato per salvaguardare le prestazioni.
Quando si utilizza il servizio di persistenza fornito, è necessario creare un database adeguato, SQL Server 2005 o SQL Server 2000. Il database standard contiene anche tabelle e stored procedure per il servizio di rilevamento standard, la classe SqlTrackingService. Si consideri uno scenario in cui entrambi i servizi sono attivati e condividono lo stesso database, il che vuol dire che si utilizza la stessa stringa di connessione. I dati di persistenza e di rilevamento vengono sempre scritti nella stessa transazione. Se il è SQL Server 2000, tuttavia, si passa a DTC a meno che i servizi condividano lo stesso oggetto di connessione. Così, quando i dati di persistenza e di rilevamento vengono indirizzati nello steso database SQL Server 2000, è necessario utilizzare SharedConnectionWorkflowCommitWorkBatchService invece del servizio predefinito. È possibile aggiungere questi servizi al runtime del flusso di lavoro nel modo seguente:
workflowRuntime.AddService(
    new SqlWorkflowPersistenceService(connString)); 
workflowRuntime.AddService(
    new SqlTrackingService(connString));
workflowRuntime.AddService(
    new SharedConnectionWorkflowCommitWorkBatchService(connString));
Il servizio SharedConnectionWorkflowCommitWorkBatchService ottimizza le prestazioni del flusso di lavoro soltanto in questo scenario particolare, poiché impedisce l'overhead di connessioni extra al database e alle transazioni DTC. Se il flusso di lavoro transazionale non richiede il servizio di rilevamento o se utilizza database separati per il rilevamento e la persistenza, è preferibile mantenere il servizio predefinito per il supporto delle transazioni.
È mio dovere far notare che il servizio di rilevamento e il servizio di persistenza funzionano sempre nella stessa transazione. Il servizio di rilevamento presenta una proprietà booleana denominata IsTransactional. Impostando la proprietà su false il servizio di rilevamento non diventa non transazionale. Più semplicemente, ciò significa che i dati di rilevamento vengono salvati quando il metodo corrispondente viene richiamato. Quando IsTransactional è impostato su true (impostazione predefinita), il metodo TrackData del servizio aggiunge dati al batch di lavoro. Il batch di lavoro viene poi inserito nel punto successivo di persistenza del flusso di lavoro.

Conclusioni
Il modellamento delle attività transazionali in Windows Workflow Foundation è abbastanza semplice. Se è necessaria una transazione ACID, cioè atomica, consistente, isolata e duratura, che generi una risposta rapidamente, è necessario utilizzare l'attività TransactionScope. In quest'attività, vengono generate altre attività che accedono agli oggetti integrati nella transazione di ambiente sottostante. Se, d'altra parte, è necessario gestire alcuni servizi associati per modellare un'attività che impiega alcuni minuti, si consiglia di utilizzare CompensatableTransactionScope.
E ricorda che una transazione prevede dei costi a causa della persistenza e delle esigenze di memoria. Se viene richiesta solo la compensazione, si consiglia di scegliere l'attività CompensatableSequence.

Per inviare domande e commenti a Dino, l'indirizzo è  cutting@microsoft.com.


Dino Esposito è un mentore presso Solid Quality Learning e autore di Programming Microsoft ASP.NET 2.0 (Microsoft Press, 2005). Vive in Italia e partecipa spesso come relatore a eventi del settore in tutto il mondo. Contattare Dino all'indirizzo cutting@microsoft.com oppure al blog weblogs.asp.net/despos.

Page view tracker