Introduzione al motore per le regole di Windows Workflow Foundation

Jurgen Willis
Microsoft Corporation

Febbraio 2006

Relativo a:
Windows Workflow Foundation (WF) Beta 2
Visual Studio 2005

Riassunto: in questo articolo viene fornita una panoramica delle funzionalità del motore per le regole in Windows Workflow Foundation (WF). Viene descritto l'utilizzo delle condizioni e degli insiemi di regole in WF e illustrato il comportamento degli insiemi di regole, compresi concatenamento in avanti, rilevamento e analisi (18 pagine stampate). (Alcuni articoli potrebbero essere in inglese).

Nota Questo articolo è stato scritto utilizzando la versione Beta 2 e potrebbe essere modificato in futuro per aggiornarlo rispetto a versioni successive di Windows Workflow Foundation.
Sommario

Introduzione
Panoramica delle regole in Windows Workflow Foundation
Valutazione delle regole
Concatenamento in avanti
Controllo del concatenamento in avanti
Ulteriori informazioni sulla modellazione
Rilevamento e analisi
Conclusioni
Ulteriori informazioni

Introduzione

Grazie a Windows Workflow Foundation (WF), Microsoft ha introdotto nella piattaforma per gli sviluppatori WinFX nuove funzionalità in materia di regole, che vanno dalle semplici condizioni che governano le modalità di esecuzione delle attività fino agli insiemi di regole complessi eseguiti da motori per le regole di concatenamento in avanti completi.

Queste funzionalità consentono la modellazione dichiarativa di unità logiche di applicazioni nell'ambito di un processo aziendale complessivo. Gli scenari di esempio per la tecnologia relativa al motore per le regole comprendono convalida degli ordini, calcolo dei prezzi, applicazione delle promozioni, gestione delle eccezioni nonché decisioni in materia di reclami e attività di gestione inerenti a questi ultimi.

Uno degli obiettivi principali dello sviluppo di questa tecnologia è la perfetta integrazione tra flusso di lavoro e regole. Nel settore, infatti, regole e flusso di lavoro costituivano tecnologie sostanzialmente distinte, normalmente realizzate da fornitori diversi. I motori per le regole di terze parti sono spesso incorporati o integrati da fornitori di soluzioni per la gestione di flussi di lavoro e processi aziendali (BPM, Business Process Management), ma le attività di sviluppo e amministrazione sono, evidentemente, diverse.

Con WF, Microsoft si è impegnata a uniformare l'attività di sviluppo relativa alla modellazione di regole e alla definizione dei flussi di lavoro per consentire agli sviluppatori di incorporarvi facilmente le regole stesse in qualsiasi punto; in questo modo, gli sviluppatori sono in grado di decidere se eseguire la modellazione della logica all'interno del flusso di lavoro, delle regole o del codice senza preoccuparsi delle successive implicazioni in tema di integrazione. Questo risultato è stato ottenuto senza rinunciare alla possibilità di eseguire le regole all'esterno dei flussi di lavoro.

Un altro obiettivo è fornire un modello lineare destinato agli sviluppatori, che potranno utilizzarlo per la definizione delle regole. In passato, quella relativa alle regole è stata spesso una tecnologia di nicchia, impiegata solo da un gruppo ristretto di professionisti altamente specializzati. Mentre i miglioramenti apportati agli strumenti hanno consentito di aumentare il numero delle persone che utilizzano le regole, l'impiego dei modelli spesso imponeva agli utenti un livello di competenza eccessivo nell'implementazione dei meccanismi del motore sottostante. Integrando le funzionalità relative alle regole all'interno della piattaforma, si è scelto un modello comprensibile dalla maggior parte della community degli sviluppatori .NET e, in ultima analisi, anche da chi non si occupa di sviluppo. Sebbene, come per tutte le tecnologie, sarà sempre necessario possedere un certo livello di conoscenze specialistiche, l'obiettivo di Microsoft è consentire a tutti gli sviluppatori .NET di impadronirsi rapidamente del modello delle regole e incorporarlo facilmente nelle proprie applicazioni.

Oltre a fornire un modello comprensibile, WF rende disponibile anche un potente motore di valutazione per il supporto di scenari che prevedono regole complesse, valutazione del concatenamento in avanti particolarmente impegnativa e controllo preciso della valutazione. Tutto ciò è stato realizzato prevedendo vari punti di estendibilità per consentire agli sviluppatori di lavorare sulla piattaforma realizzando funzionalità per le regole compatibili con un ampia gamma di scenari.

In questo documento vengono fornite una presentazione tecnica delle funzionalità relative alle regole offerte da WF e una panoramica delle funzioni disponibili e del loro utilizzo e, al termine, viene riportato un elenco di ulteriori riferimenti che possono essere impiegati per comprendere la funzionalità relativa alle regole di WF.

