Delen via


WorkflowInvoker en WorkflowApplication gebruiken

Windows Workflow Foundation (WF) biedt verschillende methoden voor het hosten van werkstromen. WorkflowInvoker biedt een eenvoudige manier om een werkstroom aan te roepen alsof het een methode-aanroep is en alleen kan worden gebruikt voor werkstromen die geen persistentie gebruiken. WorkflowApplication biedt een uitgebreider model voor het uitvoeren van werkstromen met meldingen van levenscyclus-gebeurtenissen, uitvoeringsbeheer, hervatting van bladwijzers en persistentie. WorkflowServiceHost biedt ondersteuning voor berichtenactiviteiten en wordt voornamelijk gebruikt met werkstroomservices. In dit onderwerp maakt u kennis met werkstroomhosting met WorkflowInvoker en WorkflowApplication. Zie Het overzicht van Workflow Services en Hosting Workflow Services voor meer informatie over het hosten van werkstromenWorkflowServiceHost.

WorkflowInvoker gebruiken

WorkflowInvoker biedt een model voor het uitvoeren van een werkstroom alsof het een methode-aanroep was. Als u een werkstroom wilt aanroepen met behulp WorkflowInvokervan, roept u de Invoke methode aan en geeft u de werkstroomdefinitie van de werkstroom door die moet worden aangeroepen. In dit voorbeeld wordt een WriteLine activiteit aangeroepen met behulp van WorkflowInvoker.

Activity wf = new WriteLine
{
    Text = "Hello World."
};

WorkflowInvoker.Invoke(wf);

Wanneer een werkstroom wordt aangeroepen met behulp WorkflowInvokervan, wordt de werkstroom uitgevoerd op de aanroepende thread en de Invoke methodeblokken totdat de werkstroom is voltooid, inclusief niet-actieve tijd. Als u een time-outinterval wilt configureren waarin de werkstroom moet worden voltooid, gebruikt u een van de Invoke overbelastingen die een TimeSpan parameter gebruiken. In dit voorbeeld wordt een werkstroom twee keer aangeroepen met twee verschillende time-outintervallen. De eerste werkstroom wordt voltooid, maar de tweede niet.

Activity wf = new Sequence()
{
    Activities =
    {
        new WriteLine()
        {
            Text = "Before the 1 minute delay."
        },
        new Delay()
        {
            Duration = TimeSpan.FromMinutes(1)
        },
        new WriteLine()
        {
            Text = "After the 1 minute delay."
        }
    }
};

// This workflow completes successfully.
WorkflowInvoker.Invoke(wf, TimeSpan.FromMinutes(2));

// This workflow does not complete and a TimeoutException
// is thrown.
try
{
    WorkflowInvoker.Invoke(wf, TimeSpan.FromSeconds(30));
}
catch (TimeoutException ex)
{
    Console.WriteLine(ex.Message);
}

Notitie

De TimeoutException fout wordt alleen gegenereerd als het time-outinterval is verstreken en de werkstroom niet actief wordt tijdens de uitvoering. Een werkstroom die langer duurt dan het opgegeven time-outinterval, wordt voltooid als de werkstroom niet inactief wordt.

WorkflowInvoker biedt ook asynchrone versies van de aanroepmethode. Zie voor meer informatie InvokeAsync en BeginInvoke.

Invoerargumenten van een werkstroom instellen

Gegevens kunnen worden doorgegeven aan een werkstroom met behulp van een woordenlijst met invoerparameters, gesleuteld op argumentnaam, die zijn toegewezen aan de invoerargumenten van de werkstroom. In dit voorbeeld wordt een aangeroepen WriteLine en wordt de waarde voor het Text argument opgegeven met behulp van de woordenlijst met invoerparameters.

Activity wf = new WriteLine();

Dictionary<string, object> inputs = new Dictionary<string, object>();
inputs.Add("Text", "Hello World.");

WorkflowInvoker.Invoke(wf, inputs);

Uitvoerargumenten van een werkstroom ophalen

