Поделиться через


Выражения C#

Начиная с платформа .NET Framework 4.5 выражения C# поддерживаются в Windows Workflow Foundation (WF). Новые проекты рабочих процессов C#, созданные в Visual Studio 2012, предназначенные для платформа .NET Framework 4.5, используют выражения C# и проекты рабочих процессов Visual Basic используют выражения Visual Basic. Существующие проекты рабочих процессов платформа .NET Framework 4, использующие выражения Visual Basic, можно перенести на платформа .NET Framework 4.6.1 независимо от языка проекта и поддерживаются. В этом разделе представлен обзор выражений C# в WF.

Выражения на языке C# в рабочих процессах

Использование выражений C# в конструкторе рабочих процессов

Начиная с платформа .NET Framework 4.5 выражения C# поддерживаются в Windows Workflow Foundation (WF). Проекты рабочих процессов C#, созданные в Visual Studio 2012, предназначенные для платформа .NET Framework 4.5, используют выражения C#, а проекты рабочих процессов Visual Basic используют выражения Visual Basic. Чтобы указать требуемое выражение C#, введите его в поле с меткой ВВОД выражения C#. Эта метка отображается в окне свойств при выборе действия в конструкторе или при работе в конструкторе рабочих процессов. В следующем примере два действия WriteLine содержатся в Sequence внутри NoPersistScope.

Screenshot that shows an automatically created sequence activity.

Примечание.

Выражения C# поддерживаются только в Visual Studio и не поддерживаются в повторно размещенном конструкторе рабочих процессов. Дополнительные сведения о новых функциях WF45, поддерживаемых в повторно размещенном конструкторе, см. в разделе "Поддержка новых функций Workflow Foundation 4.5" в конструкторе повторно размещенных рабочих процессов.

обратная совместимость;

Поддерживаются выражения Visual Basic в существующих проектах рабочих процессов платформа .NET Framework 4 C#, перенесенных в платформа .NET Framework 4.6.1. При просмотре выражений Visual Basic в конструкторе рабочих процессов текст существующего выражения Visual Basic заменяется значением в XAML, если только выражение Visual Basic не является допустимым синтаксисом C#. Если выражение Visual Basic имеет допустимый синтаксис C#, то отображается выражение. Чтобы обновить выражение Visual Basic до C#, следует отредактировать его в конструкторе рабочих процессов и указать эквивалентное выражение C#. Преобразование выражений Visual Basic в C# не является обязательным, но после обновления выражений в конструкторе рабочих процессов они преобразуется в C# и не могут быть восстановлены в виде выражений Visual Basic.

Использование выражений C# в рабочих процессах кода

Выражения C# поддерживаются в рабочих процессах на основе кода платформа .NET Framework 4.6.1, но перед вызовом рабочего процесса выражения C# необходимо скомпилировать с помощью TextExpressionCompiler.Compile. Авторы рабочих процессов могут использовать CSharpValue для представления r-значений выражения и CSharpReference для представления l-значений выражения. В следующем примере рабочий процесс создается с помощью действия Assign и действия WriteLine, содержащихся в Sequence. CSharpReference указывается для аргумента To действия Assign и представляет l-значение выражения. CSharpValue указывается для аргумента Value действия Assign и для аргумента Text действия WriteLine и представляет r-значение для двух этих выражений.

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

После создания рабочего процесса выражения на языке C# компилируются с помощью вызова вспомогательного метода CompileExpressions, а затем уже вызывается рабочий процесс. В следующем примере приведен метод 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);
}

Примечание.

Если выражения C# не компилируются, NotSupportedException создается при вызове рабочего процесса с сообщением, аналогичным следующему: Expression Activity type 'CSharpValue1' требует компиляции для выполнения. Убедитесь, что рабочий процесс скомпилирован.

Если рабочий процесс на основе пользовательского кода использует DynamicActivity, то требуется внести некоторые изменения в методе CompileExpressions, как показано в следующем примере кода.

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

Существует несколько различий в перегрузке CompileExpressions, которая компилирует выражения C# в динамическом действии.

  • Параметр в CompileExpressions - это DynamicActivity.

  • Имя типа и пространство имен получаются с помощью свойства DynamicActivity.Name.

  • TextExpressionCompilerSettings.ForImplementation задан как true.

  • CompiledExpressionInvoker.SetCompiledExpressionRootForImplementation вызывается вместо CompiledExpressionInvoker.SetCompiledExpressionRoot.

Дополнительные сведения о работе с выражениями в коде см. в статье "Создание рабочих процессов, действий и выражений с помощью императивного кода".

Использование выражений C# в рабочих процессах XAML

Выражения на языке C# поддерживаются в рабочих процессах языка XAML. Скомпилированные рабочие процессы языка XAML компилируются в тип, свободные рабочие процессы языка XAML загружаются средой выполнения и компилируются в дерево действий при выполнении рабочего процесса.

Скомпилированный Xaml

Выражения C# поддерживаются в скомпилированных рабочих процессах XAML, скомпилированных в тип в рамках проекта рабочего процесса C#, который предназначен для платформа .NET Framework 4.6.1. Скомпилированный XAML — это тип разработки рабочих процессов по умолчанию в Visual Studio, а проекты рабочих процессов C#, созданные в Visual Studio, предназначенные для платформа .NET Framework 4.6.1, используют выражения C#.

Свободный xaml

Выражения на языке C# поддерживаются в свободных рабочих процессах языка XAML. Программа узла рабочего процесса, загружающая и вызывающая свободный рабочий процесс XAML, должна быть нацелена на платформа .NET Framework 4.6.1 и CompileExpressions должна иметь true значение (значение по умолчанию false). Чтобы установить свойству CompileExpressions значение true, создайте экземпляр ActivityXamlServicesSettings со свойством CompileExpressions, установленным в значение true, и передайте его как параметр в ActivityXamlServices.Load. Если CompileExpressions задано значение "Не задано true", NotSupportedException создается сообщение, аналогичное следующему: Expression Activity type 'CSharpValueдля выполнения требуется компиляция 1. Убедитесь, что рабочий процесс скомпилирован.

ActivityXamlServicesSettings settings = new ActivityXamlServicesSettings
{
    CompileExpressions = true
};

DynamicActivity<int> wf = ActivityXamlServices.Load(new StringReader(serializedAB), settings) as DynamicActivity<int>;

Дополнительные сведения о работе с рабочими процессами XAML см. в статье сериализация рабочих процессов и действий в XAML и из нее.

Использование выражений C# в службах рабочих процессов XAMLX

Выражения на языке C# поддерживаются в службах рабочих процессов XAMLX. Если служба рабочего процесса размещается в IIS или WAS, то дополнительные действия не требуются. Но если служба рабочих процессов языка XAML является резидентной, то выражения C# необходимо скомпилировать. Чтобы скомпилировать выражения C# в локальной службе рабочих процессов XAMLX, сначала загрузите XAMLX-файл в файлWorkflowService, а затем передайте WorkflowService Body метод, CompileExpressions описанный в предыдущем разделе "Использование выражений C# в рабочих процессах кода". В следующем примере загружается служба рабочих процессов XAMLX, компилируются выражения на языке C#, затем открывается служба рабочих процессов, которая начинает ожидать запросы.

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

Если выражения C# не скомпилированы, операция Open выполняется успешно, но при вызове рабочий процесс завершится ошибкой. CompileExpressions Следующий метод совпадает с методом из предыдущего выражения Using C# в разделе рабочих процессов кода.

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