Panoramica delle regole in Windows Workflow Foundation

WF utilizza la tecnologia relativa alle regole in due modi: come condizioni dalle quali dipendono determinate attività e come insieme di regole per il concatenamento in avanti nell'attività del criterio. Il concatenamento in avanti verrà illustrato successivamente e, in sintesi, si riferisce alla possibilità che hanno le azioni di una regola di causare altre regole dipendenti, che devono essere nuovamente valutate.

Condizioni delle attività

Le condizioni sono utilizzate dalle quattro attività seguenti, previste da WF.

  • IfElseBranch
  • While
  • Replicator
  • ConditionedActivityGroup (CAG)

Le condizioni sono utilizzate per controllare le modalità di comportamento di queste attività, ad esempio, determinare se è necessario eseguire una determinata attività IfElseBranch. È possibile specificare le condizioni come CodeConditions, nel cui codice viene anche configurato un gestore, oppure come RuleConditionReference, che punta a una definizione RuleCondition contenuta nel file .rules associato al flusso di lavoro nel relativo progetto. La figura 1 mostra il procedimento in Visual Studio.

Figura 1. Creazione di condizioni regola in WF

Aggiunta condizioni regola

Di seguito viene descritta la procedura per aggiungere una condizione regola a un'attività IfElseBranch contenuta all'interno di un'attività IfElse.

  1. Quando viene selezionata un'attività contenente una condizione (come l'attività IfElseBranch mostrata) nella griglia Proprietà viene mostrata la proprietà Condition.
  2. L'elenco a discesa corrispondente alla proprietà Condition consente all'utente di scegliere tra CodeCondition e RuleConditionReference.
  3. Scegliendo RuleConditionReference, è possibile espandere la proprietà Condition per visualizzare le proprietà ConditionName ed Expression.
  4. Una volta indicato il nome della condizione, vengono selezionati i puntini di sospensione della proprietà Expression per avviare l'editor delle condizioni regola, grazie al quale gli sviluppatori sono in grado di digitare la condizione sotto forma di testo utilizzando il supporto simile a intellisense. Il testo viene analizzato e convertito nella rappresentazione del modello dell'oggetto associato di RuleCondition.
  5. Scegliendo OK, la definizione RuleCondition viene serializzata nel file <NomeFlussoDiLavoro>.rules, che viene aggiunto al progetto.

Per fare riferimento a campi o proprietà nel flusso di lavoro, è possibile digitare this. nell'editor. Dopo avere digitato il punto, viene visualizzato un menu di tipo intellisense che consente di scegliere i membri del flusso di lavoro (è possibile anche digitare direttamente il membro desiderato). È possibile anche eseguire chiamate nidificate, ad esempio this.order.Total o chiamare metodi statici relativamente ai tipi referenziati digitando il nome della classe seguito da quello del metodo, come nel caso di normale codice.

È possibile creare espressioni utilizzando i seguenti operatori relazionali:

  • Uguale a ("==" o "=")
  • Maggiore di (">")
  • Maggiore o uguale a (">=")
  • Minore di ("<")
  • Minore o uguale a ("<=")

Inoltre, è possibile utilizzare i seguenti operatori aritmetici:

  • Somma ("+")
  • Sottrazione ("-")
  • Moltiplicazione ("*")
  • Divisione ("/")
  • Modulo ("MOD")

I seguenti operatori consentono di combinare/negare le espressioni:

  • AND ("AND", "&&")
  • OR ("OR", "||")
  • NOT ("NOT", "!")
  • AND bit per bit ("&")
  • OR bit per bit ("|")

Il motivo principale per cui è preferibile che gli sviluppatori utilizzino condizioni regola invece di condizioni codice è che le prime diventano parte del modello e possono essere aggiornate automaticamente in fase di runtime, in occasione dell'esecuzione delle istanze del flusso di lavoro. Un ulteriore vantaggio delle condizioni regola è costituito dal fatto che, essendo parte del modello, consentono di realizzare strumenti più sofisticati basati sul modello stesso che ampliano le possibilità di creazione, gestione delle dipendenze, analisi di condizioni incrociate e così via.

Attività del criterio

L'attività del criterio incapsula la definizione e l'esecuzione di un insieme di regole, cioè di più regole che presentano varie semantiche di esecuzione. A loro volta, le regole sono espressioni If-Then-Else che operano sui membri del flusso di lavoro. La situazione descritta è mostrata nella figura 2 ed è analoga a quanto descritto per le condizioni regola.

Figura 2. Creazione di un insieme di regole in WF

Aggiunta di un'attività del criterio

