Dela via


Skapa asynkrona aktiviteter i WF

AsyncCodeActivity ger aktivitetsförfattare en basklass att använda som gör det möjligt för härledda aktiviteter att implementera asynkron körningslogik. Detta är användbart för anpassade aktiviteter som måste utföra asynkront arbete utan att hålla i tråden för arbetsflödesschemaläggaren och blockera aktiviteter som kan köras parallellt. Det här avsnittet innehåller en översikt över hur du skapar anpassade asynkrona aktiviteter med hjälp av AsyncCodeActivity.

Använda AsyncCodeActivity

System.Activities tillhandahåller anpassade aktivitetsförfattare med olika basklasser för olika aktivitetsredigeringskrav. Var och en har en viss semantik och ger en arbetsflödesförfattare (och aktivitetskörningen) ett motsvarande kontrakt. En AsyncCodeActivity baserad aktivitet är en aktivitet som utför arbete asynkront i förhållande till scheduler-tråden och vars körningslogik uttrycks i hanterad kod. Som ett resultat av att bli asynkron kan en AsyncCodeActivity utlösa en inaktiv punkt under körningen. På grund av det asynkrona arbetets flyktiga karaktär skapar en AsyncCodeActivity alltid ett inget kvarstående block under hela aktivitetens körning. Detta förhindrar att arbetsflödeskörningen bevarar arbetsflödesinstansen mitt i det asynkrona arbetet och förhindrar även att arbetsflödesinstansen tas bort medan den asynkrona koden körs.

AsyncCodeActivity-metoder

Aktiviteter som härleds från AsyncCodeActivity kan skapa asynkron körningslogik genom att BeginExecute åsidosätta metoderna och EndExecute med anpassad kod. När de anropas av körningen skickas dessa metoder en AsyncCodeActivityContext. AsyncCodeActivityContext tillåter aktivitetsförfattaren att ange delat tillstånd BeginExecute/ EndExecute i kontextens UserState egenskap. I följande exempel genererar en GenerateRandom aktivitet ett slumpmässigt tal asynkront.

public sealed class GenerateRandom : AsyncCodeActivity<int>
{
    static Random r = new Random();

    protected override IAsyncResult BeginExecute(AsyncCodeActivityContext context, AsyncCallback callback, object state)
    {
        // Create a delegate that references the method that implements
        // the asynchronous work. Assign the delegate to the UserState,
        // invoke the delegate, and return the resulting IAsyncResult.
        Func<int> GetRandomDelegate = new Func<int>(GetRandom);
        context.UserState = GetRandomDelegate;
        return GetRandomDelegate.BeginInvoke(callback, state);
    }

    protected override int EndExecute(AsyncCodeActivityContext context, IAsyncResult result)
    {
        // Get the delegate from the UserState and call EndInvoke
        Func<int> GetRandomDelegate = (Func<int>)context.UserState;
        return (int)GetRandomDelegate.EndInvoke(result);
    }

    int GetRandom()
    {
        // This activity simulates taking a few moments
        // to generate the random number. This code runs
        // asynchronously with respect to the workflow thread.
        Thread.Sleep(5000);

        return r.Next(1, 101);
    }
}

Föregående exempelaktivitet härleds från AsyncCodeActivity<TResult>och har en upphöjd OutArgument<int> med namnet Result. Värdet som returneras av GetRandom metoden extraheras och returneras av åsidosättningen EndExecute , och det här värdet anges som Result värde. Asynkrona aktiviteter som inte returnerar ett resultat bör härledas från AsyncCodeActivity. I följande exempel definieras en DisplayRandom aktivitet som härleds från AsyncCodeActivity. Den här aktiviteten liknar GetRandom aktiviteten, men i stället för att returnera ett resultat visas ett meddelande till konsolen.

public sealed class DisplayRandom : AsyncCodeActivity
{
    static Random r = new Random();

    protected override IAsyncResult BeginExecute(AsyncCodeActivityContext context, AsyncCallback callback, object state)
    {
        // Create a delegate that references the method that implements
        // the asynchronous work. Assign the delegate to the UserState,
        // invoke the delegate, and return the resulting IAsyncResult.
        Action GetRandomDelegate = new Action(GetRandom);
        context.UserState = GetRandomDelegate;
        return GetRandomDelegate.BeginInvoke(callback, state);
    }

    protected override void EndExecute(AsyncCodeActivityContext context, IAsyncResult result)
    {
        // Get the delegate from the UserState and call EndInvoke
        Action GetRandomDelegate = (Action)context.UserState;
        GetRandomDelegate.EndInvoke(result);
    }

    void GetRandom()
    {
        // This activity simulates taking a few moments
        // to generate the random number. This code runs
        // asynchronously with respect to the workflow thread.
        Thread.Sleep(5000);

        Console.WriteLine("Random Number: {0}", r.Next(1, 101));
    }
}

Observera att eftersom det inte finns något returvärde DisplayRandom använder en Action i stället för en Func<T,TResult> för att anropa dess ombud och ombudet returnerar inget värde.

AsyncCodeActivity ger också en Cancel åsidosättning. Även om BeginExecute och EndExecute är obligatoriska åsidosättningar, Cancel är valfritt och kan åsidosättas så att aktiviteten kan rensa upp sitt enastående asynkrona tillstånd när den avbryts eller avbryts. Om rensning är möjligt och AsyncCodeActivity.ExecutingActivityInstance.IsCancellationRequested är trueska aktiviteten anropa MarkCanceled. Alla undantag som genereras från den här metoden är allvarliga för arbetsflödesinstansen.

