C# 運算式
Windows Workflow Foundation (WF) 從 .NET Framework 4.5 開始支援 C# 運算式。 在 Visual Studio 2012 中建立,且目標為 .NET Framework 4.5 的新 C# 工作流程專案使用 C# 運算式,Visual Basic 工作流程專案則使用 Visual Basic 運算式。 不論採用何種專案語言,使用 Visual Basic 運算式的現有 .NET Framework 4 工作流程專案均可移轉至 .NET Framework 4.6.1 且皆受到支援。 本主題提供 WF 中的 C# 運算式概觀。
在工作流程中使用 C# 運算式
在工作流程設計工具中使用 C# 運算式
Windows Workflow Foundation (WF) 從 .NET Framework 4.5 開始支援 C# 運算式。 在 Visual Studio 2012 中建立,且目標為 .NET Framework 4.5 的新 C# 工作流程專案使用 C# 運算式,Visual Basic 工作流程專案則使用 Visual Basic 運算式。 若要指定想要的 C# 運算式,請在標示為 [輸入 C# 運算式] 的方塊中輸入運算式。 在設計工具中選取活動時,會在屬性視窗中顯示此標籤,而此標籤也會顯示在工作流程設計工具中的活動之上。 在下列範例中,WriteLine
內的 Sequence
包含兩個 NoPersistScope
活動。
注意
只有 Visual Studio 支援 C# 運算式,重新裝載的工作流程設計工具則不支援。 關於重新裝載設計工具支援的新 WF45 功能詳細資訊,請參閱重新裝載工作流程設計工具中的新 Workflow Foundation 4.5 功能支援。
回溯相容性
支援已移轉至 .NET Framework 4.6.1 的現有 .NET Framework 4 C# 工作流程專案中的 Visual Basic 運算式。 在工作流程設計工具中檢視 Visual Basic 運算式時,除非現有 Visual Basic 運算式為有效的 C# 語法,否則在 XAML 中設定的值會取代運算式的內容。 如果 Visual Basic 運算式為有效的 C# 語法,則會顯示該運算式。 若要將 Visual Basic 運算式更新為 C#,您可以在工作流程設計工具中編輯這些運算式,並指定相等的 C# 運算式。 您不需要將 Visual Basic 運算式更新為 C#,不過一旦這些運算式在工作流程設計工具中更新,將會轉換為 C#,且可能無法還原為 Visual Basic。
在程式碼工作流程中使用 C# 運算式
.NET Framework 4.6.1 程式碼工作流程支援 C# 運算式,但必須使用 TextExpressionCompiler.Compile 編譯 C# 運算式,工作流程才能叫用運算式。 工作流程作者可以使用 CSharpValue
來表示運算式的右值 (r-value),並使用 CSharpReference
來表示運算式的左值 (l-value)。 下列範例使用 Assign
活動內含的 WriteLine
活動和 Sequence
活動,來建立工作流程。 該範例為 CSharpReference
的 To
引數,指定一個 Assign
,表示運算式的左值。 CSharpValue
的 Value
引數和 Assign
的 Text
引數指定一個 WriteLine
,表示這兩個運算式的右值。
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);
建構工作流程之後,會呼叫 CompileExpressions
Helper 方法來編譯 C# 運算式,然後叫用工作流程。 以下範例是 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 'CSharpValue
1「必須編譯才能執行。 請確定工作流程已編譯。」
如果您的自訂程式碼為主之工作流程使用 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);
}
在動態活動中編譯 C# 運算式的 CompileExpressions
多載有一些差異。
傳給
CompileExpressions
的參數為DynamicActivity
。擷取型別名稱和命名空間需使用
DynamicActivity.Name
屬性。TextExpressionCompilerSettings.ForImplementation
設定為true
。呼叫
CompiledExpressionInvoker.SetCompiledExpressionRootForImplementation
,而不是CompiledExpressionInvoker.SetCompiledExpressionRoot
。
如需有關在程式碼中使用運算式的詳細資訊,請參閱使用命令式程式碼撰寫工作流程、活動和運算式。
在 XAML 工作流程中使用 C# 運算式
XAML 工作流程支援 C# 運算式。 編譯的 XAML 工作流程會編譯為型別,而鬆散的 XAML 工作流程會在工作流程執行時,由執行階段載入並編譯為活動樹狀。
編譯的 XAML
經過編譯的 XAML 工作流程支援 C# 運算式。該工作流程編譯而成的型別隨附於目標為 .NET Framework 4.6.1 的 C# 工作流程專案。 經過編譯的 XAML 是在 Visual Studio 中製作之工作流程的型別。在 Visual Studio 中建立且目標為 .NET Framework 4.6.1 的 C# 工作流程專案使用 C# 運算式。
鬆散的 XAML
鬆散的 XAML 工作流程支援 C# 運算式。 載入及叫用鬆散 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 和傳送至 XAML 的工作流程及活動序列化。
在 XAMLX 工作流程服務中使用 C# 運算式
XAMLX 工作流程服務支援 C# 運算式。 如果工作流程服務是以 IIS 或 WAS 裝載,則不需要其他步驟;但是,如果 XAML 工作流程服務為自我裝載,則必須編譯 C# 運算式。 若要在自行裝載 XAMLX 工作流程服務中編譯 C# 運算式,請先將 XAMLX 檔案載入 WorkflowService
,然後再將 WorkflowService
的 Body
傳遞至上一節<在程式碼工作流程中使用 C# 運算式>所述的 CompileExpressions
方法。 下列範例將載入 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
方法與上一節<在程式碼工作流程中使用 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);
}