De uitvoerparameters van een werkstroom kunnen worden verkregen met behulp van de uitvoerwoordenlijst die wordt geretourneerd door de aanroep naar Invoke. In het volgende voorbeeld wordt een werkstroom aangeroepen die bestaat uit één Divide activiteit met twee invoerargumenten en twee uitvoerargumenten. Wanneer de werkstroom wordt aangeroepen, wordt de arguments woordenlijst doorgegeven die de waarden voor elk invoerargument bevat, gesleuteld op argumentnaam. Wanneer de aanroep die moet Invoke worden geretourneerd, wordt elk uitvoerargument geretourneerd in de outputs woordenlijst, ook op basis van de argumentnaam.

public sealed class Divide : CodeActivity
{
    [RequiredArgument]
    public InArgument<int> Dividend { get; set; }

    [RequiredArgument]
    public InArgument<int> Divisor { get; set; }

    public OutArgument<int> Remainder { get; set; }
    public OutArgument<int> Result { get; set; }

    protected override void Execute(CodeActivityContext context)
    {
        int quotient = Dividend.Get(context) / Divisor.Get(context);
        int remainder = Dividend.Get(context) % Divisor.Get(context);

        Result.Set(context, quotient);
        Remainder.Set(context, remainder);
    }
}
int dividend = 500;
int divisor = 36;

Dictionary<string, object> arguments = new Dictionary<string, object>();
arguments.Add("Dividend", dividend);
arguments.Add("Divisor", divisor);

IDictionary<string, object> outputs =
    WorkflowInvoker.Invoke(new Divide(), arguments);

Console.WriteLine("{0} / {1} = {2} Remainder {3}",
    dividend, divisor, outputs["Result"], outputs["Remainder"]);

Als de werkstroom is afgeleid van ActivityWithResult, zoals CodeActivity<TResult> of Activity<TResult>, en er uitvoerargumenten zijn naast het goed gedefinieerde Result uitvoerargument, moet een niet-algemene overbelasting van Invoke de werkstroom worden gebruikt om de extra argumenten op te halen. Hiervoor moet de doorgegeven Invoke werkstroomdefinitie van het type Activityzijn. In dit voorbeeld is de Divide activiteit afgeleid van CodeActivity<int>, maar wordt gedeclareerd als Activity zodanig dat een niet-algemene overbelasting wordt Invoke gebruikt die een woordenlijst met argumenten retourneert in plaats van één retourwaarde.

public sealed class Divide : CodeActivity<int>
{
    public InArgument<int> Dividend { get; set; }
    public InArgument<int> Divisor { get; set; }
    public OutArgument<int> Remainder { get; set; }

    protected override int Execute(CodeActivityContext context)
    {
        int quotient = Dividend.Get(context) / Divisor.Get(context);
        int remainder = Dividend.Get(context) % Divisor.Get(context);

        Remainder.Set(context, remainder);

        return quotient;
    }
}
int dividend = 500;
int divisor = 36;

Dictionary<string, object> arguments = new Dictionary<string, object>();
arguments.Add("Dividend", dividend);
arguments.Add("Divisor", divisor);

Activity wf = new Divide();

IDictionary<string, object> outputs =
    WorkflowInvoker.Invoke(wf, arguments);

Console.WriteLine("{0} / {1} = {2} Remainder {3}",
    dividend, divisor, outputs["Result"], outputs["Remainder"]);

WorkflowApplication gebruiken

