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


Munkafolyamatok, tevékenységek és kifejezések készítése imperatív kóddal

A munkafolyamat-definíció a konfigurált tevékenységobjektumok fája. Ez a tevékenységfa sokféleképpen definiálható, például az XAML kézi szerkesztésével vagy a Munkafolyamat Tervező használatával az XAML előállításához. Az XAML használata azonban nem követelmény. A munkafolyamat-definíciók programozott módon is létrehozhatók. Ez a témakör áttekintést nyújt a munkafolyamat-definíciók, tevékenységek és kifejezések kód használatával történő létrehozásáról. Példák az XAML-munkafolyamatok kód használatával történő használatára, lásd : Munkafolyamatok és tevékenységek szerializálása az XAML-be és onnan.

Munkafolyamat-definíciók létrehozása

A munkafolyamat-definíciók létrehozhatóak egy tevékenységtípus példányának példányainak példányosításával és a tevékenységobjektum tulajdonságainak konfigurálásával. A gyermektevékenységeket nem tartalmazó tevékenységek esetében ez néhány sornyi kóddal végezhető el.

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

WorkflowInvoker.Invoke(wf);

Feljegyzés

A jelen témakör példái a minta-munkafolyamatok futtatására használhatók WorkflowInvoker . A munkafolyamatok meghívásáról, az argumentumok átadásáról és az elérhető különböző üzemeltetési lehetőségekről további információt a WorkflowInvoker és a WorkflowApplication használata című témakörben talál.

Ebben a példában egyetlen tevékenységből álló WriteLine munkafolyamat jön létre. A WriteLine tevékenység argumentuma Text be van állítva, és a rendszer meghívja a munkafolyamatot. Ha egy tevékenység gyermektevékenységeket tartalmaz, az építés módja hasonló. Az alábbi példa egy Sequence két WriteLine tevékenységet tartalmazó tevékenységet használ.

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

WorkflowInvoker.Invoke(wf);

Objektum-inicializálók használata

A jelen témakör példái objektum inicializálási szintaxist használnak. Az objektum inicializálási szintaxisa hasznos lehet a munkafolyamat-definíciók kódban való létrehozásához, mivel hierarchikus nézetet biztosít a munkafolyamat tevékenységeiről, és megjeleníti a tevékenységek közötti kapcsolatot. Munkafolyamatok programozott létrehozásakor nincs szükség objektum inicializálási szintaxis használatára. Az alábbi példa funkcionálisan egyenértékű az előző példával.

WriteLine hello = new WriteLine();
hello.Text = "Hello";

WriteLine world = new WriteLine();
world.Text = "World";

Sequence wf = new Sequence();
wf.Activities.Add(hello);
wf.Activities.Add(world);

WorkflowInvoker.Invoke(wf);

