Creazione di attività asincrone in WFCreating Asynchronous Activities in WF

AsyncCodeActivity fornisce agli autori dell'attività una classe di base che consente alle attività derivate di implementare la logica di esecuzione asincrona.AsyncCodeActivity provides activity authors a base class to use that enables derived activities to implement asynchronous execution logic. Ciò si rivela utile per attività personalizzate che devono eseguire un lavoro asincrono senza contenere il thread dell'utilità di pianificazione del flusso di lavoro e senza bloccare nessuna attività che può essere eseguita in parallelo.This is useful for custom activities that must perform asynchronous work without holding the workflow scheduler thread and blocking any activities that may be able to run in parallel. In questo argomento viene fornita una panoramica su come creare attività asincrone personalizzate usando l'oggetto AsyncCodeActivity.This topic provides an overview of how to create custom asynchronous activities using AsyncCodeActivity.

Uso di AsyncCodeActivityUsing AsyncCodeActivity

L'oggetto System.Activities fornisce agli autori dell'attività personalizzata classi di base diverse per requisiti di creazione di attività differenti.System.Activities provides custom activity authors with different base classes for different activity authoring requirements. Ognuna presenta una particolare semantica e offre a un autore del flusso di lavoro (e al runtime attività) un contratto corrispondente.Each one carries a particular semantic and provides a workflow author (and the activity runtime) a corresponding contract. Un'attività basata sull'oggetto AsyncCodeActivity è un'attività che esegue un lavoro in modo asincrono relativo al thread dell'utilità di pianificazione e la cui logica di esecuzione viene espressa in codice gestito.An AsyncCodeActivity based activity is an activity that performs work asynchronously relative to the scheduler thread and whose execution logic is expressed in managed code. Come conseguenza di tale modalità asincrona, un oggetto AsyncCodeActivity può determinare un punto di inattività durante l'esecuzione.As a result of going asynchronous, an AsyncCodeActivity may induce an idle point during execution. A causa della natura volatile del lavoro asincrono, un oggetto AsyncCodeActivity crea sempre un blocco di non persistenza per la durata dell'esecuzione dell'attività.Due to the volatile nature of asynchronous work, an AsyncCodeActivity always creates a no persist block for the duration of the activity’s execution. In questo modo si evita che l'esecuzione del flusso di lavoro renda persistente l'istanza del flusso di lavoro durante il lavoro asincrono e si evita anche lo scaricamento dell'istanza del flusso di lavoro mentre il codice asincrono è in esecuzione.This prevents the workflow runtime from persisting the workflow instance in the middle of the asynchronous work, and also prevents the workflow instance from unloading while the asynchronous code is executing.

Metodi AsyncCodeActivityAsyncCodeActivity Methods

Le attività che derivano dall'oggetto AsyncCodeActivity possono creare la logica di esecuzione asincrona eseguendo l'override dei metodi BeginExecute e EndExecute con codice personalizzato.Activities that derive from AsyncCodeActivity can create asynchronous execution logic by overriding the BeginExecute and EndExecute methods with custom code. Quando chiamati dal runtime, a questi metodi viene passato un oggetto AsyncCodeActivityContext.When called by the runtime, these methods are passed an AsyncCodeActivityContext. AsyncCodeActivityContext consente all'autore di attività fornire lo stato condiviso attraverso BeginExecute / EndExecute nel contesto UserState proprietà.AsyncCodeActivityContext allows the activity author to provide shared state across BeginExecute/ EndExecute in the context’s UserState property. Nell'esempio seguente un'attività GenerateRandom genera in modo asincrono un numero casuale.In the following example, a GenerateRandom activity generates a random number asynchronously.

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

L'attività dell'esempio precedente deriva da AsyncCodeActivity<TResult> e dispone di un oggetto OutArgument<int> elevato denominato Result.The previous example activity derives from AsyncCodeActivity<TResult>, and has an elevated OutArgument<int> named Result. Il valore restituito dal metodo GetRandom viene estratto e restituito dall'override del metodo EndExecute e tale valore viene impostato come valore Result.The value returned by the GetRandom method is extracted and returned by the EndExecute override, and this value is set as the Result value. Le attività asincrone che non restituiscono un risultato devono derivare da AsyncCodeActivity.Asynchronous activities that do not return a result should derive from AsyncCodeActivity. Nell'esempio seguente viene definita un'attività DisplayRandom che deriva da AsyncCodeActivity.In the following example, a DisplayRandom activity is defined which derives from AsyncCodeActivity. Questa attività è come l'attività GetRandom ma anziché restituire un risultato visualizza un messaggio nella console.This activity is like the GetRandom activity but instead of returning a result it displays a message to the console.

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

Notare che a causa dell'assenza di un valore restituito, DisplayRandom usa Action anziché Func<T,TResult> per richiamare il delegato e il delegato non restituisce alcun valore.Note that because there is no return value, DisplayRandom uses an Action instead of a Func<T,TResult> to invoke its delegate, and the delegate returns no value.

Anche AsyncCodeActivity fornisce un override di Cancel.AsyncCodeActivity also provides a Cancel override. Mentre BeginExecute e EndExecute sono override obbligatori, Cancel è facoltativo e può essere sottoposto a override in modo che l'attività possa pulire il relativo stato asincrono in attesa quando è in fase di annullamento o di interruzione.While BeginExecute and EndExecute are required overrides, Cancel is optional, and can be overridden so the activity can clean up its outstanding asynchronous state when it is being canceled or aborted. Se la pulizia è possibile e l'oggetto AsyncCodeActivity.ExecutingActivityInstance.IsCancellationRequested è true, l'attività deve chiamare il metodo MarkCanceled.If clean up is possible and AsyncCodeActivity.ExecutingActivityInstance.IsCancellationRequested is true, the activity should call MarkCanceled. Qualsiasi eccezione generata da questo metodo è irreversibile per l'istanza del flusso di lavoro.Any exceptions thrown from this method are fatal to the workflow instance.

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