Per configurare un insieme di regole per l'attività del criterio, procedere come descritto di seguito.

  1. Trascinare l'attività del criterio dalla casella degli strumenti nella finestra di progettazione del flusso di lavoro.
  2. Nel campo RuleSetReference viene assegnato un nome all'insieme di regole.
  3. Scegliendo i puntini di sospensione nel campo RuleSet Definition, viene attivato l'editor dell'insieme di regole,
  4. L'editor consente di visualizzare una casella di riepilogo contenente un insieme di regole.
  5. Selezionando una determinata regola, vengono visualizzate la condizione e le azioni Then ed Else corrispondenti nonché varie proprietà aggiuntive.
  6. Come nel caso dell'editor delle condizioni regola, la condizione e le azioni Then ed Else vengono immesse sotto forma di testo e, quindi, analizzate e convertite nella rappresentazione del modello dell'oggetto associato. Inoltre, le regole vengono create rispetto ai membri del flusso di lavoro.
  7. Scegliendo OK, l'insieme di regole viene serializzato nel file .rules associato al flusso di lavoro.

Scegliendo i puntini di sospensione nella proprietà RuleSetReference, viene attivato l'editor che consente di selezionare un insieme di regole esistente oppure aggiungere/rinominare/rimuovere insiemi di regole, come mostrato nella figura 3.

Figura 3. Browser degli insiemi di regole di WF

Valutazione delle regole

A ogni regola dell'insieme è assegnata una priorità, la cui impostazione predefinita è 0. Le regole di un insieme possono essere considerate come una serie ordinata in base alla priorità. L'analizzatore delle regole di WF valuta ciascuna regola e, in base al risultato della valutazione della relativa condizione, esegue le azioni corrispondenti.

Dal punto di vista concettuale, il meccanismo di valutazione può essere descritto dalla procedura seguente.

  1. Definizione dell'elenco delle regole attive.
  2. Determinazione della regola avente la priorità più elevata.
  3. Valutazione della regola ed esecuzione delle azioni Then/Else corrispondenti.
  4. Se le azioni di una regola comportano l'aggiornamento di un campo/proprietà utilizzato da una regola precedente dell'elenco (ossia, da una regola con una priorità più elevata), effettuare una nuova valutazione della regola precedente ed eseguire le azioni corrispondenti. Vengono valutate nuovamente solo le regole che presentano una dipendenza specifica.
  5. Continuazione del processo fino a quando tutte le regole dell'insieme sono state valutate.

La procedura è esemplificata di seguito, supponendo che vi sia il seguente insieme di regole, dove A, B e così via rappresentano i dati del flusso di lavoro.

Regola 4 (Priorità = 4)

                  IF A = 15
                  THEN B = 5
                

Regola 3 (P=3)

                  IF C = 5
                  THEN B = 10
                

Regola 2 (P=2)

                  IF D = 2
                  THEN A = 15
                

Regola 1 (P=1)

                  IF B = 5
                  THEN E = 7
                

Si supponga, inoltre, che i dati in ingresso siano i seguenti:

  • A = 0
  • B = 0
  • C = 5
  • D = 2
  • E = 0

La valutazione viene effettuata come descritto di seguito:

  • Viene valutata la Regola 4, il risultato è false e, poiché non vi sono azioni Else, non viene eseguita alcuna azione.
  • La valutazione della Regola 3 dà come risultato true e, quindi, viene eseguita l'azione corrispondente impostando B = 10. Poiché la Regola 4 non dipende dal valore di B, viene valutata la Regola 2.
  • La valutazione della Regola 2 dà come risultato true e, quindi, viene eseguita l'azione corrispondente impostando A = 15.
  • Poiché, all'interno delle proprie condizioni, la Regola 4 utilizza il valore di A, essa viene nuovamente valutata. Questa volta, il risultato è true e viene eseguita l'azione corrispondente, impostando B = 5, mentre le Regole 2 e 3 non vengono valutate nuovamente, giacché le rispettive condizioni non dipendono dal valore di A. Poiché nessuna regola precedente dipende dal valore di B, viene valutata la Regola 1.
  • La valutazione della Regola 1 restituisce come risultato true e, quindi, viene eseguita l'azione corrispondente impostando E = 7.

I dati risultanti sono:

  • A = 15
  • B = 5
  • C = 5
  • D = 2
  • E = 7

Concatenamento in avanti

Come mostrato in precedenza, il concatenamento è basato sulle dipendenze identificate tra le regole: più specificamente, sulle dipendenze tra le azioni previste da una regola e le condizioni di altre regole. Queste dipendenze possono essere identificate o dichiarate in tre modi diversi:

  • Implicito
  • Basato su attributi
  • Esplicito
Implicito

