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 EnterGuess
egy nevű ReadInt
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: {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 .