Megosztás a következőn keresztül:


A WorkflowInvoker és a WorkflowApplication használata

A Windows Workflow Foundation (WF) számos módszert kínál a munkafolyamatok üzemeltetésére. WorkflowInvoker Egy munkafolyamat meghívásának egyszerű módja, mintha metódushívás lenne, és csak olyan munkafolyamatokhoz használható, amelyek nem használnak adatmegőrzést. WorkflowApplication Gazdagabb modellt biztosít a munkafolyamatok végrehajtásához, beleértve az életciklus-események értesítését, a végrehajtás-vezérlést, a könyvjelzők újraindítását és az adatmegőrzést. WorkflowServiceHost támogatja az üzenetkezelési tevékenységeket, és elsősorban munkafolyamat-szolgáltatásokhoz használják. Ez a témakör bemutatja a munkafolyamat-üzemeltetést és WorkflowApplicationa WorkflowInvoker . A munkafolyamatok üzemeltetésével WorkflowServiceHostkapcsolatos további információkért lásd: Workflow Services and Hosting Workflow Services – Áttekintés.

A WorkflowInvoker használata

WorkflowInvoker olyan modellt biztosít a munkafolyamatok végrehajtásához, mintha metódushívás lenne. A munkafolyamat WorkflowInvokermeghívásához hívja meg a Invoke metódust, és adja meg a meghívandó munkafolyamat munkafolyamat-definícióját. Ebben a példában a rendszer meghív egy WriteLine tevékenységet a következő használatával WorkflowInvoker: .

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

WorkflowInvoker.Invoke(wf);

Amikor egy munkafolyamatot meghív a rendszer WorkflowInvoker, a munkafolyamat a hívó szálon fut, a Invoke metódus pedig letiltja a munkafolyamat befejezéséig, beleértve a tétlen időt is. Ha olyan időtúllépési időközt szeretne konfigurálni, amelyben a munkafolyamatnak végre kell hajtania, használja a Invoke paramétert TimeSpan használó túlterhelések egyikét. Ebben a példában a munkafolyamat két különböző időtúllépési időközzel kétszer lesz meghívva. Az első munkafolyamat befejeződik, de a második nem.

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);
}

Feljegyzés

A TimeoutException rendszer csak akkor veti ki a hibát, ha az időtúllépési időköz elévül, és a munkafolyamat tétlenné válik a végrehajtás során. A megadott időtúllépési időköznél hosszabb ideig tartó munkafolyamat sikeresen befejeződik, ha a munkafolyamat nem válik tétlenné.

WorkflowInvoker A meghívási metódus aszinkron verzióit is biztosítja. További információ: InvokeAsync és BeginInvoke.

Munkafolyamat bemeneti argumentumainak beállítása

Az adatok a munkafolyamatba továbbíthatók olyan bemeneti paraméterek szótárával, amelyek argumentumnév alapján lesznek megadva, és amelyek a munkafolyamat bemeneti argumentumaihoz lesznek megfeleltetve. Ebben a példában egy WriteLine meghívás történik, és az argumentum értéke Text a bemeneti paraméterek szótárával van megadva.

Activity wf = new WriteLine();

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

WorkflowInvoker.Invoke(wf, inputs);

Munkafolyamat kimeneti argumentumainak beolvasása

A munkafolyamat kimeneti paraméterei a hívásból Invokevisszaadott kimeneti szótár használatával kérhetők le. Az alábbi példa egy olyan munkafolyamatot hív meg, amely egy olyan Divide tevékenységből áll, amely két bemeneti argumentumot és két kimeneti argumentumot tartalmaz. A munkafolyamat meghívásakor a rendszer átadja a arguments szótárt, amely tartalmazza az egyes bemeneti argumentumok értékeit, argumentumnév alapján. A visszahíváskor Invoke a függvény minden kimeneti argumentumot a szótárban outputs ad vissza, és argumentumnévvel is meg van adva.

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"]);

Ha a munkafolyamat származik ActivityWithResultpéldául CodeActivity<TResult> vagy Activity<TResult>, és a jól definiált Result kimeneti argumentum mellett kimeneti argumentumok is vannak, a további argumentumok lekéréséhez nem általános túlterhelést Invoke kell használni. Ehhez a munkafolyamat-definíciónak Invoke típusnak Activitykell lennie. Ebben a példában a tevékenység származikCodeActivity<int>Divide, de úgy van deklarálvaActivity, hogy a rendszer nem általános túlterhelést Invoke használ, amely argumentumok szótárát adja vissza egyetlen visszatérési érték helyett.

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"]);

A WorkflowApplication használata

WorkflowApplication számos funkciót biztosít a munkafolyamat-példányok kezeléséhez. WorkflowApplication a tényleges WorkflowInstance, a futtatókörnyezetet beágyazó, szálbiztos proxyként működik, és metódusokat biztosít a munkafolyamat-példányok létrehozásához és betöltéséhez, az életciklus-események szüneteltetéséhez és folytatásához, leállításához és értesítéséhez. Ha a munkafolyamatot a WorkflowApplicationlétrehozással WorkflowApplication szeretné futtatni, iratkozzon fel a kívánt életciklus-eseményekre, indítsa el a munkafolyamatot, majd várja meg, amíg befejeződik. Ebben a példában egy tevékenységből álló WriteLine munkafolyamat-definíció jön létre, és egy WorkflowApplication a megadott munkafolyamat-definícióval jön létre. Completed a rendszer kezeli, így a gazdagép értesítést kap a munkafolyamat befejezésekor, a munkafolyamatot egy hívással Runindítja el, majd a gazdagép megvárja a munkafolyamat befejezését. Amikor a munkafolyamat befejeződik, be van állítva a AutoResetEvent beállítás, és a gazdaalkalmazás folytathatja a végrehajtást, ahogy az alábbi példában is látható.

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();