Le dipendenze implicite vengono identificate automaticamente dal motore. Quando un insieme di regole viene eseguito per la prima volta, ogni regola viene analizzata per determinare i campi/le proprietà letti e scritti, rispettivamente, all'interno delle condizioni e delle azioni. Questa operazione viene effettuata esaminando tanto la condizione quanto le istruzioni previste nelle azioni relative all'espressione. Ad esempio, si supponga di avere definito le seguenti regole.

Regola 1

                  IF this.subtotal > 10000
                  THEN this.discount = .05
                

Regola 2

                  IF this.discount > 0
                  THEN this.total = (1-this.discount) * this.subtotal
                

Il motore valuta le regole e determina che la Regola 1 legge il campo subtotal e scrive nel campo discount. La Regola 2 legge i campi discount e subtotal e scrive nel campo total. Per questo motivo, la Regola 2 presenta una dipendenza dalla Regola 1 e il risultato di questa circostanza è che il motore fa in modo che la Regola 2 venga valutata/nuovamente valutata ogni volta che la Regola 1 esegue la propria azione Then.

Si noti che le dipendenze vengono identificate a livello dei nodi foglia. Si consideri il seguente insieme di regole:

Regola 1

                  IF this.order.Subtotal > 10000
                  THEN this.order.Discount= .05
                

Regola 2

                  IF this.order.Discount > 0
                  THEN this.order.Total = (1-this.order.Discount) * this.order.Subtotal
                

Regola 3

                  IF this.order.CustomerType = "Residential"
                  THEN ...
                

Viene identificata una dipendenza tra le Regole 1 e 2, ma non tra la Regola 3 e le Regole 1 e 2, poiché nessuna di esse aggiorna la proprietà CustomerType. In altri termini, la dipendenza viene identificata in relazione alla proprietà CustomerType e non in base all'oggetto Order.

Mediante il concatenamento implicito, WF effettua la maggior parte dei concatenamenti necessari al posto dell'utente, che non deve modellare esplicitamente gli aggiornamenti e, nella maggior parte dei casi, può non essere consapevole del concatenamento o della necessità di eseguirlo. È prevedibile che questa caratteristica renderà più lineare la modellazione di insiemi di regole complessi e trasformerà il concatenamento in una funzionalità potente, ma sostanzialmente nascosta, del motore sebbene, per gestire scenari più complessi e specifici, siano disponibili altri due meccanismi che governano il concatenamento: quello basato sugli attributi e quello esplicito.

Basato su attributi

Qualora vengano effettuate chiamate di metodi all'interno di regole, diventa difficile valutare in modo deterministico quali operazioni di lettura e scrittura siano eseguite. Per risolvere questo problema, WF prevede tre attributi che possono essere applicati a un metodo per indicare le azioni corrispondenti:

  • RuleRead
  • RuleWrite
  • RuleInvoke

I metodi a cui è assegnato l'attributo RuleRead effettuano la lettura della proprietà indicata. Analogamente, è possibile utilizzare l'attributo RuleWrite per indicare che il metodo effettua l'aggiornamento di un determinato campo o proprietà. Si supponga che le prime due regole enunciate nella sezione relativa alle dipendenze implicite siano riscritte come mostrato di seguito.

Regola 1

                  IF this.subtotal > 10000
                  THEN this.SetDiscount(.05)
                

Regola 2

                  IF this.discount > 0
                  THEN this.total = (1-this.discount) * this.subtotal
                

È possibile assegnare al metodo SetDiscount l'attributo indicato di seguito, che consente al motore di determinare, in base all'uso del campo discount, la dipendenza della Regola 2 dalla Regola 1.

                  [RuleWrite("discount")]
                  void SetDiscount(double requestedDiscount)
                  {
                       ...//some code that updates the discount field
                  }
                

A sua volta, l'attributo RuleInvoke consente di determinare le dipendenze in base alle chiamate a metodi collegati. Ad esempio, si supponga che le regole e i metodi siano stati modificati come indicato di seguito.

Regola 1

                  IF this.subtotal > 10000
                  THEN this.SetDiscountWrapper(.05)
                

Regola 2

                  IF this.discount > 0
                  THEN this.total = (1-this.discount) * this.subtotal
                
                  [RuleInvoke("SetDiscount")]
                  void SetDiscountWrapper(double requestedDiscount)
                  {
                  ...
                  SetDiscount(requestedDiscount);
                  ...
                  }

                  [RuleWrite("discount")]
                  void SetDiscount(double requestedDiscount)
                  {
                  }
                

La condizione della Regola 2 chiama SetDiscountWrapper che, a sua volta, chiama il metodo SetDiscount che effettua la scrittura nel campo discount. L'attributo RuleInvoke consente di dichiarare questa scrittura indiretta e renderla individuabile dal motore.

