Espressioni C#

A partire da .NET Framework 4.5, le espressioni C# sono supportate in Windows Workflow Foundation (WF). I nuovi progetti di flusso di lavoro C# creati in Visual Studio 2012 e destinati a .NET Framework 4.5 usano le espressioni C#, mentre i progetti di flusso di lavoro di Visual Basic usano le espressioni Visual Basic. I progetti di flusso di lavoro .NET Framework 4 esistenti che usano espressioni Visual Basic possono essere migrati a .NET Framework 4.6.1, indipendentemente dal linguaggio del progetto, e sono supportati. In questo argomento viene fornita una panoramica sulle espressioni C# in WF.

Utilizzo delle espressioni C# nei flussi di lavoro

Utilizzo delle espressioni C# in Progettazione flussi di lavoro

A partire da .NET Framework 4.5, le espressioni C# sono supportate in Windows Workflow Foundation (WF). I progetti di flusso di lavoro C# creati in Visual Studio 2012 e destinati a .NET Framework 4.5 usano le espressioni C#, mentre i progetti di flusso di lavoro di Visual Basic usano le espressioni Visual Basic. Per specificare l'espressione C# desiderata, digitarla nella casella con l'etichetta Immetti un'espressione C#. Questa etichetta viene visualizzata nella finestra delle proprietà quando l'attività viene selezionata nella finestra di progettazione o sull'attività in Progettazione flussi di lavoro. Nell'esempio seguente, due attività WriteLine sono contenute in Sequence all'interno di NoPersistScope.

Screenshot that shows an automatically created sequence activity.

Nota

Le espressioni C# sono supportate solo in Visual Studio e non sono supportate nella finestra di progettazione del flusso di lavoro ospitata nuovamente. Per altre informazioni sulle nuove funzionalità di WF45 supportate nella finestra di progettazione riallocata, vedere Supporto delle nuove funzionalità di Workflow Foundation 4.5 in Progettazione flussi di lavoro riallocato.

Compatibilità con le versioni precedenti

Sono supportate le espressioni Visual Basic dei progetti di flusso di lavoro C# di .NET Framework 4 esistenti che sono stati migrati a NET Framework 4.6.1. Quando le espressioni Visual Basic vengono visualizzate nella finestra di progettazione del flusso di lavoro, il testo dell'espressione Visual Basic esistente viene sostituito con Valore impostato in XAML, a meno che l'espressione Visual Basic costituisca una sintassi C# valida. Se l'espressione Visual Basic è una sintassi C# valida, l'espressione viene visualizzata. Per aggiornare le espressioni Visual Basic a C#, è possibile modificarle nella finestra di progettazione del flusso di lavoro e specificare l'espressione C# equivalente. Non è obbligatorio aggiornare le espressioni Visual Basic a C#, ma una volta che le espressioni vengono aggiornate nella finestra di progettazione del flusso di lavoro, vengono convertite in C# e non possono essere ripristinate in Visual Basic.

Utilizzo delle espressioni C# nei flussi di lavoro di codice

Le espressioni C# sono supportate nei flussi di lavoro basati sul codice di .NET Framework 4.6.1, ma prima di poter richiamare il flusso di lavoro, le espressioni C# devono essere compilate usando TextExpressionCompiler.Compile. Gli autori di flusso di lavoro possono usare CSharpValue per rappresentare l'elemento r-value di un'espressione e CSharpReference per rappresentare l'elemento l-value di un'espressione. Nell'esempio seguente viene creato un flusso di lavoro costituito da un'attività Assign e da un'attività WriteLine contenuta in un'attività Sequence. CSharpReference viene specificato per l'argomento di To di Assign e rappresenta l'elemento l-value dell'espressione. CSharpValue viene specificato per l'argomento Value di Assign e per l'argomento Text di WriteLine e rappresenta l'elemento r-value delle due espressioni.

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

Dopo aver costruito il flusso di lavoro, le espressioni C# vengono compilate chiamando il metodo di supporto CompileExpressions, quindi viene richiamato il flusso di lavoro. Nell'esempio seguente viene indicato il metodo 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);
}

Nota