WorkflowApplication Lifecycle Events

CompletedEmellett a gazdagép-szerzők értesítést kaphatnak a munkafolyamatok kiürítésekor (Unloaded), megszakításakor (Aborted), tétlenné (Idle és PersistableIdle) válik, vagy nem kezelt kivétel történik (OnUnhandledException). A munkafolyamat-alkalmazás fejlesztői kezelhetik ezeket az értesítéseket, és elvégezhetik a megfelelő műveletet az alábbi példában látható módon.

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;
};

Munkafolyamat bemeneti argumentumainak beállítása

Az adatok átadhatók egy munkafolyamatba, mivel a paraméterek szótárát használják, hasonlóan ahhoz, ahogyan az adatok továbbítása történik a használat WorkflowInvokersorán. A szótár minden eleme megfelel a megadott munkafolyamat bemeneti argumentumának. Ebben a példában egy tevékenységből álló WriteLine munkafolyamatot hív meg a rendszer, amelynek argumentuma Text a bemeneti paraméterek szótárával van megadva.

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();

Munkafolyamat kimeneti argumentumainak beolvasása

Amikor egy munkafolyamat befejeződik, a kimeneti argumentumok lekérhetők a kezelőben a Completed WorkflowApplicationCompletedEventArgs.Outputs szótár eléréséhez. Az alábbi példa egy munkafolyamatot üzemeltet a következővel WorkflowApplication: . A WorkflowApplication példányok létrehozása egy munkafolyamat-definícióval történik, amely egyetlen DiceRoll tevékenységből áll. A DiceRoll tevékenységnek két kimeneti argumentuma van, amelyek a kockatekercselési művelet eredményeit jelölik. Amikor a munkafolyamat befejeződik, a rendszer lekéri a kimeneteket a Completed kezelőben.

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();

Feljegyzés

WorkflowApplication és WorkflowInvoker vegyen fel egy bemeneti argumentumok szótárát, és adja vissza az argumentumok szótárát out . Ezek a szótárparaméterek, tulajdonságok és visszatérési értékek típusa.IDictionary<string, object> Az átadott szótárosztály tényleges példánya bármely olyan osztály lehet, amely megvalósítja IDictionary<string, object>a elemet. Ezekben a példákban Dictionary<string, object> a rendszer ezt használja. További információ a szótárakról: és IDictionary<TKey,TValue> Dictionary<TKey,TValue>.

Adatok továbbítása futó munkafolyamatba könyvjelzőkkel

A könyvjelzők az a mechanizmus, amellyel egy tevékenység passzívan várhat a folytatásra, és az adatok futó munkafolyamat-példányba való továbbításának mechanizmusa. Ha egy tevékenység adatokra vár, létrehozhat és regisztrálhat egy Bookmark visszahívási metódust, amelyet a Bookmark rendszer meghív a folytatáskor, ahogy az az alábbi példában is látható.

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);
    }

A végrehajtáskor a ReadLine tevékenység létrehoz egy Bookmark, egy visszahívást regisztrál, majd megvárja a Bookmark folytatást. A folytatáskor a tevékenység hozzárendeli ReadLine azokat az adatokat, amelyeket az Bookmark Result argumentummal együtt ad át. Ebben a példában létrejön egy munkafolyamat, amely a ReadLine tevékenység használatával gyűjti össze a felhasználó nevét, és megjeleníti azt a konzolablakban.

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);

ReadLine A tevékenység végrehajtásakor létrehoz egy Bookmark elnevezett UserName nevet, majd megvárja a könyvjelző folytatását. A gazdagép összegyűjti a kívánt adatokat, majd folytatja a Bookmark. A munkafolyamat folytatódik, megjeleníti a nevet, majd befejeződik.

A gazdaalkalmazás megvizsgálhatja a munkafolyamatot annak megállapításához, hogy vannak-e aktív könyvjelzők. Ezt egy példány metódusának WorkflowApplication meghívásával GetBookmarks vagy a WorkflowApplicationIdleEventArgs kezelőben Idle való vizsgálattal teheti meg.

Az alábbi példakód az előző példához hasonló, azzal a kivételsel, hogy az aktív könyvjelzők felsorolása a könyvjelző folytatása előtt történik. A munkafolyamat elindul, és a Bookmark létrehozás után a munkafolyamat tétlen állapotba kerül. GetBookmarks A munkafolyamat befejezésekor a következő kimenet jelenik meg a konzolon.

Hogy hívnak?
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());

Az alábbi példakód a WorkflowApplicationIdleEventArgs példány kezelőjének WorkflowApplication átadott Idle adatokat vizsgálja. Ebben a példában a tétlen munkafolyamatnak van egy Bookmark neve, amelynek a neve EnterGuessegy nevű ReadInttevékenység tulajdonában van. Ez a példakód a How to: Run a Workflow (Munkafolyamat futtatása) című témakörön alapul, amely az Első lépések oktatóanyag része. Ha a Idle lépés kezelőjét úgy módosítják, hogy az tartalmazza a példában szereplő kódot, a következő kimenet jelenik meg.

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();
};

Összegzés

WorkflowInvoker Egyszerű módot kínál a munkafolyamatok meghívására, és bár metódusokat biztosít az adatok munkafolyamat elején történő továbbításához és az adatok egy befejezett munkafolyamatból való kinyeréséhez, nem nyújt összetettebb forgatókönyveket, amelyek használhatók WorkflowApplication .