È importante essere consapevoli del fatto che il campo o la proprietà a cui fa riferimento il percorso dell'attributo corrispondono al campo o alla proprietà della stessa classe del metodo, che non è necessariamente l'oggetto di primo livello passato all'insieme di regole per l'esecuzione. Ad esempio, alla classe Order potrebbe essere assegnato un attributo come indicato di seguito.

                  public class Order
                  {
                  private double discount;

                  public double Discount
                  {
                       get { return discount;}
                       set { discount = value;}
                  }

                  [RuleWrite("Discount")]
                  void CalculateDiscount(double requestedDiscount, double weighting)
                  {
                  ...//some code that updates the discount field
                  }
                  }
                

Inoltre, un'istanza di questa classe potrebbe essere utilizzata in un flusso di lavoro nel modo seguente:

                  public class Workflow1 :  SequentialWorkflowActivity
                  {
                  private Order discount;

                  ...
                  }
                

In questo caso, l'esecuzione della Regola 2 comporterebbe una nuova valutazione della Regola 1.

Regola 1

                  IF this.order.Discount > 5
                  THEN ...
                

Regola 2

                  IF ...
                  THEN this.order.CalculateDiscount( 5.0, .7)
                

Di seguito vengono riportate alcune ulteriori osservazioni sull'utilizzo degli attributi.

  • Gli attributi puntano ai campi/proprietà della classe Owner e non ai parametri della chiamata al metodo.
  • Gli attributi delle regole possono contenere anche caratteri jolly. Ad esempio, è possibile utilizzare RuleWrite("order/*") per indicare che tutti i campi dell'oggetto referenziato dal campo "order" vengono modificati dal metodo (in questo esempio, il metodo si trova nel flusso di lavoro e non nella classe Order). I caratteri jolly possono essere utilizzati al termine della sequenza; pertanto, un attributo come RuleWrite("*/Discount") non è valido.
  • È possibile utilizzare un attributo del tipo RuleWrite("order") con tipi di riferimento per indicare che il riferimento stesso è stato modificato, ad esempio perché la variabile punta a un'istanza diversa di Order. Si suppone che ciò influisca su tutte le regole che utilizzano un campo/proprietà all'interno di una variabile, oltre che su tutte quelle che effettuano un test sul riferimento all'istanza stesso, ad esempio IF this.order == this.order2.
  • Qualora non sia specificato alcun attributo per il metodo, il comportamento predefinito prevede che si supponga che la chiamata al metodo legga tutti i campi/proprietà dell'oggetto di destinazione (l'oggetto su cui viene invocato il metodo), ma non scriva in alcuno di essi. Inoltre, si suppone che un metodo legga i parametri che gli vengono passati, ma non effettui alcuna operazione di scrittura al loro interno. Quando vengono utilizzati in azioni relative a regole, si suppone che i parametri Out e ref vengano scritti.
Esplicito

L'ultimo meccanismo utilizzato per indicare le dipendenze da campi/proprietà prevede l'utilizzo dell'istruzione Update. L'istruzione Update riceve come argomento una stringa che rappresenta il percorso relativo a un campo o a una proprietà oppure un'espressione che rappresenta l'accesso a un campo/una proprietà. Ad esempio, è possibile inserire una delle due istruzioni seguenti nell'editor dell'insieme di regole per creare un'istruzione Update nella proprietà the Name di un'istanza Customer all'interno del flusso di lavoro.

                  Update("this/customer/Name")
                

OPPURE

                  Update(this.customer.Name)
                

L'istruzione Update indica che la regola effettua la scrittura nel campo/nella proprietà indicati, ottenendo lo stesso risultato dell'impostazione diretta del campo/della proprietà nella regola o della chiamata al metodo con un attributo RuleWrite relativo al campo/alla proprietà.

L'istruzione Update consente di utilizzare anche caratteri jolly. Ad esempio, è possibile aggiungere a una regola la seguente istruzione Update.

                  Update("this/customer/*")
                

In questo modo, tutte le regole che utilizzano proprietà dell'istanza Customer all'interno delle proprie condizioni vengono valutate nuovamente. In altri termini, ognuna delle due regole seguenti viene valutata nuovamente.

                  IF this.customer.ZipCode == 98052
                  THEN ...

                  IF this.customer.CreditScore < 600
                  THEN ...
                