WorkflowApplication biedt een uitgebreide set functies voor beheer van werkstroomexemplaren. WorkflowApplication fungeert als een thread-veilige proxy voor de werkelijke WorkflowInstanceproxy, die de runtime inkapselt en biedt methoden voor het maken en laden van werkstroomexemplaren, het onderbreken en hervatten, beëindigen en melden van levenscyclus-gebeurtenissen. Als u een werkstroom wilt uitvoeren met behulp van WorkflowApplication het maken van de WorkflowApplicationwerkstroom, abonneert u zich op eventuele gewenste levenscyclus-gebeurtenissen, start u de werkstroom en wacht u tot deze is voltooid. In dit voorbeeld wordt een werkstroomdefinitie gemaakt die bestaat uit een WriteLine activiteit en wordt er een WorkflowApplication gemaakt met behulp van de opgegeven werkstroomdefinitie. Completed wordt verwerkt zodat de host wordt gewaarschuwd wanneer de werkstroom is voltooid, de werkstroom wordt gestart met een aanroep naar Runen vervolgens wacht de host totdat de werkstroom is voltooid. Wanneer de werkstroom is voltooid, wordt de AutoResetEvent set ingesteld en kan de hosttoepassing de uitvoering hervatten, zoals wordt weergegeven in het volgende voorbeeld.

AutoResetEvent syncEvent = new AutoResetEvent(false);

Activity wf = new WriteLine
{
    Text = "Hello World."
};

// Create the WorkflowApplication using the desired
// workflow definition.
WorkflowApplication wfApp = new WorkflowApplication(wf);

// Handle the desired lifecycle events.
wfApp.Completed = delegate (WorkflowApplicationCompletedEventArgs e)
{
    syncEvent.Set();
};

// Start the workflow.
wfApp.Run();

// Wait for Completed to arrive and signal that
// the workflow is complete.
syncEvent.WaitOne();

Levenscyclusgebeurtenissen van WorkflowApplication

Daarnaast Completedkunnen hostauteurs op de hoogte worden gesteld wanneer een werkstroom wordt verwijderd (Unloaded), afgebroken (Aborted), niet-actief (Idle en PersistableIdle) wordt of er een onverwerkte uitzondering optreedt (OnUnhandledException). Ontwikkelaars van werkstroomtoepassingen kunnen deze meldingen afhandelen en de juiste actie ondernemen, zoals wordt weergegeven in het volgende voorbeeld.

wfApp.Completed = delegate (WorkflowApplicationCompletedEventArgs e)
{
    if (e.CompletionState == ActivityInstanceState.Faulted)
    {
        Console.WriteLine("Workflow {0} Terminated.", e.InstanceId);
        Console.WriteLine("Exception: {0}\n{1}",
            e.TerminationException.GetType().FullName,
            e.TerminationException.Message);
    }
    else if (e.CompletionState == ActivityInstanceState.Canceled)
    {
        Console.WriteLine("Workflow {0} Canceled.", e.InstanceId);
    }
    else
    {
        Console.WriteLine("Workflow {0} Completed.", e.InstanceId);

        // Outputs can be retrieved from the Outputs dictionary,
        // keyed by argument name.
        // Console.WriteLine("The winner is {0}.", e.Outputs["Winner"]);
    }
};

wfApp.Aborted = delegate (WorkflowApplicationAbortedEventArgs e)
{
    // Display the exception that caused the workflow
    // to abort.
    Console.WriteLine("Workflow {0} Aborted.", e.InstanceId);
    Console.WriteLine("Exception: {0}\n{1}",
        e.Reason.GetType().FullName,
        e.Reason.Message);
};

wfApp.Idle = delegate (WorkflowApplicationIdleEventArgs e)
{
    // Perform any processing that should occur
    // when a workflow goes idle. If the workflow can persist,
    // both Idle and PersistableIdle are called in that order.
    Console.WriteLine("Workflow {0} Idle.", e.InstanceId);
};

wfApp.PersistableIdle = delegate (WorkflowApplicationIdleEventArgs e)
{
    // Instruct the runtime to persist and unload the workflow.
    // Choices are None, Persist, and Unload.
    return PersistableIdleAction.Unload;
};

wfApp.Unloaded = delegate (WorkflowApplicationEventArgs e)
{
    Console.WriteLine("Workflow {0} Unloaded.", e.InstanceId);
};