Se le espressioni C# non vengono compilate, viene generata una NotSupportedException quando il flusso di lavoro viene richiamato con un messaggio simile al seguente: Per l'esecuzione di Expression Activity type 'CSharpValue1' è necessaria la compilazione. Assicurarsi che il flusso di lavoro sia stato compilato.

Se il flusso di lavoro basato sul codice personalizzato usa DynamicActivity, sono richieste alcune modifiche al metodo CompileExpressions, come illustrato nell'esempio di codice riportato di seguito.

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

Esistono numerose differenze nell'overload di CompileExpressions che compila le espressioni C# in un'attività dinamica.

  • Il parametro per CompileExpressions è DynamicActivity.

  • Il nome del tipo e lo spazio dei nomi vengono recuperati usando la proprietà DynamicActivity.Name.

  • TextExpressionCompilerSettings.ForImplementation è impostato su true.

  • CompiledExpressionInvoker.SetCompiledExpressionRootForImplementation viene chiamato al posto di CompiledExpressionInvoker.SetCompiledExpressionRoot.

Per altre informazioni sull'utilizzo di espressioni nel codice, vedere Creazione di flussi di lavoro, attività ed espressioni tramite codice imperativo.

Utilizzo delle espressioni C# nei flussi di lavoro XAML

Le espressioni C# sono supportate nei flussi di lavoro XAML. I flussi di lavoro XAML compilato vengono compilati in un tipo e i flussi di lavoro XAML separato vengono caricati dal runtime e compilati in un albero delle attività quando il flusso di lavoro viene eseguito.

XAML compilato

Le espressioni C# sono supportate nei flussi di lavoro XAML compilato che vengono compilati in un tipo come parte di un progetto di flusso di lavoro C# destinato a .NET Framework 4.6.1. XAML compilato è il tipo predefinito per la creazione di flussi di lavoro in Visual Studio, mentre i progetti di flusso di lavoro C# creati in Visual Studio e destinati a .NET Framework 4.6.1 usano espressioni C#.

XAML libero

Le espressioni C# sono supportate nei flussi di lavoro XAML separato. Il programma host del flusso di lavoro che carica e richiama il flusso di lavoro XAML separato deve essere destinato a .NET Framework 4.6.1 e CompileExpressions deve essere impostato su true (l'impostazione predefinita è false). Per impostare CompileExpressions su true, creare un'istanza di ActivityXamlServicesSettings con la relativa proprietà CompileExpressions impostata su true e passarla come parametro a ActivityXamlServices.Load. Se CompileExpressions non è impostato su true, verrà generata una NotSupportedException con un messaggio simile al seguente: Per l'esecuzione di Expression Activity type 'CSharpValue1' è necessaria la compilazione. Assicurarsi che il flusso di lavoro sia stato compilato.

ActivityXamlServicesSettings settings = new ActivityXamlServicesSettings
{
    CompileExpressions = true
};

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

Per altre informazioni sull'utilizzo di flussi di lavoro XAML, vedere Serializzazione di flussi di lavoro e attività da e verso XAML.

Utilizzo delle espressioni C# nei servizi flusso di lavoro XAMLX

Le espressioni C# sono supporte nei servizi flusso di lavoro XAMLX. Quando un servizio flusso di lavoro è ospitato in IIS o WAS non sono necessarie ulteriori attività, ma se il servizio flusso di lavoro XAML è indipendente, è necessario compilare le espressioni C#. Per compilare le espressioni C# in un servizio flusso di lavoro XAMLX indipendente, innanzitutto caricare il file XAMLX in WorkflowService e passare l'elemento Body di WorkflowService al metodo CompileExpressions descritto nella sezione precedente Utilizzo delle espressioni C# nei flussi di lavoro di codice. Nell'esempio seguente, viene caricato un servizio flusso di lavoro XAMLX, vengono compilate espressioni C# e quindi viene aperto il servizio flusso di lavoro in attesa di richieste.

// 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 le espressioni C# non sono compilate, l'operazione Open viene eseguita, ma il flusso di lavoro non verrà richiamato. Il metodo CompileExpressions riportato di seguito corrisponde al metodo della sezione precedente Utilizzo delle espressioni C# nei flussi di lavoro di codice.

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