Solitamente, nella maggior parte degli scenari non è previsto che gli utenti debbano modellare istruzioni Update esplicite, poiché il concatenamento implicito fornisce l'analisi delle dipendenze e il comportamento necessari. L'assegnazione di attributi ai metodi è adeguata alla maggior parte delle circostanze nelle quali il concatenamento implicito non è in grado di identificare le dipendenze. In genere, questa soluzione è preferibile rispetto all'istruzione Update per indicare le dipendenze, poiché è possibile identificare la presenza di queste ultime all'interno di un determinato metodo e sfruttarla in varie regole, anche diverse, che utilizzano il metodo in questione. Inoltre, qualora le regole siano create e i metodi siano implementati da persone diverse (o le attività vengano svolte in momenti differenti), l'assegnazione di attributi ai metodi consente a chi crea questi ultimi (e conosce meglio il codice) di determinarne le dipendenze.

Tuttavia, in alcune circostanze l'istruzione Update è la soluzione più appropriata, come quando un campo/una proprietà viene passato a un metodo di una classe non controllata dal creatore del flusso di lavoro che, quindi, non è in grado di assegnarle alcun attributo come nel caso del codice riportato di seguito.

                  IF ...
                  THEN this.customer.UpdateCreditScore(this.currentCreditScore)
                       Update(this.currentCreditScore)
                

Controllo del concatenamento in avanti

Il concatenamento in avanti è uno strumento potente che consente di assemblare regole atomiche in insiemi senza che sia necessario definire, o addirittura conoscere, le dipendenze tra le regole.

Tuttavia, talvolta chi crea le regole può desiderare un maggiore controllo sulle modalità di concatenamento, in particolare per quanto riguarda la possibilità di limitare il concatenamento effettuato. Ciò consente di:

  • limitare l'esecuzione ripetitiva delle regole, che potrebbe produrre risultati errati;
  • aumentare le prestazioni;
  • impedire l'esecuzione di cicli all'infinito.

Questo livello di controllo delle regole di WF è facilitato dalle due proprietà indicate di seguito.

  • La proprietà Chaining Behavior, assegnata all'insieme di regole.
  • La proprietà Reevaluation Behavior, assegnata a ciascuna regola.

È possibile impostare entrambi nell'editor dell'insieme di regole.

Proprietà Chaining Behavior

La proprietà Chaining Behavior assegnata all'insieme di regole può assumere tre valori:

  • Full Chaining
  • Explicit Chaining
  • Sequential

L'opzione Full Chaining è predefinita e prevede il comportamento decritto in precedenza. L'opzione Explicit Chaining disattiva il concatenamento implicito e quello basato sugli attributi e fa in modo che il concatenamento avvenga solo per mezzo di istruzioni Update esplicite, assicurando all'autore delle regole il controllo completo sulle regole che causano la rivalutazione. Ciò consente di evitare la ripetizione eccessiva (o addirittura infinita) dell'esecuzione delle regole oppure di aumentare le prestazioni eliminando la rivalutazione superflua delle regole non necessarie per la completezza funzionale dell'insieme di regole.

L'ultima opzione disponibile è Sequential, che fa in modo che il motore valuti le regole secondo un ordine strettamente lineare. Ogni regola viene valutata una e una sola volta, in base alla relativa priorità. Le regole con una priorità superiore potrebbero influire su quelle con priorità inferiore, ma non si verifica la situazione inversa, poiché non avviene alcuna modifica. Pertanto, è necessario utilizzare questa opzione insieme con l'assegnazione esplicita delle priorità, a meno che tra le regole non vi sia alcuna dipendenza.

Proprietà Reevaluation Behavior

La proprietà Reevaluation Behavior relativa a ciascuna regola può assumere due valori:

  • Always
  • Never

Always è l'impostazione predefinita e induce il comportamento descritto in precedenza, ovvero la ripetizione della valutazione della regola in base al concatenamento dovuto all'azione di altre regole, mentre Never disattiva la ripetizione della valutazione. In questo caso, la regola viene valutata una volta, ma questa operazione non viene ripetuta se la regola in questione ha eseguito eventuali azioni. In altri termini, se la regola è stata valutata in precedenza e sono state eseguite le azioni Then o Else corrispondenti, essa non viene valutata nuovamente. L'esecuzione di un insieme di azioni vuoto in corrispondenza delle azioni Then o Else non contrassegna una regola come eseguita.

Normalmente, questa proprietà viene utilizzata, a livello di regola, per impedire l'esecuzione infinita di un ciclo dovuta alle dipendenze di una regola rispetto alle proprie azioni o a quelle di altre regole. Ad esempio, la regola seguente crea il proprio ciclo infinito e non è necessario ripetere la valutazione per soddisfare i requisiti funzionali della regola stessa.

                  IF this.shippingCharge < 2.5 AND this.orderValue > 100
                  THEN this.shippingCharge = 0
                