wfApp.OnUnhandledException = delegate (WorkflowApplicationUnhandledExceptionEventArgs e)
{
    // Display the unhandled exception.
    Console.WriteLine("OnUnhandledException in Workflow {0}\n{1}",
        e.InstanceId, e.UnhandledException.Message);

    Console.WriteLine("ExceptionSource: {0} - {1}",
        e.ExceptionSource.DisplayName, e.ExceptionSourceInstanceId);

    // Instruct the runtime to terminate the workflow.
    // Other choices are Abort and Cancel. Terminate
    // is the default if no OnUnhandledException handler
    // is present.
    return UnhandledExceptionAction.Terminate;
};

Invoerargumenten van een werkstroom instellen

Gegevens kunnen worden doorgegeven aan een werkstroom omdat deze wordt gestart met behulp van een woordenlijst met parameters, vergelijkbaar met de manier waarop gegevens worden doorgegeven wanneer ze worden gebruikt WorkflowInvoker. Elk item in de woordenlijst wordt toegewezen aan een invoerargument van de opgegeven werkstroom. In dit voorbeeld wordt een werkstroom die bestaat uit een WriteLine activiteit aangeroepen en wordt het Text argument opgegeven met behulp van de woordenlijst met invoerparameters.

AutoResetEvent syncEvent = new AutoResetEvent(false);

Activity wf = new WriteLine();

// Create the dictionary of input parameters.
Dictionary<string, object> inputs = new Dictionary<string, object>();
inputs.Add("Text", "Hello World!");

// Create the WorkflowApplication using the desired
// workflow definition and dictionary of input parameters.
WorkflowApplication wfApp = new WorkflowApplication(wf, inputs);

// Handle the desired lifecycle events.
wfApp.Completed = delegate (WorkflowApplicationCompletedEventArgs e)
{
    syncEvent.Set();
};

// Start the workflow.
wfApp.Run();

// Wait for Completed to arrive and signal that
// the workflow is complete.
syncEvent.WaitOne();

Uitvoerargumenten van een werkstroom ophalen

Wanneer een werkstroom is voltooid, kunnen alle uitvoerargumenten in de Completed handler worden opgehaald door toegang te krijgen tot de WorkflowApplicationCompletedEventArgs.Outputs woordenlijst. In het volgende voorbeeld wordt een werkstroom gehost met behulp van WorkflowApplication. Een WorkflowApplication exemplaar wordt samengesteld met behulp van een werkstroomdefinitie die bestaat uit één DiceRoll activiteit. De DiceRoll activiteit heeft twee uitvoerargumenten die de resultaten van de dobbelsteendraaibewerking vertegenwoordigen. Wanneer de werkstroom is voltooid, worden de uitvoer opgehaald in de Completed handler.

public sealed class DiceRoll : CodeActivity
{
    public OutArgument<int> D1 { get; set; }
    public OutArgument<int> D2 { get; set; }

    static Random r = new Random();

    protected override void Execute(CodeActivityContext context)
    {
        D1.Set(context, r.Next(1, 7));
        D2.Set(context, r.Next(1, 7));
    }
}
// Create a WorkflowApplication instance.
WorkflowApplication wfApp = new WorkflowApplication(new DiceRoll());

// Subscribe to any desired workflow lifecycle events.
wfApp.Completed = delegate (WorkflowApplicationCompletedEventArgs e)
{
    if (e.CompletionState == ActivityInstanceState.Faulted)
    {
        Console.WriteLine("Workflow {0} Terminated.", e.InstanceId);
        Console.WriteLine("Exception: {0}\n{1}",
            e.TerminationException.GetType().FullName,
            e.TerminationException.Message);
    }
    else if (e.CompletionState == ActivityInstanceState.Canceled)
    {
        Console.WriteLine("Workflow {0} Canceled.", e.InstanceId);
    }
    else
    {
        Console.WriteLine("Workflow {0} Completed.", e.InstanceId);

        // Outputs can be retrieved from the Outputs dictionary,
        // keyed by argument name.
        Console.WriteLine("The two dice are {0} and {1}.",
            e.Outputs["D1"], e.Outputs["D2"]);
    }
};

// Run the workflow.
wfApp.Run();

Notitie