Richiamo di metodi asincroni su una classeInvoking Asynchronous Methods on a Class

Molte delle classi in .NET Framework.NET Framework dispongono di funzionalità asincrona che può essere richiamata in modo asincrono tramite un'attività basata su AsyncCodeActivity.Many of the classes in the .NET Framework.NET Framework provide asynchronous functionality, and this functionality can be asynchronously invoked by using an AsyncCodeActivity based activity. Nell'esempio seguente il utilizzo di AsyncOperationContext in un'attività, viene creata un'attività che crea in modo asincrono un file utilizzando il FileStream classe.In the following example from the Using AsyncOperationContext in an Activity, an activity is created that asynchronously creates a file by using the FileStream class.

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

Condivisione dello stato tra i metodi BeginExecute e EndExecuteSharing State Between the BeginExecute and EndExecute Methods

Nell'esempio precedente, è stato effettuato l'accesso in FileStream all'oggetto BeginExecute creato in EndExecute.In the previous example, the FileStream object that was created in BeginExecute was accessed in the EndExecute. Ciò è possibile poiché la variabile file è stata passata nella proprietà AsyncCodeActivityContext.UserState in BeginExecute.This is possible because the file variable was passed in the AsyncCodeActivityContext.UserState property in BeginExecute. Questo è il metodo corretto per condividere lo stato tra BeginExecute e EndExecute.This is the correct method for sharing state between BeginExecute and EndExecute. È errato usare una variabile membro nella classe derivata (in questo caso FileWriter) per condividere lo stato tra BeginExecute e EndExecute perché più istanze dell'attività possono fare riferimento agli oggetti attività.It is incorrect to use a member variable in the derived class (FileWriter in this case) to share state between BeginExecute and EndExecute because the activity object may be referenced by multiple activity instances. Tentare di usare una variabile membro per condividere lo stato può causare la sovrascrittura o la cancellazione di valori da un oggetto ActivityInstance a un altro oggetto ActivityInstance.Attempting to use a member variable to share state can result in values from one ActivityInstance overwriting or consuming values from another ActivityInstance.

Accesso ai valori degli argomentiAccessing Argument Values

L'ambiente di un oggetto AsyncCodeActivity è costituito dagli argomenti definiti nell'attività.The environment of an AsyncCodeActivity consists of the arguments defined on the activity. Questi argomenti sono accessibili dal BeginExecute / EndExecute esegue l'override utilizzando il AsyncCodeActivityContext parametro.These arguments can be accessed from the BeginExecute/EndExecute overrides using the AsyncCodeActivityContext parameter. L'accesso agli argomenti non può essere eseguito nel delegato, ma i valori dell'argomento o i dati desiderati possono essere passati al delegato usando i relativi parametri.The arguments cannot be accessed in the delegate, but the argument values or any other desired data can be passed in to the delegate using its parameters. Nell'esempio seguente viene definita un'attività che genera un numero casuale e ottiene il limite superiore incluso dal relativo argomento Max.In the following example, a random number-generating activity is defined that obtains the inclusive upper bound from its Max argument. Il valore dell'argomento viene passato al codice asincrono quando viene richiamato il delegato.The value of the argument is passed in to the asynchronous code when the delegate is invoked.

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

Azioni di programmazione o attività figlio usando AsyncCodeActivityScheduling Actions or Child Activities Using AsyncCodeActivity

Le attività personalizzate derivate AsyncCodeActivity forniscono un metodo per eseguire il lavoro in modo asincrono rispetto al thread del flusso di lavoro, ma non consentono di pianificare le attività figlio o le azioni.AsyncCodeActivity derived custom activities provide a method for performing work asynchronously with regard to the workflow thread, but do not provide the ability to schedule child activities or actions. Tuttavia, il comportamento asincrono può essere incorporato nella pianificazione delle attività figlio tramite la composizione.However, asynchronous behavior can be incorporated with scheduling of child activities through composition. Un'attività asincrona può essere creata e quindi composta con un'attività Activity o NativeActivity derivata per fornire il comportamento asincrono e la pianificazione delle attività figlio o delle azioni.An asynchronous activity can be created, and then composed with an Activity or NativeActivity derived activity to provide asynchronous behavior and scheduling of child activities or actions. Ad esempio, è possibile creare un'attività che deriva da Activity e ha come implementazione un oggetto Sequence che contiene l'attività asincrona nonché le altre attività che implementano la logica dell'attività.For example, an activity could be created that derives from Activity, and has as its implementation a Sequence containing the asynchronous activity as well the other activities that implement the logic of the activity. Per altri esempi di composizione di attività usando Activity e NativeActivity, vedere procedura: creare un'attività, opzioni di creazione di attivitàe il composito esempi di attività.For more examples of composing activities using Activity and NativeActivity, see How to: Create an Activity, Activity Authoring Options, and the Composite activity samples.

Vedere ancheSee Also

Action
Func<T,TResult>
Uso di AsyncOperationContext in un'attivitàUsing AsyncOperationContext in an Activity