Gerade bei komplexen Datenmodellen besteht das einfache Erstellen von neuen Instanzen aus mehreren Schritten.
Die Validierung einer neuen Instanz eines Typs ist sollte dabei immer der erste Schritt sein, damit die Konsistenz von Daten gewährleistet sein kann.
Da demnach die Validierung in allen Workflows vorhanden sein muss die eine neue Objektinstanz in den Datenspeicher schreiben, habe ich eine einfache Activity geschrieben die diese Funktionalität durchführt.
1. Anforderung
Es soll eine Activity erstellt werden die neue Objektinstanzen validiert und entsprechend dem Validierungsergebnis eine Property zur Bindung an IfElse Activities bereitstellt.
2. Überlegungen
Mit der Hilfe eines Interfaces kann allen benötigten Typen eine Methode zum Validieren bereitgestellt werden und durch das Interface kann die Activity einfach gehalten werden.
3. Lösung
Die Implementierung der CustomActivity ist recht simpel, dar die Validierungslogik direkt am Geschäftsobjekt implementiert ist. Als ersten Schritt erstellt man das oben genannte Interface hier IValidateable.
public interface IValidateable
{
bool IsValid();
}
Der nächste Schritt wäre demnach die Geschäftsobjekte um dieses Interface zu erweitern, so dass alle benötigten Typen dieses Interface implementieren.
Danach geht es an die eigentliche Arbeit, die Custom Activity:
Da die Validierung eine atomare Funktion ist und demnach keine eingebetteten Aktivitäten haben kann leitet man die ValidationActivity direkt von Activity aus dem Namespace System.Workflow.ComponentModel ab.
public class ValidationActivity : Activity
{
// ...
}
Zur Realisierung der Anforderung werden lediglich zwei Properties benötigt, die, wie üblich in der Workflow Entwicklung, als DependencyProperty erstellt werden.
- ItemToValidate – Dass zu validierende Objekt
- IsItemValidate - Das Ergebnis der Validierung
Zunächst müssen die beiden Properties registriert werden:
public static DependencyProperty ItemToValidateProperty = DependencyProperty.Register("ItemToValidate",
typeof (IValidateable),
typeof (ValidateActivity));
public static DependencyProperty IsItemValidProperty = DependencyProperty.Register("IsItemValid", typeof (bool),
typeof (ValidateActivity));
Danach müssen noch zwei Wrapper für die Properties geschrieben werden, damit diese von .Net Code aus typisiert aufgerufen werden können. Diese Properties sind darüber hinaus noch mit dem Browsable Attribut zu versehen, damit sie auch im Eigenschaftenfenster von Visual Studio sichtbar sind.
[Browsable(true)]
public IValidateable ItemToValidate
{
get { return (GetValue(ItemToValidateProperty) as IValidateable); }
set { SetValue(ItemToValidateProperty,value);}
}
[Browsable(true)]
public bool IsItemValid
{
get { return Convert.ToBoolean(GetValue(IsItemValidProperty)); }
set{SetValue(IsItemValidProperty,value);}
}
Letztlich bleibt nur noch der Aufruf der Validierungsmethode selbst. In meinem Beispiel prüfe ich zunächst noch ab, ob das zu prüfende Element gesetzt wurde, ist dies nicht der Fall, werfe ich eine ArgumentException mit entsprechender Message. Das Validierungsergebnis schreibe ich direkt in die entsprechende Property, damit diese im weiteren Workflowverlauf gebunden werden kann.
protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
{
if (ItemToValidate == null)
throw new ArgumentException("Item is not set, can't validate null");
this.IsItemValid = ItemToValidate.IsValid();
return ActivityExecutionStatus.Closed;
}
Ein Workflow der diese Activity verwendet kann demnach wie folgt aussehen
Die IfElse Activity “CheckIsItemValid” verfügt hier über eine Bedingung die deklarativ an die IsItemValid Proprety der ValidateNewUser Activity gebunden ist. Entsprechend dem Validierungsergebnis wird die neue Objektinstanz gespeichert oder eine Exception wird generiert.