Az objektum-inicializálókkal kapcsolatos további információkért lásd : Az objektumok inicializálása konstruktor meghívása nélkül (C# programozási útmutató) és útmutató: Objektum deklarálása objektum inicializáló használatával.

Változók, literális értékek és kifejezések használata

Amikor kóddal hoz létre munkafolyamat-definíciót, vegye figyelembe, hogy a munkafolyamat-definíció létrehozása során milyen kód fut, és hogy milyen kód fut a munkafolyamat egy példányának végrehajtása során. Az alábbi munkafolyamat célja például egy véletlenszerű szám létrehozása és a konzolba való írása.

Variable<int> n = new Variable<int>
{
    Name = "n"
};

Activity wf = new Sequence
{
    Variables = { n },
    Activities =
    {
        new Assign<int>
        {
            To = n,
            Value = new Random().Next(1, 101)
        },
        new WriteLine
        {
            Text = new InArgument<string>((env) => "The number is " + n.Get(env))
        }
    }
};

A munkafolyamat-definíciós kód végrehajtásakor a rendszer meghívja a hívást Random.Next , és az eredmény a munkafolyamat-definícióban literális értékként lesz tárolva. A munkafolyamat számos példánya meghívható, és mindegyik ugyanazt a számot jeleníti meg. Ha azt szeretné, hogy a véletlenszerű számgenerálás a munkafolyamat végrehajtása során történjen, egy olyan kifejezést kell használni, amelyet a rendszer minden alkalommal kiértékel, amikor a munkafolyamat fut. Az alábbi példában egy Visual Basic-kifejezést használunk egy VisualBasicValue<TResult>.

new Assign<int>
{
    To = n,
    Value = new VisualBasicValue<int>("New Random().Next(1, 101)")
}

Az előző példában szereplő kifejezés egy és egy CSharpValue<TResult> C# kifejezéssel is implementálható.

new Assign<int>  
{  
    To = n,  
    Value = new CSharpValue<int>("new Random().Next(1, 101)")  
}  

A C#-kifejezéseket az őket tartalmazó munkafolyamat meghívása előtt kell lefordítani. Ha a C#-kifejezések nincsenek lefordítva, NotSupportedException a rendszer a következőhöz hasonló üzenettel hívja meg a munkafolyamatot: Expression Activity type 'CSharpValue`1' requires compilation in order to run. Please ensure that the workflow has been compiled. A Visual Studióban létrehozott munkafolyamatokat tartalmazó legtöbb forgatókönyvben a C#-kifejezések automatikusan lesznek lefordítva, de bizonyos helyzetekben, például kód-munkafolyamatokban a C#-kifejezéseket manuálisan kell lefordítani. A C#-kifejezések fordítására a C#-kifejezések témakör kód-munkafolyamatokban című szakaszában talál példát.

Az A VisualBasicValue<TResult> kifejezés a Visual Basic szintaxisában olyan kifejezést jelöl, amely r-értékként használható egy kifejezésben, a C# szintaxisban pedig egy CSharpValue<TResult> olyan kifejezést jelöl, amely r-értékként használható egy kifejezésben. Ezeket a kifejezéseket a rendszer minden alkalommal kiértékeli, amikor az adott tevékenységet végrehajtja. A kifejezés eredménye a munkafolyamat változóhoz nvan rendelve, és ezeket az eredményeket a munkafolyamat következő tevékenysége használja. A munkafolyamat-változó n futásidejű értékének eléréséhez a ActivityContext szükséges. Ez a következő lambda kifejezéssel érhető el.

Feljegyzés

Vegye figyelembe, hogy mindkét kód példaként a C#-ot használja programozási nyelvként, de az egyik egy VisualBasicValue<TResult> , a másik pedig egy CSharpValue<TResult>. VisualBasicValue<TResult> és CSharpValue<TResult> Visual Basic- és C#-projektekben is használható. Alapértelmezés szerint a munkafolyamat-tervezőben létrehozott kifejezések megegyeznek az üzemeltetési projekt nyelvével. A munkafolyamatok kódban való létrehozásakor a kívánt nyelv a munkafolyamat-szerző saját belátása szerint történik.

Ezekben a példákban a kifejezés eredménye hozzá van rendelve a munkafolyamat változóhoz n, és ezeket az eredményeket a munkafolyamat következő tevékenysége használja. A munkafolyamat-változó n futásidejű értékének eléréséhez a ActivityContext szükséges. Ez a következő lambda kifejezéssel érhető el.

new WriteLine
{
    Text = new InArgument<string>((env) => "The number is " + n.Get(env))
}

A lambdakifejezésekről további információt a Lambda-kifejezések (C#-referencia) vagy a Lambda-kifejezések (Visual Basic) című témakörben talál.

A Lambda-kifejezések nem szerializálhatók XAML formátumban. Ha lambdakifejezésekkel próbál szerializálni egy munkafolyamatot, LambdaSerializationException a következő üzenet jelenik meg: "Ez a munkafolyamat a kódban megadott lambdakifejezéseket tartalmazza. Ezek a kifejezések nem XAML szerializálhatók. A munkafolyamat XAML-szerializálhatóvá tételéhez használja a VisualBasicValue/VisualBasicReference vagy a ExpressionServices.Convert(lambda) parancsot. Ez a lambda-kifejezéseket kifejezési tevékenységekké alakítja." Ha kompatibilissé szeretné tenni ezt a kifejezést az XAML-vel, használja és Converthasználja ExpressionServices az alábbi példában látható módon.

new WriteLine
{
    //Text = new InArgument<string>((env) => "The number is " + n.Get(env))
    Text = ExpressionServices.Convert((env) => "The number is " + n.Get(env))
}

A VisualBasicValue<TResult> is használható. Ne feledje, hogy Visual Basic-kifejezés használatakor nincs szükség lambda kifejezésre.

new WriteLine
{
    //Text = new InArgument<string>((env) => "The number is " + n.Get(env))
    //Text = ExpressionServices.Convert((env) => "The number is " + n.Get(env))
    Text = new VisualBasicValue<string>("\"The number is \" + n.ToString()")
}

Futásidőben a Visual Basic-kifejezések LINQ-kifejezésekké lesznek lefordítva. Mindkét előző példa szerializálható az XAML-hez, de ha a szerializált XAML-t a munkafolyamat-tervezőben szeretné megtekinteni és szerkeszteni, használja VisualBasicValue<TResult> a kifejezéseket. A szerializált munkafolyamatok, amelyeket használnak ExpressionServices.Convert , megnyithatók a tervezőben, de a kifejezés értéke üres lesz. A munkafolyamatok XAML-be való szerializálásával kapcsolatos további információkért lásd : Munkafolyamatok és tevékenységek szerializálása az XAML-be és onnan.

Literálkifejezések és hivatkozástípusok

A konstans kifejezéseket a tevékenység jeleníti meg a Literal<T> munkafolyamatokban. Az alábbi WriteLine tevékenységek funkcionálisan egyenértékűek.

new WriteLine  
{  
    Text = "Hello World."  
},  
new WriteLine  
{  
    Text = new Literal<string>("Hello World.")  
}  

Érvénytelen a literális kifejezés inicializálása bármilyen hivatkozástípussal, kivéve String. Az alábbi példában egy Assign tevékenység tulajdonsága Value egy literális kifejezéssel inicializálódik egy List<string>.

new Assign  
{  
    To = new OutArgument<List<string>>(items),  
    Value = new InArgument<List<string>>(new List<string>())  
},  

A tevékenységet tartalmazó munkafolyamat ellenőrzésekor a következő érvényesítési hiba jelenik meg: "A literál csak az értéktípusokat és a nem módosítható System.String típust támogatja. A System.Collections.Generic.List'1[System.String] típus nem használható literálként." Ha a munkafolyamat meghívása történik, a rendszer az InvalidWorkflowException érvényesítési hiba szövegét tartalmazza. Ez egy érvényesítési hiba, mert egy hivatkozástípussal rendelkező literális kifejezés létrehozása nem hoz létre új hivatkozástípus-példányt a munkafolyamat minden példányához. A probléma megoldásához cserélje le a literális kifejezést egy olyan kifejezésre, amely létrehozza és visszaadja a referenciatípus új példányát.

new Assign  
{  
    To = new OutArgument<List<string>>(items),  
    Value = new InArgument<List<string>>(new VisualBasicValue<List<string>>("New List(Of String)"))  
},  

A kifejezésekről további információt a Kifejezések című témakörben talál.

Metódusok meghívása objektumokon kifejezések és az InvokeMethod-tevékenység használatával

A InvokeMethod<TResult> tevékenység a .NET-keretrendszer osztályainak statikus és példánymetóriák meghívására használható. A jelen témakör egy korábbi példájában véletlenszerű szám jött létre az Random osztály használatával.

new Assign<int>
{
    To = n,
    Value = new VisualBasicValue<int>("New Random().Next(1, 101)")
}

A InvokeMethod<TResult> tevékenység az osztály metódusának meghívására NextRandom is használható.

new InvokeMethod<int>  
{  
    TargetObject = new InArgument<Random>(new VisualBasicValue<Random>("New Random()")),  
    MethodName = "Next",  
    Parameters =
    {  
        new InArgument<int>(1),  
        new InArgument<int>(101)  
    },  
    Result = n  
}  

Mivel Next ez nem statikus módszer, az Random osztály egy példánya lesz megadva a TargetObject tulajdonsághoz. Ebben a példában egy új példány egy Visual Basic-kifejezéssel jön létre, de korábban is létrehozhatta, és egy munkafolyamat-változóban tárolta. Ebben a példában egyszerűbb lenne a tevékenységet használni a Assign<T>InvokeMethod<TResult> tevékenység helyett. Ha a metódushívást végül vagy a Assign<T>InvokeMethod<TResult> tevékenységek hosszú ideig futtatják, akkor előnyt élvez, InvokeMethod<TResult> mivel rendelkezik egy tulajdonságtal RunAsynchronously . Ha ez a tulajdonság be van állítva true, a meghívott metódus aszinkron módon fog futni a munkafolyamat tekintetében. Ha más tevékenységek párhuzamosak, akkor a metódus aszinkron végrehajtása során nem lesznek blokkolva. Ha a meghívandó metódusnak nincs visszatérési értéke, akkor InvokeMethod<TResult> a metódus meghívásának megfelelő módja.

Argumentumok és dinamikus tevékenységek

A munkafolyamat-definíciók kódban jönnek létre a tevékenységek tevékenységfába való összeállításával, valamint a tulajdonságok és argumentumok konfigurálásával. A meglévő argumentumok kötöttek lehetnek, de új argumentumok nem adhatók hozzá a tevékenységekhez. Ide tartoznak a gyökértevékenységnek átadott munkafolyamat-argumentumok. Az imperatív kódban a munkafolyamat-argumentumok egy új CLR-típus tulajdonságaiként vannak megadva, az XAML-ben pedig a használatával x:Class és x:Membera . Mivel nem jön létre új CLR-típus, amikor a munkafolyamat-definíció memórián belüli objektumok fajaként jön létre, argumentumokat nem lehet hozzáadni. Az argumentumok azonban hozzáadhatók egy DynamicActivity. Ebben a példában egy DynamicActivity<TResult> olyan létrejön, amely két egész argumentumot vesz fel, összeadja őket, és visszaadja az eredményt. Minden DynamicActivityProperty argumentumhoz létrejön egy A, és a művelet eredménye hozzá lesz rendelve a .Result /> DynamicActivity<TResult>argumentumához.

InArgument<int> Operand1 = new InArgument<int>();
InArgument<int> Operand2 = new InArgument<int>();

DynamicActivity<int> wf = new DynamicActivity<int>
{
    Properties =
    {
        new DynamicActivityProperty
        {
            Name = "Operand1",
            Type = typeof(InArgument<int>),
            Value = Operand1
        },
        new DynamicActivityProperty
        {
            Name = "Operand2",
            Type = typeof(InArgument<int>),
            Value = Operand2
        }
    },

    Implementation = () => new Sequence
    {
        Activities =
        {
            new Assign<int>
            {
                To = new ArgumentReference<int> { ArgumentName = "Result" },
                Value = new InArgument<int>((env) => Operand1.Get(env) + Operand2.Get(env))
            }
        }
    }
};

Dictionary<string, object> wfParams = new Dictionary<string, object>
{
    { "Operand1", 25 },
    { "Operand2", 15 }
};

int result = WorkflowInvoker.Invoke(wf, wfParams);
Console.WriteLine(result);

A dinamikus tevékenységekkel kapcsolatos további információkért lásd : Tevékenység létrehozása a futtatókörnyezetben.

Lefordított tevékenységek

A dinamikus tevékenységek egy olyan tevékenység definiálására szolgálnak, amely kóddal tartalmaz argumentumokat, de a tevékenységek kódban is létrehozhatók, és típusok szerint fordíthatók le. Egyszerű tevékenységek hozhatók létre, amelyek származnak CodeActivity, és aszinkron tevékenységek származnak AsyncCodeActivity. Ezek a tevékenységek argumentumokkal, visszaadott értékekkel és imperatív kóddal definiálhatják logikájukat. Az ilyen típusú tevékenységek létrehozásának példáiért lásd: CodeActivity Alaposztály és Aszinkron tevékenységek létrehozása.

A származtatott NativeActivity tevékenységek imperatív kóddal definiálhatják a logikájukat, és olyan gyermektevékenységeket is tartalmazhatnak, amelyek meghatározzák a logikát. Teljes hozzáféréssel rendelkeznek a futtatókörnyezet funkcióihoz, például könyvjelzők létrehozásához. Példák a -based tevékenység létrehozására NativeActivity: NativeActivity Base Class, How to: Create an Activity, and the Custom Composite using Native Activity sample.

Azok a tevékenységek, amelyek a logikájuk meghatározásából Activity származnak, kizárólag gyermektevékenységek használatával. Ezeket a tevékenységeket általában a munkafolyamat-tervezővel hozzák létre, de kóddal is definiálhatók. Az alábbi példában egy Square olyan tevékenység van definiálva, amely a következőből Activity<int>származik: . A Square tevékenység egyetlen InArgument<T> névvel Valuerendelkezik, és a tulajdonságot használó tevékenység megadásával Sequence határozza meg a Implementation logikáját. A Sequence tevékenység egy WriteLine tevékenységet és egy Assign<T> tevékenységet tartalmaz. Ez a három tevékenység együttesen valósítja meg a tevékenység logikáját Square .

class Square : Activity<int>  
{  
    [RequiredArgument]  
    public InArgument<int> Value { get; set; }  
  
    public Square()  
    {  
        this.Implementation = () => new Sequence  
        {  
            Activities =  
            {  
                new WriteLine  
                {  
                    Text = new InArgument<string>((env) => "Squaring the value: " + this.Value.Get(env))  
                },  
                new Assign<int>  
                {  
                    To = new OutArgument<int>((env) => this.Result.Get(env)),  
                    Value = new InArgument<int>((env) => this.Value.Get(env) * this.Value.Get(env))  
                }  
            }  
        };  
    }  
}  

Az alábbi példában egy egyetlen Square tevékenységből álló munkafolyamat-definíciót hív meg a rendszer WorkflowInvoker.

Dictionary<string, object> inputs = new Dictionary<string, object> {{ "Value", 5}};  
int result = WorkflowInvoker.Invoke(new Square(), inputs);  
Console.WriteLine("Result: {0}", result);  

A munkafolyamat meghívásakor a következő kimenet jelenik meg a konzolon:

Az érték guggolása: 5
Eredmény: 25