Compartilhar via


Criando atividades assíncrono em WF

forneceAsyncCodeActivity autores de atividade de uma classe base para usar que permite atividades derivados para implementar a lógica assíncrona de execução. Isso é útil para as atividades personalizados que devem realizar o trabalho assíncrona sem armazenar o segmento de agendador de fluxo de trabalho e bloquear quaisquer atividades que podem ser capaz executar paralelamente. Este tópico fornece uma visão geral sobre como criar atividades assíncronos personalizados usando AsyncCodeActivity.

Usando AsyncCodeActivity

forneceSystem.Activities autores personalizados de atividade com classes base diferentes para diferentes requisitos de criação da atividade. Cada um leva um semântico específico e fornece um autor de fluxo de trabalho (e o runtime da atividade) um contrato correspondente. Uma atividade com base AsyncCodeActivity é uma atividade que executem o trabalho de forma assíncrona relativo ao segmento de agendador e o cujo a lógica de execução é expressa no código gerenciado. Como resultado de ir assíncrona, AsyncCodeActivity pode induzir um ponto ocioso durante a execução. Devido a natureza temporária de trabalho assíncrona, AsyncCodeActivity sempre cria um nenhum persistir o pacote para a duração de execução da atividade. Isso impede o runtime de fluxo de trabalho persistir a instância de fluxo de trabalho no meio de trabalho assíncrono, e também impede que a instância de fluxo de trabalho descarregar quando o código assíncrono executar.

Métodos de AsyncCodeActivity

As atividades que derivam de AsyncCodeActivity podem criar a lógica assíncrona de execução substituindo o BeginExecute e métodos de EndExecute com o código personalizado. Quando chamados em runtime, esses métodos são passados AsyncCodeActivityContext. AsyncCodeActivityContext permite que o autor da atividade forneça o estado compartilhado em BeginExecute/ EndExecute na propriedade UserState do contexto. No exemplo a seguir, uma atividade de GenerateRandom gerencia um número aleatório de forma assíncrona.

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

A atividade do exemplo anterior deriva de AsyncCodeActivity<TResult>, e tem-se OutArgument<int> alto chamado Result. O valor retornado pelo método de GetRandom é extraído e retornado pela sobrescrita do EndExecute , e esse valor é definido como o valor de Result . As atividades assíncronas que não retornam um resultado devem derivar de AsyncCodeActivity. No exemplo a seguir, uma atividade de DisplayRandom é definida que deriva de AsyncCodeActivity. Esta atividade é como a atividade de GetRandom mas em vez de retornar um resultado exibe uma mensagem para o 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));
    }
}

Observe que porque não há nenhum valor de retorno, DisplayRandom usa Action em vez de Func<T,TResult> para chamar seu representante, e o representante não retorna nenhum valor.

AsyncCodeActivity também fornece uma substituição de Cancel . Quando o BeginExecute e EndExecute substituições são necessárias, Cancel é opcional, e pode ser substituído para que a atividade pode limpar seu estado assíncrono excelente quando está sendo cancelada ou aborted. Se limpeza é possível e AsyncCodeActivity.ExecutingActivityInstance.IsCancellationRequested é true, a atividade deve chamar MarkCanceled. Todas as exceções geradas do método são fatais à instância do fluxo de trabalho.

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

Chamando métodos assíncronos em uma classe

Muitas das classes no .NET Framework fornecem funcionalidade assíncrona, e essa funcionalidade pode ser invocada de forma assíncrona usando uma atividade baseada em AsyncCodeActivity. No exemplo a seguir, é criada uma atividade que cria um arquivo de forma assíncrona usando a classe FileStream.

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

Compartilhando o estado entre o BeginExecute e métodos de EndExecute

No exemplo anterior, o objeto de FileStream que foi criado em BeginExecute foi acessado em EndExecute. Isso é possível porque a variável de file foi passado a propriedade de AsyncCodeActivityContext.UserState no BeginExecute. Este é o método correto para compartilhar o estado entre o BeginExecute e o EndExecute. Está incorreto usar um variável de membro na classe derivadaFileWriter (neste caso) para compartilhar o estado entre o BeginExecute e o EndExecute porque o objeto de atividade pode ser referenciado por várias instâncias de atividade. Tentar usar um variável de membro para compartilhar o estado pode resultar em valores de um ActivityInstance que substitui ou que consome valores de outro ActivityInstance.

Acessando valores de argumento

O ambiente de AsyncCodeActivity consiste nos argumentos definidos na atividade. Esses argumentos podem ser acessados a partir das substituições BeginExecute/EndExecute usando o parâmetro AsyncCodeActivityContext. Os argumentos não podem ser acessados no delegado, mas os valores de argumento ou todos os outros dados desejados podem ser passados para o representante que usa seus parâmetros. No exemplo a seguir, uma atividade de geração aleatória é definida que obtenha o limite superior inclusive de seu argumento de Max . O valor do argumento é passado para o código assíncrona quando o representante é chamado.

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

Ações de programação ou atividades filhos usando AsyncCodeActivity

AsyncCodeActivity derivado atividades personalizados fornece um método para fazer o trabalho de forma assíncrona com relação ao segmento de fluxo de trabalho, mas não fornece a capacidade de agendar atividades filho ou ações. No entanto, o comportamento assíncrono pode ser inserido com programação de atividades filho através de composição. Uma atividade assíncrona pode ser criada, e redigir em com Activity ou NativeActivity derivado a atividade para fornecer o comportamento assíncrono e a programação de atividades filho ou de ações. Por exemplo, uma atividade pode ser criada que é derivado de Activity, e tem como sua implementação Sequence que contém a atividade assíncrono também as outras atividades que implementam a lógica de atividade. Para obter mais exemplos de composição de atividades usando Activity e NativeActivity, consulte Como: Criar uma atividade e Opções de criação de atividades.

Confira também