In alternativa, se si desidera valutare nuovamente la regola, ma solo se in caso di variazione del campo OrderValue, è possibile impostare la modalità del cambiamento nell'insieme di regole affinché esegua il concatenamento solo in corrispondenza di istruzioni Update esplicite (e, quindi, aggiunga queste istruzioni Update alle azioni corrispondenti della regola). Naturalmente, l'utente potrebbe avere aggiunto alla regola un'ulteriore condizione per verificare che il valore di ShippingCost non sia già 0, ma i controlli del concatenamento eliminano la necessità per gli utenti di definire le regole in base ai dettagli della valutazione, in contrasto con i requisiti aziendali.

Funzione Halt

È possibile aggiungere la funzione Halt, in qualità di controllo finale, all'azione di una regola (è sufficiente digitare "Halt" nelle caselle dell'editor corrispondente alle azioni Then o Else). Ciò interrompe immediatamente l'esecuzione dell'insieme di regole e restituisce il controllo al codice che ha effettuato la chiamata. Naturalmente, l'utilità di questa funzione non si limita al controllo del concatenamento: un insieme di regole avente uno scopo specifico, può utilizzare la funzione Halt per interrompere l'esecuzione una volta raggiunto il risultato prefissato.

Ulteriori informazioni sulla modellazione

Esecuzione basata sulle priorità

Come illustrato nella sezione precedente, qualora si desideri una determinata sequenza di esecuzione nell'ambito di un insieme di regole o di un suo sottoinsieme, è possibile utilizzare il campo relativo alla priorità di ciascuna regola. In questo modo viene eliminata la necessità del concatenamento che, eventualmente, può addirittura essere disattivato. In molti casi, infatti, per ottenere una determinata dipendenza tra le regole è sufficiente definire opportunamente una sequenza di esecuzione esplicita.

È importante notare, tuttavia, che il meccanismo di esecuzione in avanti di WF offre agli utenti la possibilità di definire una sequenza di esecuzione, ma non impone loro di farlo. Nella maggior parte dei casi, il comportamento del concatenamento in avanti rende superflua l'assegnazione di priorità alle regole per fare in modo che il risultato dell'insieme di regole sia corretto, poiché le relazioni vengono gestite automaticamente dal motore per garantire il rispetto delle dipendenze tra le regole.

Si supponga che esistano le regole indicate di seguito.

Regola 1

                  IF this.Weather.Temperature < 50
                  THEN this.Drink.Style = "Latte"
                

Regola 2

                  IF this.Drink.Style == "Latte"
                  THEN this.Snack.Style = "Scone"
                  ELSE this.Snack.Style = "Muffin"
                

In WF è possibile assegnare alla Regola 1 una priorità più elevata, affinché sia eseguita per prima. Ciò garantisce che Drink.Style venga impostato prima della valutazione della Regola 2.

Per ottenere il risultato desiderato, tuttavia, non è necessario creare alcuna sequenza. Si supponga, invece, che la Regola 2 venga valutata per prima: in questo caso, Drink.Style potrebbe assumere il valore null oppure un altro valore e il risultato sarebbe l'impostazione di Snack.Style su Muffin. Tuttavia, in seguito all'esecuzione della Regola 1 e all'impostazione di Drink.Style su Latte, la Regola 2 verrebbe nuovamente valutata e imposterebbe Snack.Style su Scone. In sostanza, l'utente è in grado di determinare la sequenza di esecuzione, ma in molti casi ciò non è necessario.

Elaborazione degli insiemi

Talvolta potrebbe essere necessario valutare le regole rispetto a tutti i singoli elementi di un insieme. La ripetizione nell'ambito di un insieme può essere effettuata in vari modi, uno dei quali consiste nel definire lo schema delle regole, come nell'esempio seguente.

Regola 1 (Priorità = 2)

                  //always execute this rule once to create the enumerator
                  IF 1==1
                  THEN this.enumerator = this.myCollection.GetEnumerator()
                

Regola 2 (Priorità = 1)

                  IF this.enumerator.MoveNext()
                  THEN this.currentInstance = this.enumerator.Current
                

Regole 3-n (Priorità = 0)

                  .... //additional rules written against this.currentInstance
                

Regola n+1 (Priorità = -1)

                  // can be any condition as long as it is evaluated every time;
                  // this.currentInstance will be evaluated each time
                  //this.currentInstance changes, whereas
                  // "1==1" would only be evaluated once
                  IF this.currentInstance == this.currentInstance

                  THEN ...
                  Update("this/enumerator") //this will cause Rule 2 to be reevaluated
                  ELSE ...
                  Update("this/enumerator")
                

Rilevamento e analisi

Rilevamento

Durante l'esecuzione di un insieme di regole, i rilevamenti degli eventi vengono inviati ad appositi servizi configurati negli host e registrati aggiungendo UserTrackPoint al rispettivo profilo di rilevamento. Viene inviato RuleActionTrackingEvent, che fornisce il nome della regola valutata nonché il risultato della valutazione (true/false). Consultare l'esempio di RuleActionTrackingEvent nell'SDK.