WorkflowApplication en WorkflowInvoker neem een woordenlijst met invoerargumenten en retourneer een woordenlijst met out argumenten. Deze woordenlijstparameters, eigenschappen en retourwaarden zijn van het type IDictionary<string, object>. Het werkelijke exemplaar van de woordenlijstklasse die wordt doorgegeven, kan elke klasse zijn die wordt geïmplementeerd IDictionary<string, object>. In deze voorbeelden Dictionary<string, object> wordt gebruikt. Zie en Dictionary<TKey,TValue>voor meer informatie over woordenlijstenIDictionary<TKey,TValue>.

Gegevens doorgeven aan een actieve werkstroom met behulp van bladwijzers

Bladwijzers zijn het mechanisme waarmee een activiteit passief kan wachten om te worden hervat en een mechanisme is voor het doorgeven van gegevens aan een actieve werkstroominstantie. Als een activiteit wacht op gegevens, kan deze een Bookmark callback-methode maken en registreren die moet worden aangeroepen wanneer de Bookmark activiteit wordt hervat, zoals wordt weergegeven in het volgende voorbeeld.

public sealed class ReadLine : NativeActivity<string>
{
    [RequiredArgument]
    public InArgument<string> BookmarkName { get; set; }

    protected override void Execute(NativeActivityContext context)
    {
        // Create a Bookmark and wait for it to be resumed.
        context.CreateBookmark(BookmarkName.Get(context),
            new BookmarkCallback(OnResumeBookmark));
    }

    // NativeActivity derived activities that do asynchronous operations by calling
    // one of the CreateBookmark overloads defined on System.Activities.NativeActivityContext
    // must override the CanInduceIdle property and return true.
    protected override bool CanInduceIdle
    {
        get { return true; }
    }