protected override void Cancel(AsyncCodeActivityContext context)
{
    // Implement any cleanup as a result of the asynchronous work
    // being canceled, and then call MarkCanceled.
    if (context.IsCancellationRequested)
    {
        context.MarkCanceled();
    }
}

Anropa asynkrona metoder på en klass

Många av klasserna i .NET Framework tillhandahåller asynkrona funktioner och den här funktionen kan anropas asynkront med hjälp av en AsyncCodeActivity baserad aktivitet. I följande exempel skapas en aktivitet som asynkront skapar en fil med hjälp FileStream av klassen.

public sealed class FileWriter : AsyncCodeActivity
{
    public FileWriter()
        : base()
    {
    }

    protected override IAsyncResult BeginExecute(AsyncCodeActivityContext context, AsyncCallback callback, object state)
    {
        string tempFileName = Path.GetTempFileName();
        Console.WriteLine("Writing to file: " + tempFileName);

        FileStream file = File.Open(tempFileName, FileMode.Create);

        context.UserState = file;

        byte[] bytes = UnicodeEncoding.Unicode.GetBytes("123456789");
        return file.BeginWrite(bytes, 0, bytes.Length, callback, state);
    }

    protected override void EndExecute(AsyncCodeActivityContext context, IAsyncResult result)
    {
        FileStream file = (FileStream)context.UserState;

        try
        {
            file.EndWrite(result);
            file.Flush();
        }
        finally
        {
            file.Close();
        }
    }
}

Delningstillstånd mellan Metoderna BeginExecute och EndExecute

I föregående exempel användes objektet FileStream som skapades i BeginExecute i EndExecute. Detta är möjligt eftersom variabeln file skickades i AsyncCodeActivityContext.UserState egenskapen i BeginExecute. Det här är rätt metod för att dela tillstånd mellan BeginExecute och EndExecute. Det är felaktigt att använda en medlemsvariabel i den härledda klassen (FileWriter i det här fallet) för att dela tillstånd mellan BeginExecute och EndExecute eftersom aktivitetsobjektet kan refereras av flera aktivitetsinstanser. Om du försöker använda en medlemsvariabel för att dela tillstånd kan det resultera i värden från en ActivityInstance överskrivning eller användning av värden från en annan ActivityInstance.

Åtkomst till argumentvärden

Miljön för en AsyncCodeActivity består av argumenten som definierats för aktiviteten. Dessa argument kan nås från BeginExecute/EndExecute åsidosättningarna med hjälp av parametern .AsyncCodeActivityContext Det går inte att komma åt argumenten i ombudet, men argumentvärdena eller andra önskade data kan skickas till ombudet med hjälp av dess parametrar. I följande exempel definieras en slumpmässig talgenereringsaktivitet som hämtar den inkluderande övre gränsen från argumentet Max . Värdet för argumentet skickas till den asynkrona koden när ombudet anropas.

public sealed class GenerateRandomMax : AsyncCodeActivity<int>
{
    public InArgument<int> Max { get; set; }

    static Random r = new Random();

    protected override IAsyncResult BeginExecute(AsyncCodeActivityContext context, AsyncCallback callback, object state)
    {
        // Create a delegate that references the method that implements
        // the asynchronous work. Assign the delegate to the UserState,
        // invoke the delegate, and return the resulting IAsyncResult.
        Func<int, int> GetRandomDelegate = new Func<int, int>(GetRandom);
        context.UserState = GetRandomDelegate;
        return GetRandomDelegate.BeginInvoke(Max.Get(context), callback, state);
    }

    protected override int EndExecute(AsyncCodeActivityContext context, IAsyncResult result)
    {
        // Get the delegate from the UserState and call EndInvoke
        Func<int, int> GetRandomDelegate = (Func<int, int>)context.UserState;
        return (int)GetRandomDelegate.EndInvoke(result);
    }

    int GetRandom(int max)
    {
        // This activity simulates taking a few moments
        // to generate the random number. This code runs
        // asynchronously with respect to the workflow thread.
        Thread.Sleep(5000);

        return r.Next(1, max + 1);
    }
}

Schemaläggningsåtgärder eller underordnade aktiviteter med AsyncCodeActivity

AsyncCodeActivity härledda anpassade aktiviteter ger en metod för att utföra arbete asynkront med avseende på arbetsflödestråden, men ger inte möjlighet att schemalägga underordnade aktiviteter eller åtgärder. Asynkront beteende kan dock införlivas med schemaläggning av underordnade aktiviteter via sammansättning. En asynkron aktivitet kan skapas och sedan bestå av en Activity eller NativeActivity härledd aktivitet för att tillhandahålla asynkront beteende och schemaläggning av underordnade aktiviteter eller åtgärder. En aktivitet kan till exempel skapas som härleds från Activityoch har som implementering en Sequence som innehåller den asynkrona aktiviteten samt de andra aktiviteter som implementerar aktivitetens logik. Fler exempel på hur du skapar aktiviteter med hjälp av Activity och finns i Så här skapar du alternativ för aktivitets- och NativeActivityaktivitetsredigering.

Se även