Expressões C#
A partir do .NET Framework 4.5, há suporte para expressões C# no WF (Windows Workflow Foundation). Novos projetos de fluxo de trabalho C# criados no Visual Studio 2012 direcionados ao .NET Framework 4.5 usam expressões C#, e projetos de fluxo de trabalho do Visual Basic usam expressões do Visual Basic. Os projetos de fluxo de trabalho existentes do .NET Framework 4 que usam expressões do Visual Basic podem ser migrados para o .NET Framework 4.6.1 independentemente da linguagem do projeto e são suportados. Este tópico fornece uma visão geral de expressões C# no WF.
Usando expressões C# em fluxos de trabalho
Usando expressões C# no Designer de Fluxo de Trabalho
A partir do .NET Framework 4.5, há suporte para expressões C# no WF (Windows Workflow Foundation). Os projetos de fluxo de trabalho C# criados no Visual Studio 2012 direcionados ao .NET Framework 4.5 usam expressões C#, enquanto os projetos de fluxo de trabalho Visual Basic usam expressões Visual Basic. Para especificar a expressão desejada C#, digite-a na caixa rotulada Inserir uma expressão C#. Esse rótulo é exibido na janela de propriedades quando a atividade é selecionada no designer ou na atividade no designer de fluxo de trabalho. No exemplo a seguir, duas atividades WriteLine
estão contidas no Sequence
dentro de NoPersistScope
.
Observação
As expressões C# têm suporte apenas no Visual Studio e não têm suporte no designer de fluxo de trabalho hospedado novamente. Para obter mais informações sobre os novos recursos do WF45 com suporte no designer re-hospedado, confira Suporte para novos recursos do Workflow Foundation 4.5 no Designer de Fluxo de Trabalho re-hospedado.
Compatibilidade com versões anteriores
Há suporte para expressões do Visual Basic em projetos de fluxo de trabalho .NET Framework 4 C# existentes que foram migrados para .NET Framework 4.6.1. Quando as expressões do Visual Basic são exibidas no designer de fluxo de trabalho, o texto da expressão existente do Visual Basic é substituído por O valor foi definido em XAML, a menos que a expressão do Visual Basic seja uma sintaxe C# válida. Se a expressão do Visual Basic for uma sintaxe C# válida, a expressão será exibida. Para atualizar as expressões do Visual Basic para C#, você poderá editá-las no designer de fluxo de trabalho e especificar a expressão C# equivalente. Não é necessário atualizar as expressões do Visual Basic para C#, mas, assim que as expressões forem atualizadas no designer de fluxo de trabalho, serão convertidas em C# e não poderão ser revertidas para o Visual Basic.
Usando expressões C# em fluxos de trabalho de código
Expressões C# têm suporte em fluxos de trabalho baseados em código .NET Framework 4.6.1, mas antes que o fluxo de trabalho possa ser invocado, as expressões C# devem ser compiladas usando TextExpressionCompiler.Compile. Os autores de fluxo de trabalho podem usar CSharpValue
para representar o valor r de uma expressão e CSharpReference
para representar o valor l de uma expressão. No exemplo a seguir, um fluxo de trabalho é criado com uma atividade Assign
e uma atividade WriteLine
contidas em uma atividade Sequence
. Um CSharpReference
é especificado para o argumento To
do Assign
, e representa o valor l da expressão. Um CSharpValue
é especificado para o argumento Value
do Assign
e para o argumento Text
do WriteLine
e representa o valor r para essas duas expressões.
Variable<int> n = new Variable<int>
{
Name = "n"
};
Activity wf = new Sequence
{
Variables = { n },
Activities =
{
new Assign<int>
{
To = new CSharpReference<int>("n"),
Value = new CSharpValue<int>("new Random().Next(1, 101)")
},
new WriteLine
{
Text = new CSharpValue<string>("\"The number is \" + n")
}
}
};
CompileExpressions(wf);
WorkflowInvoker.Invoke(wf);
Depois que o fluxo de trabalho for criado, as expressões C# serão compiladas chamando o método auxiliar do CompileExpressions
e, em seguida, o fluxo de trabalho será chamado. O exemplo a seguir é o método CompileExpressions
.
static void CompileExpressions(Activity activity)
{
// activityName is the Namespace.Type of the activity that contains the
// C# expressions.
string activityName = activity.GetType().ToString();
// Split activityName into Namespace and Type.Append _CompiledExpressionRoot to the type name
// to represent the new type that represents the compiled expressions.
// Take everything after the last . for the type name.
string activityType = activityName.Split('.').Last() + "_CompiledExpressionRoot";
// Take everything before the last . for the namespace.
string activityNamespace = string.Join(".", activityName.Split('.').Reverse().Skip(1).Reverse());
// Create a TextExpressionCompilerSettings.
TextExpressionCompilerSettings settings = new TextExpressionCompilerSettings
{
Activity = activity,
Language = "C#",
ActivityName = activityType,
ActivityNamespace = activityNamespace,
RootNamespace = null,
GenerateAsPartialClass = false,
AlwaysGenerateSource = true,
ForImplementation = false
};
// Compile the C# expression.
TextExpressionCompilerResults results =
new TextExpressionCompiler(settings).Compile();
// Any compilation errors are contained in the CompilerMessages.
if (results.HasErrors)
{
throw new Exception("Compilation failed.");
}
// Create an instance of the new compiled expression type.
ICompiledExpressionRoot compiledExpressionRoot =
Activator.CreateInstance(results.ResultType,
new object[] { activity }) as ICompiledExpressionRoot;
// Attach it to the activity.
CompiledExpressionInvoker.SetCompiledExpressionRoot(
activity, compiledExpressionRoot);
}
Observação
Se as expressões C# não forem compiladas, um NotSupportedException será gerado quando o fluxo de trabalho for invocado com uma mensagem semelhante à seguinte: Expression Activity type 'CSharpValue
1' requer compilação para ser executado. Verifique se o fluxo de trabalho foi compilado.'
Se seu fluxo de trabalho baseado em código personalizado usar DynamicActivity
, algumas alterações ao método CompileExpressions
serão necessárias, como mostrado no seguinte exemplo de código.
static void CompileExpressions(DynamicActivity dynamicActivity)
{
// activityName is the Namespace.Type of the activity that contains the
// C# expressions. For Dynamic Activities this can be retrieved using the
// name property , which must be in the form Namespace.Type.
string activityName = dynamicActivity.Name;
// Split activityName into Namespace and Type.Append _CompiledExpressionRoot to the type name
// to represent the new type that represents the compiled expressions.
// Take everything after the last . for the type name.
string activityType = activityName.Split('.').Last() + "_CompiledExpressionRoot";
// Take everything before the last . for the namespace.
string activityNamespace = string.Join(".", activityName.Split('.').Reverse().Skip(1).Reverse());
// Create a TextExpressionCompilerSettings.
TextExpressionCompilerSettings settings = new TextExpressionCompilerSettings
{
Activity = dynamicActivity,
Language = "C#",
ActivityName = activityType,
ActivityNamespace = activityNamespace,
RootNamespace = null,
GenerateAsPartialClass = false,
AlwaysGenerateSource = true,
ForImplementation = true
};
// Compile the C# expression.
TextExpressionCompilerResults results =
new TextExpressionCompiler(settings).Compile();
// Any compilation errors are contained in the CompilerMessages.
if (results.HasErrors)
{
throw new Exception("Compilation failed.");
}
// Create an instance of the new compiled expression type.
ICompiledExpressionRoot compiledExpressionRoot =
Activator.CreateInstance(results.ResultType,
new object[] { dynamicActivity }) as ICompiledExpressionRoot;
// Attach it to the activity.
CompiledExpressionInvoker.SetCompiledExpressionRootForImplementation(
dynamicActivity, compiledExpressionRoot);
}
Há várias diferenças na sobrecarga do CompileExpressions
que cria as expressões C# em uma atividade dinâmica.
O parâmetro para
CompileExpressions
é umDynamicActivity
.O nome e o namespace do tipo são recuperados usando a propriedade
DynamicActivity.Name
.TextExpressionCompilerSettings.ForImplementation
é definido comotrue
.CompiledExpressionInvoker.SetCompiledExpressionRootForImplementation
é chamado em vez deCompiledExpressionInvoker.SetCompiledExpressionRoot
.
Para obter mais informações sobre como trabalhar com expressões no código, confira Criação de fluxos de trabalho, atividades e expressões usando código imperativo.
Usando expressões C# em fluxos de trabalho XAML
As expressões C# têm suporte em fluxos de trabalho XAML. Os fluxos de trabalho XAML compilados são criados em um tipo e os fluxos de trabalho XAML flexíveis são carregados pelo runtime e compilados em uma árvore de atividade quando o fluxo de trabalho é executado.
Xaml compilado
As expressões C# têm suporte nos fluxos de trabalho XAML compilados criados em um tipo como parte de um projeto de fluxo de trabalho de C# destinado para .NET Framework 4.6.1. O XAML compilado é o tipo padrão de criação de fluxo de trabalho no Visual Studio e projetos de fluxo de trabalho em C# criados no Visual Studio destinados ao .NET Framework 4.6.1 usam expressões C#.
Xaml flexível
As expressões C# têm suporte em fluxos de trabalho XAML flexíveis. O programa do host de fluxo de trabalho que carrega e chama o fluxo de trabalho XAML flexível deve ter como destino o .NET Framework 4.6.1 e CompileExpressions deve ser definido como true
(o padrão é false
). Para definir CompileExpressions como true
, crie uma instância ActivityXamlServicesSettings com o conjunto de propriedades CompileExpressions definido como true
e passá-lo como um parâmetro para ActivityXamlServices.Load. Se CompileExpressions
não está definido como true
, uma NotSupportedException será gerada com uma mensagem semelhante à seguinte: Expression Activity type 'CSharpValue
1' requer compilação para execução. Verifique se o fluxo de trabalho foi compilado.'
ActivityXamlServicesSettings settings = new ActivityXamlServicesSettings
{
CompileExpressions = true
};
DynamicActivity<int> wf = ActivityXamlServices.Load(new StringReader(serializedAB), settings) as DynamicActivity<int>;
Para obter mais informações sobre como trabalhar com fluxos de trabalho XAML, confira Serializando fluxos de trabalho e atividades de e para XAML.
Usando expressões C# em serviços de fluxo de trabalho do XAMLX
Expressões C# têm suporte em serviços de fluxo de trabalho do XAMLX. Quando um serviço de fluxo de trabalho é hospedado no IIS ou WAS, nenhuma etapa adicional é necessária. Porém, se o serviço de fluxo de trabalho XAML for auto-hospedado, as expressões C# deverão ser compiladas. Para criar expressões C# em um serviço fluxo de trabalho XAMLX auto-hospedado, primeiro carregue o arquivo XAMLX em um WorkflowService
e passe o Body
do WorkflowService
para o método CompileExpressions
descrito na seção anterior Usando expressões C# em fluxos de trabalho de código. No exemplo a seguir, um serviço de fluxo de trabalho XAMLX é carregado, as expressões C# são criadas e o serviço do fluxo de trabalho é aberto e aguarda solicitações.
// Load the XAMLX workflow service.
WorkflowService workflow1 =
(WorkflowService)XamlServices.Load(xamlxPath);
// Compile the C# expressions in the workflow by passing the Body to CompileExpressions.
CompileExpressions(workflow1.Body);
// Initialize the WorkflowServiceHost.
var host = new WorkflowServiceHost(workflow1, new Uri("http://localhost:8293/Service1.xamlx"));
// Enable Metadata publishing/
ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;
host.Description.Behaviors.Add(smb);
// Open the WorkflowServiceHost and wait for requests.
host.Open();
Console.WriteLine("Press enter to quit");
Console.ReadLine();
Se as expressões C# não forem compiladas, a operação Open
terá êxito, mas o fluxo de trabalho falhará quando for chamado. O método CompileExpressions
a seguir é o mesmo que o método da seção anterior Usando expressões C# em fluxos de trabalho de código.
static void CompileExpressions(Activity activity)
{
// activityName is the Namespace.Type of the activity that contains the
// C# expressions.
string activityName = activity.GetType().ToString();
// Split activityName into Namespace and Type.Append _CompiledExpressionRoot to the type name
// to represent the new type that represents the compiled expressions.
// Take everything after the last . for the type name.
string activityType = activityName.Split('.').Last() + "_CompiledExpressionRoot";
// Take everything before the last . for the namespace.
string activityNamespace = string.Join(".", activityName.Split('.').Reverse().Skip(1).Reverse());
// Create a TextExpressionCompilerSettings.
TextExpressionCompilerSettings settings = new TextExpressionCompilerSettings
{
Activity = activity,
Language = "C#",
ActivityName = activityType,
ActivityNamespace = activityNamespace,
RootNamespace = null,
GenerateAsPartialClass = false,
AlwaysGenerateSource = true,
ForImplementation = false
};
// Compile the C# expression.
TextExpressionCompilerResults results =
new TextExpressionCompiler(settings).Compile();
// Any compilation errors are contained in the CompilerMessages.
if (results.HasErrors)
{
throw new Exception("Compilation failed.");
}
// Create an instance of the new compiled expression type.
ICompiledExpressionRoot compiledExpressionRoot =
Activator.CreateInstance(results.ResultType,
new object[] { activity }) as ICompiledExpressionRoot;
// Attach it to the activity.
CompiledExpressionInvoker.SetCompiledExpressionRoot(
activity, compiledExpressionRoot);
}