Il risultato della valutazione delle condizioni di una regola rispetto alle attività può essere rilevato implicitamente osservando l'esecuzione delle attività in questione.

Analisi

È possibile inviare a un file di log ulteriori informazioni sulla valutazione di un insieme di regole aggiungendo il codice seguente al file di configurazione di un'applicazione.

                  <configuration>
                  <system.diagnostics>
                  <switches>
                             <add name="Rules" value="Information"/>
                  </switches>
                  </system.diagnostics>
                  </configuration>
                

Al file di log vengono inviate le seguenti informazioni:

  • Dipendenze della condizione:
    • Esempio: dipendenze della condizione "ReturnNumberOfStops" della regola: "this/currentFlight/OutboundFlight/NumberOfStops/"
  • Effetti collaterali delle azioni:
    • Esempio: effetto collaterale THEN "ReturnNumberOfStops" della regola "this/currentFlight/Score/"
  • Relazioni tra i concatenamenti:
    • Esempio: le azioni THEN "ReturnNumberOfStops" della regola attivano la regola "ApprovedFlights"
  • Esecuzione dell'insieme di regole:
    • Esempio: regole: "esecuzione RuleSet FlightRuleSet"
  • Valutazione delle condizioni:
    • Esempio: regole: valutazione della condizione della regola "SetDefaultScore"
  • Risultato della valutazione della condizione:
    • Esempio: regole: La condizione viene valutata come True
  • Esecuzione delle azioni:
    • Esempio: regole: valutazione delle azioni THEN per la regola "SetDefaultScore"

Tutti i messaggi di analisi sono attualmente definiti al livello "Informazioni", quindi, per visualizzare l'analisi delle regole, è necessario specificare il livello informativo o dettagliato nel file di configurazione.

Conclusioni

WF offre funzionalità relative alle regole flessibili che è possibile sfruttare in molti modi diversi, per affrontare un'ampia gamma di scenari. Dalle semplici condizioni delle attività agli insiemi di regole dotati di concatenamento in avanti sofisticato, la tecnologia consente di integrare senza problemi il supporto delle regole nei flussi di lavoro. Inoltre, il motore per le regole può essere sfruttato anche all'interno dei flussi di lavoro per fornire funzionalità relative alle regole a tutte le applicazioni .NET.

L'insieme di funzionalità consente ai nuovi sviluppatori di incorporare regole semplici nei flussi di lavoro, offrendo la possibilità e l'estensibilità per supportare applicazioni e insiemi di regole molto più complessi. Questo documento, insieme con le risorse citate nella sezione successiva, aiuta gli sviluppatori che non conoscono le regole di WF ad apprendere la tecnologia e a utilizzarla rapidamente in modo produttivo.

Ulteriori informazioni

  • MSDN Workflow Site

    Contiene numerosi documenti e collegamenti a webcast e laboratori.

  • Community Site Samples
    • External RuleSet Toolkit, fornisce un esempio di esternalizzazione di regole rispetto ai gruppi di lavoro.
    • RuleSet Analysis, strumento per analizzare gli insiemi di regole per la determinazione delle relazioni tra le regole e tra queste ultime e i dati.
    • Rules in Excel, fornisce un esempio di utilizzo delle regole in modo autonomo, all'esterno di un flusso di lavoro nonché come creare regole da programma mediante una tabella di decisioni in Excel.
  • Esempi dell'SDK
    • IfElseWithRules mostra l'utilizzo di RuleCondition in un'attività IfElse (in \Technologies\RulesAndConditions).
    • DynamicUpdateChangingRules mostra l'utilizzo delle API per l'aggiornamento dinamico per modificare la condizione di una regola in un'istanza del flusso di lavoro in esecuzione (\Technologies\RulesAndConditions).
    • SimplePolicy mostra l'uso delle API per definire un semplice insieme di regole e di attività del criterio (\Technologies\Activities\Policy).
    • AdvancedPolicy definisce un insieme di regole più complesso (\Technologies\Activities\Policy).
    • RuleActionTrackingEventSample mostra come acquisire i risultati della valutazione delle regole in un provider di rilevamento (\Technologies\Tracking).
  • MSDN Workflow Forum
    • Per domande relative alle regole di WF o a WF in generale, visitare il forum di discussione.

 

Informazioni sull'autore

Jurgen Willis è Program Manager del team Windows Workflow Foundation, dove è responsabile della tecnologia relativa al motore per le regole e delle attività governate dalle regole. Prima di entrare in Microsoft, Jurgen ha progettato e implementato soluzioni per l'integrazione e la gestione dei processi per aziende del gruppo Fortune 500.

Mostra: