Freigeben über


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-Workflowprojekte 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 migriert werden und unterstützt werden. Dieses Thema enthält 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, während Visual Basic-Workflowprojekte Visual Basic-Ausdrücke verwenden. Um den gewünschten C#-Ausdruck anzugeben, geben Sie ihn in das Feld mit der Bezeichnung "C#-Ausdruck eingeben" ein. Diese Bezeichnung wird im Eigenschaftenfenster angezeigt, wenn die Aktivität im Designer oder in der Aktivität im Workflow-Designer ausgewählt ist. Im folgenden Beispiel sind zwei WriteLine-Aktivitäten innerhalb eines Sequence in einem NoPersistScope enthalten.

Screenshot einer automatisch erstellten Sequenzaktivität.

Hinweis

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

Abwärtskompatibilität

Visual Basic-Ausdrücke in vorhandenen .NET Framework 4 C#-Workflowprojekten, 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 Value was set in XAML ersetzt, es sei denn, der Visual Basic-Ausdruck ist gültige C#-Syntax. Wenn der Visual Basic-Ausdruck eine gültige C#-Syntax ist, 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 C# zu aktualisieren, aber nachdem die Ausdrücke im Workflow-Designer aktualisiert wurden, werden sie in C# konvertiert und möglicherweise nicht auf Visual Basic zurückgesetzt.

Verwenden von C#-Ausdrücken in Codeworkflows

C#-Ausdrücke werden in .NET Framework 4.6.1 codegesteuerten Workflows unterstützt, aber bevor der Workflow aufgerufen werden kann, müssen die C#-Ausdrücke mithilfe von TextExpressionCompiler.Compile kompiliert werden. Workflowautoren können CSharpValue als R-Wert und CSharpReference als L-Wert eines Ausdrucks verwenden. 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. Ein CSharpReference wird für das To Argument des Assign Ausdrucks angegeben und stellt den L-Wert des Ausdrucks dar. Ein CSharpValue ist für das Value-Argument des Assign und für das Text-Argument des WriteLine angegeben und repräsentiert den R-Wert für diese beiden Ausdrücke.

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 die CompileExpressions Hilfsmethode aufgerufen und der Workflow aufgerufen wird. Das folgende Beispiel ist die CompileExpressions Methode.

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 Ihr benutzerdefinierter, codebasierter Workflow DynamicActivity verwendet, sind einige Änderungen an der CompileExpressions-Methode erforderlich, wie im folgenden Codebeispiel veranschaulicht.

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 von CompileExpressions ist ein DynamicActivity.

  • Der Typname und der Namespace werden mithilfe der DynamicActivity.Name Eigenschaft abgerufen.

  • TextExpressionCompilerSettings.ForImplementation ist auf true eingestellt.

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

Weitere Informationen zum Arbeiten mit Ausdrücken im Code finden Sie unter Erstellen von Workflows, Aktivitäten und Ausdrücken mit 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, während lose XAML-Workflows zur Laufzeit geladen und in einen Aktivitätsbaum kompiliert werden, wenn der Workflow ausgeführt wird.

Kompiliertes XAML

C#-Ausdrücke werden in kompilierten XAML-Workflows unterstützt, die als Teil eines C#-Workflowprojekts zu einem Typ kompiliert werden, das auf .NET Framework 4.6.1 ausgerichtet ist. In Visual Studio ist kompilierter XAML standardmäßig die Art der Workflowerstellung. C#-Workflowprojekte, die in Visual Studio erstellt werden und auf das .NET Framework 4.6.1 abzielen, verwenden C#-Ausdrücke.

Loses XAML

C#-Ausdrücke werden in losen XAML-Workflows unterstützt. Das Workflow-Hostprogramm, das den losen XAML-Workflow lädt und aufruft, muss das .NET Framework 4.6.1 anvisieren und CompileExpressions auf true festgelegt sein (der Standard ist false). Zum Festlegen CompileExpressions auf true, erstellen Sie eine ActivityXamlServicesSettings Instanz mit ihrer CompileExpressions Eigenschaft auf true, und übergeben Sie sie als Parameter an ActivityXamlServices.Load. Wenn CompileExpressions nicht auf true festgelegt ist, wird eine NotSupportedException mit einer Meldung ähnlich der folgenden ausgelöst: Expression Activity type 'CSharpValue1' muss kompiliert werden, 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 wird, sind keine zusätzlichen Schritte erforderlich, aber wenn der XAML-Workflowdienst selbst gehostet wird, müssen die C#-Ausdrücke kompiliert werden. Um die C#-Ausdrücke in einem selbst gehosteten XAMLX-Workflowdienst zu kompilieren, laden Sie zuerst die XAMLX-Datei in eine WorkflowService, und übergeben Sie dann das Body des WorkflowService an die CompileExpressions-Methode, die im vorherigen Abschnitt "Verwenden von C#-Ausdrücken in Codeworkflows" beschrieben wurde. Im folgenden Beispiel wird ein XAMLX-Workflowdienst geladen, die C#-Ausdrücke werden kompiliert, und dann 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, wird der Open Vorgang erfolgreich ausgeführt, der Workflow schlägt jedoch fehl, wenn er aufgerufen wird. Die folgende CompileExpressions Methode ist dieselbe wie die Methode im vorherigen Abschnitt "C#-Ausdrücke in Code-Workflows verwenden".

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