Usando delegados de atividade
Os delegados de atividade permitem que os autores de atividades exponham retornos de chamada com assinaturas específicas, para as quais os usuários da atividade podem fornecer manipuladores baseados em atividades. Dois tipos de delegados de atividade estão disponíveis: ActivityAction<T> é usado para definir delegados de atividade que não têm um valor de retorno e ActivityFunc<TResult> é usado para definir delegados de atividade que têm um valor de retorno.
Os delegados de atividade são úteis em cenários em que uma atividade filho deve ser restringida a ter uma determinada assinatura. Por exemplo, uma While atividade pode conter qualquer tipo de atividade filho sem restrições, mas o corpo de uma ForEach<T> atividade é um ActivityAction<T>, e a atividade filho que é executada em ForEach<T> última instância deve ter um InArgument<T> que é o mesmo tipo dos membros da coleção que enumera ForEach<T> .
Usando o ActivityAction
Várias atividades do .NET Framework 4.6.1 usam ações de atividade, como a Catch atividade e a ForEach<T> atividade. Em cada caso, a ação de atividade representa um local onde o autor do fluxo de trabalho especifica uma atividade para fornecer o comportamento desejado ao compor um fluxo de trabalho usando uma dessas atividades. No exemplo a seguir, uma ForEach<T> atividade é usada para exibir texto na janela do console. O corpo do ForEach<T> é especificado usando um ActivityAction<T> que corresponde ao tipo do ForEach<T> que é string. A WriteLine atividade especificada no Handler tem seu Text argumento vinculado aos valores de cadeia de caracteres na coleção que a ForEach<T> atividade itera.
DelegateInArgument<string> actionArgument = new DelegateInArgument<string>();
Activity wf = new ForEach<string>
{
Body = new ActivityAction<string>
{
Argument = actionArgument,
Handler = new WriteLine
{
Text = new InArgument<string>(actionArgument)
}
}
};
List<string> items = new List<string>();
items.Add("Hello");
items.Add("World.");
Dictionary<string, object> inputs = new Dictionary<string, object>();
inputs.Add("Values", items);
WorkflowInvoker.Invoke(wf, inputs);
O actionArgument é usado para fluir os itens individuais na coleção para o WriteLine. Quando o fluxo de trabalho é invocado, a saída a seguir é exibida no console.
HelloWorld.
Os exemplos neste tópico usam sintaxe de inicialização de objeto. A sintaxe de inicialização de objeto pode ser uma maneira útil de criar definições de fluxo de trabalho no código, pois fornece uma exibição hierárquica das atividades no fluxo de trabalho e mostra a relação entre as atividades. Não há nenhum requisito para usar a sintaxe de inicialização de objeto quando você cria fluxos de trabalho programaticamente. O exemplo a seguir é funcionalmente equivalente ao exemplo anterior.
DelegateInArgument<string> actionArgument = new DelegateInArgument<string>();
WriteLine output = new WriteLine();
output.Text = new InArgument<string>(actionArgument);
ActivityAction<string> body = new ActivityAction<string>();
body.Argument = actionArgument;
body.Handler = output;
ForEach<string> wf = new ForEach<string>();
wf.Body = body;
List<string> items = new List<string>();
items.Add("Hello");
items.Add("World.");
Dictionary<string, object> inputs = new Dictionary<string, object>();
inputs.Add("Values", items);
WorkflowInvoker.Invoke(wf, inputs);
Para obter mais informações sobre inicializadores de objetos, consulte Como inicializar objetos sem chamar um construtor (Guia de programação em C#) e Como declarar um objeto usando um inicializador de objeto (Visual Basic).
No exemplo a seguir, uma TryCatch atividade é usada em um fluxo de trabalho. Um ApplicationException é lançado pelo fluxo de trabalho e é manipulado por uma Catch<TException> atividade. O manipulador para a Catch<TException> ação de atividade da atividade é uma WriteLine atividade, e o detalhe da exceção é fluído para ela usando o ex
DelegateInArgument<T>.
DelegateInArgument<ApplicationException> ex = new DelegateInArgument<ApplicationException>()
{
Name = "ex"
};
Activity wf = new TryCatch
{
Try = new Throw()
{
Exception = new InArgument<Exception>((env) => new ApplicationException("An ApplicationException was thrown."))
},
Catches =
{
new Catch<ApplicationException>
{
Action = new ActivityAction<ApplicationException>
{
Argument = ex,
Handler = new WriteLine()
{
Text = new InArgument<string>((env) => ex.Get(env).Message)
}
}
}
},
Finally = new WriteLine()
{
Text = "Executing in Finally."
}
};
Ao criar uma atividade personalizada que define um ActivityAction<T>, use um InvokeAction<T> para modelar a invocação desse ActivityAction<T>. Neste exemplo, uma atividade personalizada WriteLineWithNotification
é definida. Essa atividade é composta por um Sequence que contém uma WriteLine atividade seguida por um InvokeAction<T> que invoca um ActivityAction<T> que usa um argumento de cadeia de caracteres.
public class WriteLineWithNotification : Activity
{
public InArgument<string> Text { get; set; }
public ActivityAction<string> TextProcessedAction { get; set; }
public WriteLineWithNotification()
{
this.Implementation = () => new Sequence
{
Activities =
{
new WriteLine
{
Text = new InArgument<string>((env) => Text.Get(env))
},
new InvokeAction<string>
{
Action = TextProcessedAction,
Argument = new InArgument<string>((env) => Text.Get(env))
}
}
};
}
}
Quando um fluxo de trabalho é criado usando a WriteLineWithNotification
atividade, o autor do fluxo de trabalho especifica a lógica personalizada desejada no .Handler Neste exemplo, é criado um fluxo de trabalho que usa a WriteLineWithNotification
atividade e uma WriteLine atividade é usada como o Handler.
// Create and invoke the workflow without specifying any activity action
// for TextProcessed.
Activity wf = new WriteLineWithNotification
{
Text = "Hello World."
};
WorkflowInvoker.Invoke(wf);
// Output:
// Hello World.
// Create and Invoke the workflow with specifying an activity action
// for TextProcessed.
DelegateInArgument<string> msg = new DelegateInArgument<string>();
Activity wf2 = new WriteLineWithNotification
{
Text = "Hello World with activity action.",
TextProcessedAction = new ActivityAction<string>
{
Argument = msg,
Handler = new WriteLine
{
Text = new InArgument<string>((env) => "Handler of: " + msg.Get(env))
}
}
};
// Invoke the workflow with an activity action specified
WorkflowInvoker.Invoke(wf2);
// Output:
// Hello World with activity action.
// Handler of: Hello World with activity action.
Existem várias versões genéricas de InvokeAction<T> e ActivityAction<T> fornecidas para passar um ou mais argumentos.
Usando o ActivityFunc
ActivityAction<T> é útil quando não há nenhum valor de resultado da atividade e ActivityFunc<TResult> é usado quando um valor de resultado é retornado. Ao criar uma atividade personalizada que define um ActivityFunc<TResult>, use um InvokeFunc<TResult> para modelar a invocação desse ActivityFunc<TResult>. No exemplo a seguir, uma WriteFillerText
atividade é definida. Para fornecer o texto de preenchimento, é especificado um InvokeFunc<TResult> argumento que usa um argumento inteiro e tem um resultado de cadeia de caracteres. Depois que o texto de preenchimento é recuperado, ele é exibido no console usando uma WriteLine atividade.
public class WriteFillerText : Activity
{
public ActivityFunc<int, string> GetText { get; set; }
public InArgument<int> Quantity { get; set; }
Variable<string> text = new Variable<string>
{
Name = "Text"
};
public WriteFillerText()
{
this.Implementation = () => new Sequence
{
Variables =
{
text
},
Activities =
{
new InvokeFunc<int, string>
{
Func = GetText,
Argument = new InArgument<int>((env) => Quantity.Get(env)),
Result = new OutArgument<string>(text)
},
new WriteLine
{
Text = new InArgument<string>(text)
}
}
};
}
}
Para fornecer o texto, deve ser usada uma atividade que usa um int
argumento e tem um resultado de cadeia de caracteres. Este exemplo mostra uma TextGenerator
atividade que atende a esses requisitos.
public class TextGenerator : CodeActivity<string>
{
public InArgument<int> Quantity { get; set; }
public InArgument<string> Text { get; set; }
protected override string Execute(CodeActivityContext context)
{
// Provide a quantity of Random Text
int q = Quantity.Get(context);
if (q < 1)
{
q = 1;
}
string text = Text.Get(context) + " ";
StringBuilder sb = new StringBuilder(text.Length * q);
for (int i = 0; i < q; i++)
{
sb.Append(text);
}
return sb.ToString();
}
}
Para usar a TextGenerator
atividade com a WriteFillerText
atividade, especifique-a como .Handler
DelegateInArgument<int> actionArgument = new DelegateInArgument<int>();
Activity wf = new WriteFillerText
{
Quantity = 5,
GetText = new ActivityFunc<int, string>
{
Argument = actionArgument,
Handler = new TextGenerator
{
Quantity = new InArgument<int>(actionArgument),
Text = "Hello World."
}
}
};
WorkflowInvoker.Invoke(wf);