C#-Ausdrücke

Ab .NET Framework 4.5 werden C#-Ausdrücke in Windows Workflow Foundation (WF) unterstützt. Neue C#-Workflowprojekte, die in Visual Studio 2012 für .NET Framework 4.5 erstellt wurden, verwenden C#-Ausdrücke, und Visual Basic-Workflowprojeke verwenden Visual Basic-Ausdrücke. Vorhandene .NET Framework 4-Workflowprojekte, die Visual Basic-Ausdrücke verwenden, können unabhängig von der Projektsprache zu .NET Framework 4.6.1 migrieren und werden unterstützt. Dieser Artikel bietet eine Übersicht über C#-Ausdrücke in WF.

Verwenden von C#-Ausdrücken in Workflows

Verwenden von C#-Ausdrücken im Workflow-Designer

Ab .NET Framework 4.5 werden C#-Ausdrücke in Windows Workflow Foundation (WF) unterstützt. C#-Workflowprojekte, die in Visual Studio 2012 für .NET Framework 4.5 erstellt wurden, verwenden C#-Ausdrücke, und Visual Basic-Workflowprojeke verwenden Visual Basic-Ausdrücke. Um den gewünschten C#-Ausdruck festzulegen, geben Sie ihn in das Feld mit der Bezeichnung C#-Ausdruck eingeben ein. Die Bezeichnung wird im Eigenschaftenfenster angezeigt, wenn die Aktivität im Designer ausgewählt wird, oder in der Aktivität im Workflow-Designer. Im folgenden Beispiel sind zwei WriteLine-Aktivitäten in Sequence innerhalb von NoPersistScope enthalten.

Screenshot that shows an automatically created sequence activity.

Hinweis

C#-Ausdrücke werden nur in Visual Studio unterstützt und nicht im neu gehosteten Workflow-Designer. Weitere Informationen zu neuen WF45-Features, die im erneut gehosteten Designer unterstützt werden, finden Sie unter Unterstützung für neue Workflow Foundation 4.5-Features im erneut gehosteten Workflow-Designer.

Abwärtskompatibilität

Visual Basic-Ausdrücke in vorhandenen C#-Workflowprojekten in .NET Framework 4, die zu .NET Framework 4.6.1 migriert wurden, werden unterstützt. Wenn die Visual Basic-Ausdrücke im Workflow-Designer angezeigt werden, wird der Text des vorhandenen Visual Basic-Ausdrucks durch Wert wurde in XAML festgelegt ersetzt, es sei denn, der Visual Basic-Ausdruck entspricht gültiger C#-Syntax. Wenn der Visual Basic-Ausdruck gültiger C#-Syntax entspricht, wird der Ausdruck angezeigt. Um die Visual Basic-Ausdrücke auf C# zu aktualisieren, können Sie sie im Workflow-Designer bearbeiten und den entsprechenden C#-Ausdruck angeben. Es ist nicht erforderlich, die Visual Basic-Ausdrücke auf Visual C# zu aktualisieren. Nachdem die Ausdrücke jedoch im Workflow-Designer aktualisiert wurden, werden sie in C# konvertiert und möglicherweise nicht in Visual Basic wiederhergestellt.

Verwenden von C#-Ausdrücken in Codeworkflows

C#-Ausdrücke werden in codebasierten .NET Framework 4.6.1-Workflows unterstützt. Bevor der Workflow aufgerufen werden kann, müssen C#-Ausdrücke jedoch mit TextExpressionCompiler.Compile kompiliert werden. Workflowautoren können CSharpValue verwenden, um den R-Wert eines Ausdrucks darzustellen, und CSharpReference, um den L-Wert eines Ausdrucks darzustellen. Im folgenden Beispiel wird ein Workflow mit einer Assign-Aktivität und einer WriteLine-Aktivität erstellt, die in einer Sequence-Aktivität enthalten ist. CSharpReference wird für das To-Argument von Assign angegeben und stellt den L-Wert des Ausdrucks dar. Ein CSharpValue wird für das Value-Argument von Assign und für das Text-Argument von WriteLine angegeben und stellt den R-Wert für diese beiden Ausdrücke dar.

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

Nachdem der Workflow erstellt wurde, werden die C#-Ausdrücke kompiliert, indem erst die CompileExpressions-Hilfsmethode und dann der Workflow aufgerufen wird. Im folgenden Beispiel wird die CompileExpressions-Methode verwendet:

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

Hinweis

