Partilhar via


Expressões em C#

A partir do .NET Framework 4.5, as expressões C# são suportadas no Windows Workflow Foundation (WF). Novos projetos de fluxo de trabalho C# criados no Visual Studio 2012 destinados ao .NET Framework 4.5 usam expressões C# e projetos de fluxo de trabalho do Visual Basic usam expressões do Visual Basic. 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 das 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, as expressões C# são suportadas no Windows Workflow Foundation (WF). Os projetos de fluxo de trabalho C# criados no Visual Studio 2012 destinados ao .NET Framework 4.5 usam expressões C#, enquanto os projetos de fluxo de trabalho do Visual Basic usam expressões do Visual Basic. Para especificar a expressão C# desejada, digite-a na caixa 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 WriteLine atividades estão contidas dentro de um Sequence NoPersistScope.

Screenshot that shows an automatically created sequence activity.

Nota

As expressões C# são suportadas apenas no Visual Studio e não são suportadas no designer de fluxo de trabalho rehospedado. Para obter mais informações sobre os novos recursos do WF45 suportados no designer rehospedado, consulte Suporte para novos recursos do Workflow Foundation 4.5 no Designer de fluxo de trabalho rehospedado.

Compatibilidade com versões anteriores

Há suporte para expressões do Visual Basic em projetos de fluxo de trabalho C# do .NET Framework 4 existentes que foram migrados para o .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 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ê pode 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 uma vez que as expressões são atualizadas no designer de fluxo de trabalho, elas são convertidas em C# e não podem ser revertidas para Visual Basic.

Usando expressões C# em fluxos de trabalho de código

As expressões C# são suportadas em fluxos de trabalho baseados em código do .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 do 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 Assign atividade e uma WriteLine atividade contida em uma Sequence atividade. A CSharpReference é especificado para o To argumento do Assign, e representa o valor l da expressão. A CSharpValue é especificado para o Value argumento do Assign, e para o Text argumento 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 é construído, as expressões C# são compiladas chamando o CompileExpressions método auxiliar e, em seguida, o fluxo de trabalho é invocado. O exemplo a seguir é o CompileExpressions método.

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

Nota

Se as expressões C# não forem compiladas, um NotSupportedException será lançado quando o fluxo de trabalho for invocado com uma mensagem semelhante à seguinte: Expression Activity type 'CSharpValue1' requer compilação para ser executado. Certifique-se de que o fluxo de trabalho foi compilado."

Se o fluxo de trabalho baseado em código personalizado usa DynamicActivity, algumas alterações no CompileExpressions método são necessárias, conforme demonstrado no exemplo de código a seguir.

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 CompileExpressions sobrecarga que compila as expressões C# em uma atividade dinâmica.

  • O parâmetro a CompileExpressions é um DynamicActivityarquivo .

  • O nome do tipo e o namespace são recuperados usando a DynamicActivity.Name propriedade.

  • TextExpressionCompilerSettings.ForImplementation está definido como true.

  • CompiledExpressionInvoker.SetCompiledExpressionRootForImplementation é chamado em vez de CompiledExpressionInvoker.SetCompiledExpressionRoot.

Para obter mais informações sobre como trabalhar com expressões no código, consulte Criação de fluxos de trabalho, atividades e expressões usando código imperativo.

Usando expressões C# em fluxos de trabalho XAML

Há suporte para expressões C# em fluxos de trabalho XAML. Os fluxos de trabalho XAML compilados são compilados em um tipo, e os fluxos de trabalho XAML soltos são carregados pelo tempo de execução e compilados em uma árvore de atividades quando o fluxo de trabalho é executado.

Xaml compilado

Há suporte para expressões C# em fluxos de trabalho XAML compilados que são compilados para um tipo como parte de um projeto de fluxo de trabalho C# destinado ao .NET Framework 4.6.1. XAML compilado é o tipo padrão de criação de fluxo de trabalho no Visual Studio, e os projetos de fluxo de trabalho C# criados no Visual Studio destinados ao .NET Framework 4.6.1 usam expressões C#.

Xaml solto

Há suporte para expressões C# em fluxos de trabalho XAML soltos. O programa host de fluxo de trabalho que carrega e invoca o fluxo de trabalho XAML solto 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 , crie uma ActivityXamlServicesSettings instância com sua CompileExpressions propriedade definida como true, e passe-a como um parâmetro para ActivityXamlServices.Loadtrue. Se CompileExpressions Não estiver definido como true, um NotSupportedException será lançado com uma mensagem semelhante à seguinte: Expression Activity type 'CSharpValue1' requer compilação para ser executado. Certifique-se de que 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, consulte Serializando fluxos de trabalho e atividades de e para XAML.

Usando expressões C# em serviços de fluxo de trabalho XAMLX

As expressões C# são suportadas nos serviços de fluxo de trabalho XAMLX. Quando um serviço de fluxo de trabalho é hospedado no IIS ou no WAS, nenhuma etapa adicional é necessária, mas se o serviço de fluxo de trabalho XAML for auto-hospedado, as expressões C# deverão ser compiladas. Para compilar as expressões C# em um serviço de fluxo de trabalho XAMLX auto-hospedado, primeiro carregue o arquivo XAMLX em um WorkflowServicee, em seguida, passe o Body do WorkflowService para o CompileExpressions método 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 compiladas e, em seguida, o serviço de 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 Open operação será bem-sucedida, mas o fluxo de trabalho falhará quando for invocado. O método a seguir CompileExpressions é 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);
}