    public void OnResumeBookmark(NativeActivityContext context, Bookmark bookmark, object obj)
    {
        // When the Bookmark is resumed, assign its value to
        // the Result argument.
        Result.Set(context, (string)obj);
    }

Wanneer de ReadLine activiteit wordt uitgevoerd, wordt er een Bookmarkcallback gemaakt, wordt er een callback geregistreerd en wordt gewacht totdat de Bookmark activiteit is hervat. Wanneer deze wordt hervat, wijst de ReadLine activiteit de gegevens toe die met het Bookmark Result argument zijn doorgegeven. In dit voorbeeld wordt een werkstroom gemaakt die gebruikmaakt van de activiteit om de ReadLine naam van de gebruiker te verzamelen en weer te geven in het consolevenster.

Variable<string> name = new Variable<string>();

Activity wf = new Sequence
{
    Variables = { name },
    Activities =
     {
         new WriteLine
         {
             Text = "What is your name?"
         },
         new ReadLine
         {
             BookmarkName = "UserName",
             Result = new OutArgument<string>(name)
         },
         new WriteLine
         {
             Text = new InArgument<string>((env) =>
                 ("Hello, " + name.Get(env)))
         }
     }
};

// Create a WorkflowApplication instance.
WorkflowApplication wfApp = new WorkflowApplication(wf);

// Workflow lifecycle events omitted except idle.
AutoResetEvent idleEvent = new AutoResetEvent(false);

wfApp.Idle = delegate (WorkflowApplicationIdleEventArgs e)
{
    idleEvent.Set();
};

// Run the workflow.
wfApp.Run();

// Wait for the workflow to go idle before gathering
// the user's input.
idleEvent.WaitOne();

// Gather the user's input and resume the bookmark.
// Bookmark resumption only occurs when the workflow
// is idle. If a call to ResumeBookmark is made and the workflow
// is not idle, ResumeBookmark blocks until the workflow becomes
// idle before resuming the bookmark.
BookmarkResumptionResult result = wfApp.ResumeBookmark("UserName",
    Console.ReadLine());

// Possible BookmarkResumptionResult values:
// Success, NotFound, or NotReady
Console.WriteLine("BookmarkResumptionResult: {0}", result);

Wanneer de ReadLine activiteit wordt uitgevoerd, wordt er een Bookmark benoemde gemaakt UserName en wordt gewacht totdat de bladwijzer is hervat. De host verzamelt de gewenste gegevens en hervat vervolgens de Bookmark. De werkstroom wordt hervat, de naam wordt weergegeven en vervolgens voltooid.

De hosttoepassing kan de werkstroom inspecteren om te bepalen of er actieve bladwijzers zijn. Dit kan door de GetBookmarks methode van een WorkflowApplication exemplaar aan te roepen of door de WorkflowApplicationIdleEventArgs Idle handler te inspecteren.

Het volgende codevoorbeeld lijkt op het vorige voorbeeld, behalve dat de actieve bladwijzers worden geïnventariseerd voordat de bladwijzer wordt hervat. De werkstroom wordt gestart en zodra de Bookmark werkstroom is gemaakt en de werkstroom inactief gaat, GetBookmarks wordt aangeroepen. Wanneer de werkstroom is voltooid, wordt de volgende uitvoer weergegeven in de console.

Hoe heet u?
BookmarkName: UserName - OwnerDisplayName: ReadLineSteveHello, Steve

Variable<string> name = new Variable<string>();

Activity wf = new Sequence
{
    Variables = { name },
    Activities =
     {
         new WriteLine
         {
             Text = "What is your name?"
         },
         new ReadLine
         {
             BookmarkName = "UserName",
             Result = new OutArgument<string>(name)
         },
         new WriteLine
         {
             Text = new InArgument<string>((env) =>
                 ("Hello, " + name.Get(env)))
         }
     }
};

// Create a WorkflowApplication instance.
WorkflowApplication wfApp = new WorkflowApplication(wf);

// Workflow lifecycle events omitted except idle.
AutoResetEvent idleEvent = new AutoResetEvent(false);

wfApp.Idle = delegate (WorkflowApplicationIdleEventArgs e)
{
    // You can also inspect the bookmarks from the Idle handler
    // using e.Bookmarks

    idleEvent.Set();
};

// Run the workflow.
wfApp.Run();

// Wait for the workflow to go idle and give it a chance
// to create the Bookmark.
idleEvent.WaitOne();

// Inspect the bookmarks
foreach (BookmarkInfo info in wfApp.GetBookmarks())
{
    Console.WriteLine("BookmarkName: {0} - OwnerDisplayName: {1}",
        info.BookmarkName, info.OwnerDisplayName);
}

// Gather the user's input and resume the bookmark.
wfApp.ResumeBookmark("UserName", Console.ReadLine());

In het volgende codevoorbeeld wordt de WorkflowApplicationIdleEventArgs doorgegeven in de Idle handler van een WorkflowApplication exemplaar gecontroleerd. In dit voorbeeld heeft de werkstroom die inactief wordt een Bookmark werkstroom met een naam van , die eigendom is van EnterGuesseen activiteit met de naam ReadInt. Dit codevoorbeeld is gebaseerd op Instructies: Een werkstroom uitvoeren, die deel uitmaakt van de zelfstudie Aan de slag. Als de Idle handler in die stap wordt gewijzigd om de code uit dit voorbeeld te bevatten, wordt de volgende uitvoer weergegeven.

BookmarkName: EnterGuess - OwnerDisplayName: ReadInt

wfApp.Idle = delegate (WorkflowApplicationIdleEventArgs e)
{
    foreach (BookmarkInfo info in e.Bookmarks)
    {
        Console.WriteLine("BookmarkName: {0} - OwnerDisplayName: {1}",
            info.BookmarkName, info.OwnerDisplayName);
    }

    idleEvent.Set();
};

Samenvatting

WorkflowInvoker biedt een eenvoudige manier om werkstromen aan te roepen en hoewel het methoden biedt voor het doorgeven van gegevens aan het begin van een werkstroom en het extraheren van gegevens uit een voltooide werkstroom, biedt het geen complexere scenario's die WorkflowApplication kunnen worden gebruikt.