Anmerkung
Der Zugriff auf diese Seite erfordert eine Genehmigung. Du kannst versuchen, dich anzumelden oder die Verzeichnisse zu wechseln.
Der Zugriff auf diese Seite erfordert eine Genehmigung. Du kannst versuchen , die Verzeichnisse zu wechseln.
Aktivitäten können innerhalb eines Workflows abgebrochen werden, z. B. durch eine Parallel-Aktivität, die unvollständige Verzweigungen abbricht, wenn ihre CompletionConditiontrue ergibt, oder von außerhalb des Workflows, wenn der Host Cancel aufruft. Workflowautoren können die Abbruchbehandlung mithilfe der CancellationScope-Aktivität oder der CompensableActivity-Aktivität bereitstellen oder können benutzerdefinierte Aktivitäten erstellen, die eine Abbruchlogik bereitstellen. Dieses Thema bietet eine Übersicht über den Abbruch in Workflows.
Abbruch, Kompensation und Transaktionen
Wenn Sie Transaktionen verwenden, kann Ihre Anwendung alle Änderungen abbrechen, die während der Transaktion durchgeführt wurden, wenn ein Fehler im Transaktionsprozess auftritt. Möglicherweise ist jedoch nicht die gesamte Arbeit, die abgebrochen oder rückgängig gemacht werden muss, für Transaktionen geeignet, beispielsweise Prozesse mit langer Laufzeit oder Aufgaben, die keine Transaktionsressourcen einschließen. Die Kompensation stellt ein Modell zum Rückgängigmachen von zuvor abgeschlossenen, nicht transaktionalen Aufgaben bereit, wenn im Workflow ein nachfolgender Fehler auftritt. Der Abbruch stellt ein Modell für Workflow- und Aktivitätsautoren zum Behandeln von nicht transaktionalen Aufgaben bereit, die noch nicht abgeschlossen waren. Wenn die Ausführung einer Aktivität nicht abgeschlossen war und abgebrochen wird, wird die Abbruchlogik aufgerufen, falls verfügbar.
Hinweis
Weitere Informationen zu Transaktionen und Entschädigungen finden Sie unter Transaktionen und Entschädigungen.
Verwendung von „CancellationScope“
Die CancellationScope-Aktivität verfügt über zwei Abschnitte, die untergeordnete Aktivitäten enthalten können: Body und CancellationHandler. Im Body befinden sich die Aktivitäten, aus denen die Logik der Aktivität besteht, und im CancellationHandler befinden sich die Aktivitäten, die die Abbruchlogik für die Aktivität bereitstellen. Eine Aktivität kann nur abgebrochen werden, wenn sie noch nicht abgeschlossen wurde. Im Fall der CancellationScope-Aktivität verweist der Abschluss auf den Abschluss der Aktivitäten im Body. Wenn eine Abbruchanforderung geplant ist und die Aktivitäten im Body nicht abgeschlossen wurden, dann wird der CancellationScope als Canceled markiert, und die CancellationHandler-Aktivitäten werden ausgeführt.
Abbrechen eines Workflows vom Host aus
Ein Host kann einen Workflow abbrechen, indem er die Cancel-Methode der WorkflowApplication-Instanz aufruft, die den Workflow hostet. Im folgenden Beispiel wird ein Workflow erstellt, der einen CancellationScope aufweist. Der Workflow wird aufgerufen und anschließend ruft der Host Cancel auf. Die Hauptausführung des Workflows wird beendet, der CancellationHandler des CancellationScope wird aufgerufen, und dann wird der Workflow mit einem Status von Canceled abgeschlossen.
Activity wf = new CancellationScope
{
Body = new Sequence
{
Activities =
{
new WriteLine
{
Text = "Starting the workflow."
},
new Delay
{
Duration = TimeSpan.FromSeconds(5)
},
new WriteLine
{
Text = "Ending the workflow."
}
}
},
CancellationHandler = new WriteLine
{
Text = "CancellationHandler invoked."
}
};
// Create a WorkflowApplication instance.
WorkflowApplication wfApp = new WorkflowApplication(wf);
// Subscribe to any desired workflow lifecycle events.
wfApp.Completed = delegate (WorkflowApplicationCompletedEventArgs e)
{
if (e.CompletionState == ActivityInstanceState.Faulted)
{
Console.WriteLine($"Workflow {e.InstanceId} Terminated.");
Console.WriteLine($"Exception: {e.TerminationException.GetType().FullName}\n{e.TerminationException.Message}");
}
else if (e.CompletionState == ActivityInstanceState.Canceled)
{
Console.WriteLine($"Workflow {e.InstanceId} Canceled.");
}
else
{
Console.WriteLine($"Workflow {e.InstanceId} Completed.");
}
};
// Run the workflow.
wfApp.Run();
Thread.Sleep(TimeSpan.FromSeconds(1));
wfApp.Cancel();
Wenn dieser Workflow aufgerufen wird, wird die folgende Ausgabe in der Konsole angezeigt.
Starten des Workflows.
CancellationHandler aufgerufen.Workflow b30ebb30-df46-4d90-a211-e31c38d8db3c Abgebrochen.
Hinweis
Wenn eine CancellationScope-Aktivität abgebrochen und der CancellationHandler aufgerufen wird, liegt es in der Verantwortung des Workflowautors, den Status der abgebrochenen Aktivität vor dem Abbruch zu bestimmen, um die entsprechende Abbruchlogik bereitzustellen. Der CancellationHandler stellt keine Informationen zum Status der abgebrochenen Aktivität bereit.
Ein Workflow kann auch vom Host abgebrochen werden, wenn eine nicht behandelte Ausnahme über den Stamm des Workflows hinaus aufsteigt und der OnUnhandledException-Handler Cancel zurückgibt. In diesem Beispiel startet der Workflow und löst dann eine ApplicationException aus. Diese Ausnahme wird vom Workflow nicht behandelt, daher wird der OnUnhandledException-Handler aufgerufen. Der Handler weist die Laufzeit an, den Workflow abzubrechen, und der CancellationHandler der derzeit ausgeführten CancellationScope-Aktivität wird aufgerufen.
Activity wf = new CancellationScope
{
Body = new Sequence
{
Activities =
{
new WriteLine
{
Text = "Starting the workflow."
},
new Throw
{
Exception = new InArgument<Exception>((env) =>
new ApplicationException("An ApplicationException was thrown."))
},
new WriteLine
{
Text = "Ending the workflow."
}
}
},
CancellationHandler = new WriteLine
{
Text = "CancellationHandler invoked."
}
};
// Create a WorkflowApplication instance.
WorkflowApplication wfApp = new WorkflowApplication(wf);
// Subscribe to any desired workflow lifecycle events.
wfApp.OnUnhandledException = delegate (WorkflowApplicationUnhandledExceptionEventArgs e)
{
// Display the unhandled exception.
Console.WriteLine($"OnUnhandledException in Workflow {e.InstanceId}\n{e.UnhandledException.Message}");
// Instruct the runtime to cancel the workflow.
return UnhandledExceptionAction.Cancel;
};
wfApp.Completed = delegate (WorkflowApplicationCompletedEventArgs e)
{
if (e.CompletionState == ActivityInstanceState.Faulted)
{
Console.WriteLine($"Workflow {e.InstanceId} Terminated.");
Console.WriteLine($"Exception: {e.TerminationException.GetType().FullName}\n{e.TerminationException.Message}");
}
else if (e.CompletionState == ActivityInstanceState.Canceled)
{
Console.WriteLine($"Workflow {e.InstanceId} Canceled.");
}
else
{
Console.WriteLine($"Workflow {e.InstanceId} Completed.");
}
};
// Run the workflow.
wfApp.Run();
Wenn dieser Workflow aufgerufen wird, wird die folgende Ausgabe in der Konsole angezeigt.
Starten des Workflows.
OnUnhandledException in Workflow 6bb2d5d6-f49a-4c6d-a988-478afb86dbe9Eine ApplicationException wurde ausgelöst.CancellationHandler wurde aufgerufen.Workflow 6bb2d5d6-f49a-4c6d-a988-478afb86dbe9 Abgebrochen.
Abbrechen einer Aktivität innerhalb eines Workflows
Eine Aktivität kann auch von ihrer übergeordneten Instanz abgebrochen werden. Wenn eine Parallel-Aktivität beispielsweise mehrere ausführende Zweige hat und ihr CompletionConditiontrue ergibt, werden ihre unvollständigen Zweige abgebrochen. In diesem Beispiel wird eine Parallel-Aktivität erstellt, die zwei Zweige aufweist. Seine CompletionCondition ist auf true festgelegt, damit die Parallel abgeschlossen wird, sobald einer seiner Zweige abgeschlossen ist. In diesem Beispiel wird Branch 2 abgeschlossen und daher wird Branch 1 abgebrochen.
Activity wf = new Parallel
{
CompletionCondition = true,
Branches =
{
new CancellationScope
{
Body = new Sequence
{
Activities =
{
new WriteLine
{
Text = "Branch 1 starting."
},
new Delay
{
Duration = TimeSpan.FromSeconds(2)
},
new WriteLine
{
Text = "Branch 1 complete."
}
}
},
CancellationHandler = new WriteLine
{
Text = "Branch 1 canceled."
}
},
new WriteLine
{
Text = "Branch 2 complete."
}
}
};
// Create a WorkflowApplication instance.
WorkflowApplication wfApp = new WorkflowApplication(wf);
wfApp.Completed = delegate (WorkflowApplicationCompletedEventArgs e)
{
if (e.CompletionState == ActivityInstanceState.Faulted)
{
Console.WriteLine($"Workflow {e.InstanceId} Terminated.");
Console.WriteLine($"Exception: {e.TerminationException.GetType().FullName}\n{e.TerminationException.Message}");
}
else if (e.CompletionState == ActivityInstanceState.Canceled)
{
Console.WriteLine($"Workflow {e.InstanceId} Canceled.");
}
else
{
Console.WriteLine($"Workflow {e.InstanceId} Completed.");
}
};
// Run the workflow.
wfApp.Run();
Wenn dieser Workflow aufgerufen wird, wird die folgende Ausgabe in der Konsole angezeigt.
Branch 1 beginnt.
Branch 2 abgeschlossen.Branch 1 abgebrochen.Workflow e0685e24-18ef-4a47-acf3-5c638732f3be abgeschlossen. Aktivitäten werden auch abgebrochen, wenn eine Ausnahme an der Wurzel der Aktivität vorbei auftaucht, aber auf einer höheren Ebene im Workflow behandelt wird. In diesem Beispiel besteht die Hauptlogik des Workflows aus einer Sequence-Aktivität. Die Sequence wird als Body einer CancellationScope-Aktivität angegeben, die in einer TryCatch-Aktivität enthalten ist. Im Körper von Sequence wird eine Ausnahme ausgelöst, die von der übergeordneten TryCatch-Aktivität behandelt wird, und die Sequence-Aktivität wird abgebrochen.
Activity wf = new TryCatch
{
Try = new CancellationScope
{
Body = new Sequence
{
Activities =
{
new WriteLine
{
Text = "Sequence starting."
},
new Throw
{
Exception = new InArgument<Exception>((env) =>
new ApplicationException("An ApplicationException was thrown."))
},
new WriteLine
{
Text = "Sequence complete."
}
}
},
CancellationHandler = new WriteLine
{
Text = "Sequence canceled."
}
},
Catches =
{
new Catch<ApplicationException>
{
Action = new ActivityAction<ApplicationException>
{
Handler = new WriteLine
{
Text = "Exception caught."
}
}
}
}
};
// Create a WorkflowApplication instance.
WorkflowApplication wfApp = new WorkflowApplication(wf);
wfApp.Completed = delegate (WorkflowApplicationCompletedEventArgs e)
{
if (e.CompletionState == ActivityInstanceState.Faulted)
{
Console.WriteLine($"Workflow {e.InstanceId} Terminated.");
Console.WriteLine($"Exception: {e.TerminationException.GetType().FullName}\n{e.TerminationException.Message}");
}
else if (e.CompletionState == ActivityInstanceState.Canceled)
{
Console.WriteLine($"Workflow {e.InstanceId} Canceled.");
}
else
{
Console.WriteLine($"Workflow {e.InstanceId} Completed.");
}
};
// Run the workflow.
wfApp.Run();
Wenn dieser Workflow aufgerufen wird, wird die folgende Ausgabe in der Konsole angezeigt.
Starten der Sequenz.
Sequenz abgebrochen.Ausnahme abgefangen.Workflow e3c18939-121e-4c43-af1c-ba1ce977ce55 Abgeschlossen.
Auslösen von Ausnahmen durch einen CancellationHandler
Alle vom CancellationHandler eines CancellationScope ausgelösten Ausnahmen haben schwerwiegende Auswirkungen auf den Workflow. Wenn die Möglichkeit besteht, dass Ausnahmen aus einem CancellationHandler entstehen, verwenden Sie einen TryCatch im CancellationHandler, um diese Ausnahmen abzufangen und zu behandeln.
Abbruch mithilfe von CompensableActivity
Genau wie die CancellationScope-Aktivität verfügt die CompensableActivity über einen CancellationHandler. Wenn eine CompensableActivity abgebrochen wird, werden alle Aktivitäten in ihrem CancellationHandler aufgerufen. Dies kann nützlich für das Rückgängigmachen teilweise abgeschlossener, kompensierbarer Arbeit sein. Für Informationen zur Verwendung von CompensableActivity zur Kompensation und Stornierung siehe Kompensierung.
Abbruch mithilfe von benutzerdefinierten Aktivitäten
Für Autoren von benutzerdefinierten Aktivitäten gibt es mehrere Möglichkeiten, eine Abbruchlogik in ihre benutzerdefinierten Aktivitäten zu implementieren. Benutzerdefinierte Aktivitäten, die von Activity abgeleitet werden, können Abbruchlogik implementieren, indem CancellationScope oder eine andere benutzerdefinierte Aktivität, die Abbruchlogik enthält, in den Text der Aktivität eingefügt wird. Von AsyncCodeActivity und NativeActivity abgeleitete Aktivitäten können die jeweilige Cancel-Methode überschreiben und an dieser Stelle eine Abbruchlogik bereitstellen. Von CodeActivity abgeleitete Aktivitäten stellen keine Möglichkeit zum Abbruch dar, da die gesamte Arbeit in einer einzigen Ausführung ausgeführt wird, wenn die Laufzeit die Execute-Methode aufruft. Wenn die execute-Methode noch nicht aufgerufen wurde und eine auf CodeActivity basierende Aktivität abgebrochen wird, wird die Aktivität mit einem Status von Canceled geschlossen, und die Execute-Methode wird nicht aufgerufen.
Abbruch mithilfe von NativeActivity
Von NativeActivity abgeleitete Aktivitäten können die Cancel-Methode überschreiben, um eine benutzerdefinierte Abbruchlogik bereitzustellen. Wenn diese Methode nicht überschrieben wird, dann wird die standardmäßige Workflowabbruchlogik angewendet. Bei einem Standardabbruch handelt es sich um den Prozess, der für eine NativeActivity auftritt, die die Cancel-Methode nicht überschreibt oder deren Cancel-Methode die NativeActivityCancel-Basismethode aufruft. Wenn eine Aktivität abgebrochen wird, kennzeichnet die Laufzeitumgebung die Aktivität für den Abbruch und führt automatisch bestimmte Aufräumarbeiten durch. Wenn die Aktivität nur über ausstehende Lesezeichen verfügt, werden die Lesezeichen entfernt, und die Aktivität wird als Canceled markiert. Alle ausstehenden Kindaktivitäten von der abgebrochenen Aktivität werden dann ebenfalls abgebrochen. Jeder Versuch zur Planung zusätzlicher untergeordneter Aktivitäten wird ignoriert, und die Aktivität wird als Canceled markiert. Wenn eine ausstehende untergeordnete Aktivität im Zustand Canceled oder Faulted abgeschlossen wird, wird die Aktivität als Canceled markiert. Beachten Sie, dass eine Abbruchanforderung ignoriert werden kann. Wenn eine Aktivität nicht über ausstehende Lesezeichen oder ausgeführte untergeordnete Aktivitäten verfügt und keine zusätzlichen Arbeitselemente plant, nachdem sie für einen Abbruch gekennzeichnet wurde, wird sie erfolgreich abgeschlossen. Dieser standardmäßige Abbruch ist für viele Szenarien ausreichen, wenn jedoch eine zusätzliche Abbruchlogik erforderlich ist, können die integrierten Abbruchaktivitäten oder benutzerdefinierte Aktivitäten verwendet werden.
Im folgenden Beispiel ist die Cancel-Überschreibung einer auf NativeActivity basierenden, benutzerdefinierten ParallelForEach-Aktivität definiert. Wenn die Aktivität abgebrochen wird, behandelt diese Überschreibung die Abbruchlogik für die Aktivität. Dieses Beispiel ist Teil des Nicht-generischen ParallelForEach-Beispiels.
protected override void Cancel(NativeActivityContext context)
{
// If we do not have a completion condition then we can just
// use default logic.
if (this.CompletionCondition == null)
{
base.Cancel(context);
}
else
{
context.CancelChildren();
}
}
Von NativeActivity abgeleitete Aktivitäten können feststellen, ob ein Abbruch angefordert wurde, indem sie die IsCancellationRequested-Eigenschaft überprüfen und sich selbst als abgebrochen markieren, indem sie die MarkCanceled-Methode aufrufen. Durch Aufrufen von MarkCanceled wird eine Aktivität nicht sofort abgeschlossen. Wie üblich schließt die Laufzeit die Aktivität ab, wenn sie keine ausstehenden Aufgaben mehr aufweist; wenn jedoch MarkCanceled aufgerufen wird, ist der abschließende Zustand Canceled anstelle von Closed.
Abbruch mithilfe von AsyncCodeActivity
Auf AsyncCodeActivity basierende Aktivitäten können auch eine benutzerdefinierte Abbruchlogik bereitstellen, indem die Cancel-Methode überschrieben wird. Wenn diese Methode nicht überschrieben wird, wird keine Abbruchbehandlung ausgeführt, wenn die Aktivität abgebrochen wird. Im folgenden Beispiel ist die Cancel-Überschreibung einer auf AsyncCodeActivity basierenden, benutzerdefinierten ExecutePowerShell-Aktivität definiert. Wenn die Aktivität abgebrochen wird, wird das gewünschte Abbruchverhalten ausgeführt.
// Called by the runtime to cancel the execution of this asynchronous activity.
protected override void Cancel(AsyncCodeActivityContext context)
{
Pipeline pipeline = context.UserState as Pipeline;
if (pipeline != null)
{
pipeline.Stop();
DisposePipeline(pipeline);
}
base.Cancel(context);
}
Von AsyncCodeActivity abgeleitete Aktivitäten können bestimmen, ob ein Abbruch angefordert wurde, indem die IsCancellationRequested-Eigenschaft überprüft wird und sie sich selbst als abgebrochen markieren, indem die MarkCanceled-Methode aufgerufen wird.