Megjegyzés
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhat bejelentkezni vagy módosítani a címtárat.
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhatja módosítani a címtárat.
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 a WorkflowInvoker és a WorkflowApplication segítségével. 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 egy WriteLine tevékenységet hívnak meg az WorkflowInvoker használatával.
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, és a Invoke metódus blokkolja a szálat a munkafolyamat befejezéséig, beleértve a tétlen időt is. Az időkorlát intervallumának beállításához, amelyen belül a munkafolyamatnak be kell fejeződnie, használja a Invoke paramétert tartalmazó TimeSpan túlterhelési lehetőségek 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);
}
Megjegyzés
A TimeoutException csak akkor vet ki hibát, ha az időkorlát letelik, és a munkafolyamat végrehajtás közben tétlenné válik. 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 lekérhetők a Invoke hívásból visszakapott kimeneti szótár használatával. 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 Invoke függvény hívása után minden kimeneti argumentumot a outputs szótár ad vissza, az argumentum neve alapján kulcsolva.
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($"{dividend} / {divisor} = {outputs["Result"]} Remainder {outputs["Remainder"]}");
Ha a munkafolyamat a ActivityWithResult-ból származik, mint például a CodeActivity<TResult> vagy a Activity<TResult>, és a jól definiált Result kimeneti argumentum mellett további kimeneti argumentumok is vannak, akkor a további argumentumok lekéréséhez a nem általános Invoke túlterhelést kell használni. Ehhez a munkafolyamat-definíciónak Invoke típusnak Activitykell lennie. Ebben a példában a Divide tevékenység a CodeActivity<int>-ból/ből származik, de úgy van deklarálva, mint Activity, hogy a rendszer egy nem általanos túlterhelést használjon Invoke, 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($"{dividend} / {divisor} = {outputs["Result"]} Remainder {outputs["Remainder"]}");
A WorkflowApplication használata
WorkflowApplication számos funkciót biztosít a munkafolyamat-példányok kezeléséhez. WorkflowApplication szálbiztos proxyként működik a tényleges WorkflowInstance számára, amely a futtatókörnyezetet beágyazza, és metódusokat biztosít a munkafolyamat-példányok létrehozásához és betöltéséhez, szüneteltetéséhez és folytatásához, leállításához, valamint az életciklus-események értesítéséhez. A munkafolyamat futtatásához a WorkflowApplication használatával először hozza létre a WorkflowApplication-t, 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. A Completed kezelése úgy történik, hogy a gazdagép értesítést kap, amikor a munkafolyamat befejeződik. A munkafolyamat egy Run hívással indul el, majd a gazdagép megvárja annak 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();
A WorkflowApplication életciklus eseményei
Emellett a gazdagép-szerzők értesítést kaphatnak, amikor egy munkafolyamat betöltésének megszüntetése vagy megszakítása történik (Completed, Unloaded), tétlenné válik (Aborted és Idle), vagy ha nem kezelt kivétel fordul elő (PersistableIdle). 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 {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.");
// Outputs can be retrieved from the Outputs dictionary,
// keyed by argument name.
// Console.WriteLine($"The winner is {e.Outputs["Winner"]}.");
}
};
wfApp.Aborted = delegate (WorkflowApplicationAbortedEventArgs e)
{
// Display the exception that caused the workflow
// to abort.
Console.WriteLine($"Workflow {e.InstanceId} Aborted.");
Console.WriteLine($"Exception: {e.Reason.GetType().FullName}\n{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 {e.InstanceId} Idle.");
};
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 {e.InstanceId} Unloaded.");
};
wfApp.OnUnhandledException = delegate (WorkflowApplicationUnhandledExceptionEventArgs e)
{
// Display the unhandled exception.
Console.WriteLine($"OnUnhandledException in Workflow {e.InstanceId}\n{e.UnhandledException.Message}");
Console.WriteLine($"ExceptionSource: {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 a munkafolyamat indításakor adhatók át egy paraméterszótár használatával, hasonlóan ahhoz, ahogyan az adatok továbbítása történik a WorkflowInvoker használata sorá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érdezhetők a Completed kezelőben a WorkflowApplicationCompletedEventArgs.Outputs szótár elérésével. 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 kimenetek a Completed kezelőben kerülnek lekérésre.
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 {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.");
// Outputs can be retrieved from the Outputs dictionary,
// keyed by argument name.
Console.WriteLine($"The two dice are {e.Outputs["D1"]} and {e.Outputs["D2"]}.");
}
};
// Run the workflow.
wfApp.Run();
Megjegyzés
WorkflowApplication és WorkflowInvoker elfogad egy bemeneti argumentumok szótárát, és visszaad egy out argumentumok szótárát. Ezeknek a szótárparamétereknek, tulajdonságoknak és visszatérési értékeknek a 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 a Dictionary<string, object> van használatban. További információ a szótárakról a IDictionary<TKey,TValue> és Dictionary<TKey,TValue> résznél található.
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, regisztrál egy visszahívást, majd megvárja a Bookmark folytatását. A folytatáskor a ReadLine tevékenység hozzárendeli azokat az adatokat, amelyeket az Bookmark által továbbított Result argumentumnak. 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: {result}");
ReadLine A tevékenység végrehajtásakor létrehoz egy `Bookmark` nevű `UserName`-t, majd megvárja a könyvjelző folytatását. A kiszolgáló ö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 a GetBookmarks példány WorkflowApplication metódusának meghívásával vagy a WorkflowApplicationIdleEventArgs kezelőben a Idle vizsgálatával 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 amikor a Bookmark létrejön, a munkafolyamat tétlen állapotba kerül, majd meghívódik a 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: {info.BookmarkName} - OwnerDisplayName: {info.OwnerDisplayName}");
}
// Gather the user's input and resume the bookmark.
wfApp.ResumeBookmark("UserName", Console.ReadLine());
A következő példakód megvizsgálja a WorkflowApplicationIdleEventArgs-t, amely a Idle példány WorkflowApplication kezelőjéhez lett továbbítva. Ebben a példában a tétlen munkafolyamatnak van egy Bookmark, amelynek a neve EnterGuess, és amely egy ReadInt nevű tevé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: {info.BookmarkName} - OwnerDisplayName: {info.OwnerDisplayName}");
}
idleEvent.Set();
};
Összefoglalá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 .