Condividi tramite


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 destinati a .NET Framework 4.5 usano espressioni C# e i progetti di flusso di lavoro visual Basic usano espressioni Visual Basic. È possibile eseguire la migrazione di progetti di flusso di lavoro .NET Framework 4 esistenti che usano espressioni di Visual Basic a .NET Framework 4.6.1 indipendentemente dal linguaggio di progetto e supportati. Questo argomento offre una panoramica delle espressioni C# in WF.

Uso di espressioni C# nei flussi di lavoro

Uso di 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 del flusso di lavoro C# creati in Visual Studio 2012 destinati a .NET Framework 4.5 usano espressioni C#, mentre i progetti del flusso di lavoro visual Basic usano espressioni Visual Basic. Per specificare l'espressione C# desiderata, digitarla nella casella immettere un'espressione C#. Questa etichetta viene visualizzata nella finestra delle proprietà quando l'attività viene selezionata nella finestra di progettazione o nell'attività nella finestra di progettazione del flusso di lavoro. Nell'esempio seguente, due WriteLine attività sono contenute all'interno di un Sequence dentro un NoPersistScope.

Screenshot che mostra un'attività di sequenza creata automaticamente.

Annotazioni

Le espressioni C# sono supportate solo in Visual Studio e non sono supportate nella finestra di progettazione del flusso di lavoro ospitata di nuovo. Per ulteriori informazioni sulle nuove funzionalità di WF45 supportate nella progettazione di flussi di lavoro ri-ospitata, vedere Supporto per le nuove funzionalità di Workflow Foundation 4.5 nel Designer di Workflow ri-ospitato.

Compatibilità retroattiva

Sono supportate espressioni visual Basic nei progetti di flusso di lavoro C# di .NET Framework 4 esistenti di cui è stata eseguita la migrazione a .NET Framework 4.6.1. Quando le espressioni di Visual Basic vengono visualizzate nella finestra di progettazione del flusso di lavoro, il testo dell'espressione Visual Basic esistente viene sostituito con Value impostato in XAML, a meno che l'espressione Visual Basic non sia una sintassi C# valida. Se l'espressione Visual Basic è una sintassi C# valida, viene visualizzata l'espressione. Per aggiornare le espressioni di Visual Basic in C#, è possibile modificarle nella finestra di progettazione del flusso di lavoro e specificare l'espressione C# equivalente. Non è necessario aggiornare le espressioni di Visual Basic in C#, ma una volta aggiornate le espressioni nella finestra di progettazione del flusso di lavoro, queste vengono convertite in C# e potrebbero non essere ripristinate in Visual Basic.

Uso di espressioni C# nei flussi di lavoro del codice

Le espressioni C# sono supportate nei flussi di lavoro basati su codice di .NET Framework 4.6.1, ma prima che il flusso di lavoro possa essere richiamato, le espressioni C# devono essere compilate usando TextExpressionCompiler.Compile. Gli autori del flusso di lavoro possono usare CSharpValue per rappresentare il valore r di un'espressione e CSharpReference per rappresentare il valore l di un'espressione. Nell'esempio seguente viene creato un flusso di lavoro con un'attività Assign e un'attività WriteLine contenuta in un'attività Sequence . Un CSharpReference è specificato per l'argomento To del Assign e rappresenta l-value dell'espressione. Un CSharpValue oggetto viene specificato per l'argomento Value di Assigne per l'argomento Text di WriteLinee rappresenta il valore r per queste 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 la costruzione del flusso di lavoro, le espressioni C# vengono compilate chiamando il CompileExpressions metodo helper e quindi viene richiamato il flusso di lavoro. L'esempio seguente è il CompileExpressions metodo .

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

Annotazioni

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

Se il flusso di lavoro basato su codice personalizzato usa DynamicActivity, sono necessarie alcune modifiche al CompileExpressions metodo , come illustrato nell'esempio di codice seguente.

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 diverse differenze nell'overload CompileExpressions che compila le espressioni C# in un'attività dinamica.

  • Il parametro di CompileExpressions è un DynamicActivity.

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

  • TextExpressionCompilerSettings.ForImplementation è impostato su true.

  • CompiledExpressionInvoker.SetCompiledExpressionRootForImplementation viene chiamato invece di CompiledExpressionInvoker.SetCompiledExpressionRoot.

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

Uso di espressioni C# nei flussi di lavoro XAML

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

Xaml compilato

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

Xaml libero

Le espressioni C# sono supportate nei flussi di lavoro XAML separati. Il programma host del flusso di lavoro che carica e richiama il flusso di lavoro XAML libero deve essere destinato a .NET Framework 4.6.1 e CompileExpressions deve essere impostato su true (il valore predefinito è false). Per impostare CompileExpressions su true, crea un'istanza ActivityXamlServicesSettings con la proprietà CompileExpressions impostata su true, e la passa come parametro a ActivityXamlServices.Load. Se CompileExpressions non è impostato su true, verrà generata un'eccezione NotSupportedException con un messaggio simile al seguente: Expression Activity type 'CSharpValue1' richiede la compilazione per l'esecuzione. 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'uso dei flussi di lavoro XAML, vedere Serializzazione di flussi di lavoro e attività da e verso XAML.

Uso di espressioni C# nei servizi flusso di lavoro XAMLX

Le espressioni C# sono supportate nei servizi flusso di lavoro XAMLX. Quando un servizio flusso di lavoro è ospitato in IIS o WAS, non sono necessari passaggi aggiuntivi, ma se il servizio flusso di lavoro XAML è self-hosted, è necessario compilare le espressioni C#. Per compilare le espressioni C# in un servizio flusso di lavoro XAMLX self-hosted, innanzitutto caricare il file XAMLX nell'oggetto WorkflowService, e quindi passare il Body del WorkflowService al metodo CompileExpressions descritto nella sezione precedente Uso di espressioni C# nei flussi di lavoro di codice. Nell'esempio seguente viene caricato un servizio flusso di lavoro XAMLX, le espressioni C# vengono compilate e quindi il servizio flusso di lavoro viene aperto e attende le 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 vengono compilate, l'operazione Open ha esito positivo ma il flusso di lavoro avrà esito negativo quando viene richiamato. Il metodo seguente CompileExpressions è identico al metodo della sezione precedente Using C# expressions in code workflows (Uso di 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);
}