Verwenden von Aktivitätsdelegaten
Aktivitätsdelegaten ermöglichen es Aktivitätsautoren, Rückrufe mit bestimmten Signaturen verfügbar zu machen, für die Benutzer der Aktivität aktivitätsbasierte Handler bereitstellen können. Es sind zwei Typen von Aktivitätsdelegaten verfügbar: ActivityAction<T> wird verwendet, um Aktivitätsdelegaten zu definieren, die keinen Rückgabewert haben, und ActivityFunc<TResult> wird verwendet, um Aktivitätsdelegaten zu definieren, die einen Rückgabewert aufweisen.
Aktivitätsdelegaten sind in Szenarien nützlich, in denen eine untergeordnete Aktivität auf die Verwendung einer bestimmten Signatur beschränkt werden muss. Eine While-Aktivität kann z. B. einen beliebigen Typ von untergeordneter Aktivität ohne Einschränkungen enthalten. Der Text einer ForEach<T>-Aktivität ist jedoch ein ActivityAction<T>-Element, und die untergeordnete Aktivität, die letztlich von ForEach<T> ausgeführt wird, muss über ein InArgument<T>-Element verfügen, das den gleichen Typ wie die Member der Auflistung aufweist, die das ForEach<T>-Element auflistet.
Verwenden von ActivityAction
Mehrere .NET Framework 4.6.1-Aktivitäten verwenden Aktivitätsaktionen, z. B. die Catch-Aktivität und die ForEach<T>-Aktivität. In jedem Fall stellt die Aktivitätsaktion einen Speicherort da, an dem der Workflowautor beim Verfassen eines Workflows mithilfe einer dieser Aktivitäten eine Aktivität angibt, um das gewünschte Verhalten bereitzustellen. Im folgenden Beispiel wird eine ForEach<T>-Aktivität verwendet, um Text im Konsolenfenster anzuzeigen. Der Text von ForEach<T> wird mit einer ActivityAction<T> angegeben, die dem Typ von ForEach<T>, einer Zeichenfolge, entspricht. Die im WriteLine angegebene Handler-Aktivität weist ein Text-Argument auf, das an die Zeichenfolgenwerte in der Auflistung gebunden ist, die die ForEach<T>-Aktivität durchläuft.
DelegateInArgument<string> actionArgument = new DelegateInArgument<string>();
Activity wf = new ForEach<string>
{
Body = new ActivityAction<string>
{
Argument = actionArgument,
Handler = new WriteLine
{
Text = new InArgument<string>(actionArgument)
}
}
};
List<string> items = new List<string>();
items.Add("Hello");
items.Add("World.");
Dictionary<string, object> inputs = new Dictionary<string, object>();
inputs.Add("Values", items);
WorkflowInvoker.Invoke(wf, inputs);
Das actionArgument wird verwendet, um die einzelnen Elemente in der Auflistung in die WriteLine zu verschieben. Wenn der Workflow aufgerufen wird, wird die folgende Ausgabe in der Konsole angezeigt.
HelloWorld.
In den Beispielen in diesem Thema wird die Syntax zur Objektinitialisierung verwendet. Die Objektinitialisierungssyntax kann eine nützliche Möglichkeit zum Erstellen von Workflowdefinitionen per Code darstellen, da diese eine hierarchische Ansicht der Aktivitäten im Workflow bietet und die Beziehung zwischen den Aktivitäten anzeigt. Die Verwendung der Objektinitialisierungssyntax ist keine Anforderung der programmgesteuerten Erstellung von Workflows. Das folgende Beispiel entspricht von der Funktion her dem vorherigen Beispiel.
DelegateInArgument<string> actionArgument = new DelegateInArgument<string>();
WriteLine output = new WriteLine();
output.Text = new InArgument<string>(actionArgument);
ActivityAction<string> body = new ActivityAction<string>();
body.Argument = actionArgument;
body.Handler = output;
ForEach<string> wf = new ForEach<string>();
wf.Body = body;
List<string> items = new List<string>();
items.Add("Hello");
items.Add("World.");
Dictionary<string, object> inputs = new Dictionary<string, object>();
inputs.Add("Values", items);
WorkflowInvoker.Invoke(wf, inputs);
Weitere Informationen zu Objektinitialisierern finden Sie unter Vorgehensweise: Initialisieren von Objekten ohne Aufrufen eines Konstruktors (C#-Programmierleitfaden) und Vorgehensweise: Deklarieren eines Objekts mithilfe eines Objektinitialisierers (Visual Basic).
Im folgenden Beispiel wird eine TryCatch-Aktivität in einem Workflow verwendet. Eine ApplicationException wird vom Workflow ausgelöst und wird von einer Catch<TException>-Aktivität behandelt. Der Handler für die Aktivitätsaktion der Catch<TException>-Aktivität ist eine WriteLine-Aktivität, und die Ausnahmedetails werden dorthin mithilfe von ex
DelegateInArgument<T> weitergeleitet.
DelegateInArgument<ApplicationException> ex = new DelegateInArgument<ApplicationException>()
{
Name = "ex"
};
Activity wf = new TryCatch
{
Try = new Throw()
{
Exception = new InArgument<Exception>((env) => new ApplicationException("An ApplicationException was thrown."))
},
Catches =
{
new Catch<ApplicationException>
{
Action = new ActivityAction<ApplicationException>
{
Argument = ex,
Handler = new WriteLine()
{
Text = new InArgument<string>((env) => ex.Get(env).Message)
}
}
}
},
Finally = new WriteLine()
{
Text = "Executing in Finally."
}
};
Verwenden Sie beim Erstellen einer benutzerdefinierten Aktivität, die ein ActivityAction<T>-Element definiert, ein InvokeAction<T>-Element, um das Aufrufen dieses ActivityAction<T>-Elements zu modellieren. In diesem Beispiel wird eine benutzerdefinierte WriteLineWithNotification
-Aktivität definiert. Diese Aktivität besteht aus einem Sequence-Element, das eine WriteLine-Aktivität gefolgt von einem InvokeAction<T>-Element enthält. Dieses Element ruft ein ActivityAction<T>-Element auf, das ein Zeichenfolgenargument verwendet.
public class WriteLineWithNotification : Activity
{
public InArgument<string> Text { get; set; }
public ActivityAction<string> TextProcessedAction { get; set; }
public WriteLineWithNotification()
{
this.Implementation = () => new Sequence
{
Activities =
{
new WriteLine
{
Text = new InArgument<string>((env) => Text.Get(env))
},
new InvokeAction<string>
{
Action = TextProcessedAction,
Argument = new InArgument<string>((env) => Text.Get(env))
}
}
};
}
}
Wenn mit der WriteLineWithNotification
-Aktivität ein Workflow erstellt wird, gibt der Workflowautor die gewünschte benutzerdefinierte Logik in der Handler-Eigenschaft der Aktivitätsaktion an. In diesem Beispiel wird ein Workflow mit der WriteLineWithNotification
-Aktivität erstellt, und eine WriteLine-Aktivität wird als Handler-Eigenschaft verwendet.
// Create and invoke the workflow without specifying any activity action
// for TextProcessed.
Activity wf = new WriteLineWithNotification
{
Text = "Hello World."
};
WorkflowInvoker.Invoke(wf);
// Output:
// Hello World.
// Create and Invoke the workflow with specifying an activity action
// for TextProcessed.
DelegateInArgument<string> msg = new DelegateInArgument<string>();
Activity wf2 = new WriteLineWithNotification
{
Text = "Hello World with activity action.",
TextProcessedAction = new ActivityAction<string>
{
Argument = msg,
Handler = new WriteLine
{
Text = new InArgument<string>((env) => "Handler of: " + msg.Get(env))
}
}
};
// Invoke the workflow with an activity action specified
WorkflowInvoker.Invoke(wf2);
// Output:
// Hello World with activity action.
// Handler of: Hello World with activity action.
Es gibt mehrere generische Versionen von InvokeAction<T> und ActivityAction<T> zum Übergeben von einem oder mehreren Argumenten.
Verwenden von ActivityFunc
ActivityAction<T> ist nützlich, wenn es keinen Ergebniswert der Aktivität gibt, und ActivityFunc<TResult> wird verwendet, wenn ein Ergebniswert zurückgegeben wird. Verwenden Sie beim Erstellen einer benutzerdefinierten Aktivität, die ein ActivityFunc<TResult>-Element definiert, ein InvokeFunc<TResult>-Element, um das Aufrufen dieses ActivityFunc<TResult>-Elements zu modellieren. Im folgenden Beispiel wird eine WriteFillerText
-Aktivität definiert. Um den Füllzeichentext anzugeben, wird ein InvokeFunc<TResult>-Element angegeben, das ein ganzzahliges Argument verwendet und über ein Zeichenfolgenergebnis verfügt. Nachdem der Füllzeichentext abgerufen wurde, wird er mit einer WriteLine-Aktivität auf der Konsole angezeigt.
public class WriteFillerText : Activity
{
public ActivityFunc<int, string> GetText { get; set; }
public InArgument<int> Quantity { get; set; }
Variable<string> text = new Variable<string>
{
Name = "Text"
};
public WriteFillerText()
{
this.Implementation = () => new Sequence
{
Variables =
{
text
},
Activities =
{
new InvokeFunc<int, string>
{
Func = GetText,
Argument = new InArgument<int>((env) => Quantity.Get(env)),
Result = new OutArgument<string>(text)
},
new WriteLine
{
Text = new InArgument<string>(text)
}
}
};
}
}
Um den Text anzugeben, müssen Sie eine Aktivität verwenden, die ein int
-Argument verwendet und über ein Zeichenfolgenergebnis verfügt. In diesem Beispiel wird eine TextGenerator
-Aktivität veranschaulicht, die diese Anforderungen erfüllt.
public class TextGenerator : CodeActivity<string>
{
public InArgument<int> Quantity { get; set; }
public InArgument<string> Text { get; set; }
protected override string Execute(CodeActivityContext context)
{
// Provide a quantity of Random Text
int q = Quantity.Get(context);
if (q < 1)
{
q = 1;
}
string text = Text.Get(context) + " ";
StringBuilder sb = new StringBuilder(text.Length * q);
for (int i = 0; i < q; i++)
{
sb.Append(text);
}
return sb.ToString();
}
}
Um die TextGenerator
-Aktivität mit der WriteFillerText
-Aktivität zu verwenden, geben Sie diese als Handler-Eigenschaft an.
DelegateInArgument<int> actionArgument = new DelegateInArgument<int>();
Activity wf = new WriteFillerText
{
Quantity = 5,
GetText = new ActivityFunc<int, string>
{
Argument = actionArgument,
Handler = new TextGenerator
{
Quantity = new InArgument<int>(actionArgument),
Text = "Hello World."
}
}
};
WorkflowInvoker.Invoke(wf);