Werden die C#-Ausdrücke nicht kompiliert, wird eine NotSupportedException ausgelöst, wenn der Workflow mit einer Nachricht ähnlich der Folgenden aufgerufen wird: Expression Activity type 'CSharpValue„1' erfordert eine Kompilierung, um ausgeführt zu werden. Stellen Sie sicher, dass der Workflow kompiliert wurde.“

Wenn der auf benutzerdefiniertem Code basierende Workflow DynamicActivity verwendet, sind einige Änderungen an der CompileExpressions-Methode erforderlich, wie im folgenden Codebeispiel gezeigt.

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

Es gibt einige Unterschiede in der CompileExpressions-Überladung, die die C#-Ausdrücke in eine dynamische Aktivität kompiliert.

  • Der Parameter zu CompileExpressions ist DynamicActivity.

  • Typname und Namespace werden mit der DynamicActivity.Name-Eigenschaft abgerufen.

  • TextExpressionCompilerSettings.ForImplementation ist auf true festgelegt.

  • CompiledExpressionInvoker.SetCompiledExpressionRootForImplementation wird anstelle von CompiledExpressionInvoker.SetCompiledExpressionRoot aufgerufen.

Weitere Informationen zur Verwendung von Ausdrücken im Code finden Sie unter Erstellen von Workflows, Aktivitäten und Ausdrücken mithilfe von imperativem Code.

Verwenden von C#-Ausdrücken in XAML-Workflows

C#-Ausdrücke werden in XAML-Workflows unterstützt. Kompilierte XAML-Workflows werden in einen Typ kompiliert und Loose XAML-Workflows werden von der Laufzeit geladen und beim Ausführen des Workflows in eine Aktivitätsstruktur kompiliert.

Kompilierte XAML

C#-Ausdrücke werden in kompilierten XAML-Workflows unterstützt, die als Teil eines C#-Workflowprojekts, das .NET Framework 4.6.1 als Zielframework verwendet, in einen Typ kompiliert werden. Kompilierter XAML-Code ist der Standardtyp bei der Workflowerstellung in Visual Studio, und in Visual Studio erstellte C#-Workflowprojekte, die auf .NET Framework 4.6.1 ausgerichtet sind, verwenden C#-Ausdrücke.

Loose Xaml

C#-Ausdrücke werden in Loose XAML-Workflows unterstützt. Das Workflowhostprogramm, von dem der Loose XAML-Workflow geladen und aufgerufen wird, muss .NET Framework 4.6.1 als Zielframework verwenden, und CompileExpressions muss auf true festgelegt werden (der Standardwert ist false). Zum Festlegen von CompileExpressions auf true erstellen Sie eine ActivityXamlServicesSettings-Instanz, deren CompileExpressions-Eigenschaft auf true festgelegt ist, und übergeben sie als Parameter an ActivityXamlServices.Load. Wenn CompileExpressions nicht auf true festgelegt ist, wird eine NotSupportedException mit einer Meldung wie der folgenden ausgelöst: Expression Activity type 'CSharpValue„1' erfordert eine Kompilierung, um ausgeführt zu werden. Stellen Sie sicher, dass der Workflow kompiliert wurde.“

ActivityXamlServicesSettings settings = new ActivityXamlServicesSettings
{
    CompileExpressions = true
};

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

Weitere Informationen zum Arbeiten mit XAML-Workflows finden Sie unter Serialisieren von Workflows und Aktivitäten in und aus XAML.

Verwenden von C#-Ausdrücken in XAMLX-Workflowdiensten

C#-Ausdrücke werden in XAMLX-Workflowdiensten unterstützt. Wenn ein Workflowdienst in IIS oder WAS gehostet ist, sind keine zusätzlichen Schritte erforderlich. Ist der XAML-Workflowdienst jedoch selbst gehostet, müssen die C#-Ausdrücke kompiliert werden. Um die C#-Ausdrücke in einen selbst gehosteten XAMLX-Workflowdienst zu kompilieren, laden Sie zuerst die XAMLX-Datei in einen WorkflowService und übergeben dann den Body des WorkflowService an die CompileExpressions-Methode, die im vorherigen Abschnitt Verwenden von C#-Ausdrücken in Codeworkflows beschrieben wird. Im folgenden Beispiel wird ein XAMLX-Workflowdienst geladen, und die C#-Ausdrücke werden kompiliert. Anschließend wird der Workflowdienst geöffnet und wartet auf Anforderungen.

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

Wenn die C#-Ausdrücke nicht kompiliert werden, ist der Open-Vorgang zwar erfolgreich, der Workflow verursacht beim Aufruf jedoch einen Fehler. Die folgendeCompileExpressions-Methode entspricht der Methode aus dem vorherigen Abschnitt Verwenden von C#-Ausdrücken in Codeworkflows.

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