叫用活動驗證
活動驗證提供的方法可在活動執行前識別及報告任何活動之組態中的錯誤。 在工作流程設計工具中修改工作流程時,若工作流程設計工具中顯示任何驗證錯誤或警告,就會進行驗證。 叫用工作流程時,也會在執行階段進行驗證,而且如果發生任何驗證錯誤,預設驗證邏輯會擲回 InvalidWorkflowException。 Windows Workflow Foundation (WF) 提供了 ActivityValidationServices 類別,可讓工作流程應用程式和工具開發人員用來明確驗證活動。 本主題描述如何使用 ActivityValidationServices 執行活動驗證。
使用 ActivityValidationServices
ActivityValidationServices 具有兩個 Validate 負載,可用於叫用活動的驗證邏輯。 第一個多載會採用要驗證的根活動,然後傳回驗證錯誤及警告的集合。 下列範例中會使用具有兩個必要引數的自訂 Add
活動。
public sealed class Add : CodeActivity<int>
{
[RequiredArgument]
public InArgument<int> Operand1 { get; set; }
[RequiredArgument]
public InArgument<int> Operand2 { get; set; }
protected override int Execute(CodeActivityContext context)
{
return Operand1.Get(context) + Operand2.Get(context);
}
}
Add
活動用於 Sequence 內部,但其兩個必要的引數並未繫結,如下列範例所示。
Variable<int> Operand1 = new Variable<int>{ Default = 10 };
Variable<int> Operand2 = new Variable<int>{ Default = 15 };
Variable<int> Result = new Variable<int>();
Activity wf = new Sequence
{
Variables = { Operand1, Operand2, Result },
Activities =
{
new Add(),
new WriteLine
{
Text = new InArgument<string>(env => "The result is " + Result.Get(env))
}
}
};
您可以呼叫 Validate 來驗證此工作流程。 Validate 會傳回活動和任何子活動中包含的任何驗證錯誤或警告集合,如下列範例所示。
ValidationResults results = ActivityValidationServices.Validate(wf);
if (results.Errors.Count == 0 && results.Warnings.Count == 0)
{
Console.WriteLine("No warnings or errors");
}
else
{
foreach (ValidationError error in results.Errors)
{
Console.WriteLine("Error: {0}", error.Message);
}
foreach (ValidationError warning in results.Warnings)
{
Console.WriteLine("Warning: {0}", warning.Message);
}
}
在此工作流程範例中呼叫 Validate 時,會傳回兩個驗證錯誤。
錯誤:未提供必要活動引數 'Operand2' 的值。
錯誤:未提供必要活動引數 'Operand1' 的值。 如果叫用這個工作流程,就會擲回 InvalidWorkflowException,如下列範例所示。
try
{
WorkflowInvoker.Invoke(wf);
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
System.Activities.InvalidWorkflowException:
處理工作流程樹狀結構時發生下列錯誤:'Add':未提供必要活動引數 'Operand2' 的值。'Add':未提供必要活動引數 'Operand1' 的值。若要讓這個工作流程範例生效,就必須繫結 Add
活動的兩個必要引數。 在下列範例中,兩個必要引數會與結果值一同繫結於工作流程變數。 在此範例中,Result 引數會與兩個必要的引數一同繫結。 Result 引數不需繫結,若不繫結此引數,也不會導致驗證錯誤。 如果工作流程中的其他位置會使用 Result 的值,工作流程作者必須負責繫結該值。
new Add
{
Operand1 = Operand1,
Operand2 = Operand2,
Result = Result
}
在根活動驗證必要的引數
如果工作流程的根活動含有引數,則在叫用該工作流程並將參數傳遞到該工作流程之前,這些都不會被繫結。 下列工作流程會通過驗證,但若叫用工作流程而未傳入必要的引數,則會擲回例外狀況,如下列範例所示。
Activity wf = new Add();
ValidationResults results = ActivityValidationServices.Validate(wf);
// results has no errors or warnings, but when the workflow
// is invoked, an InvalidWorkflowException is thrown.
try
{
WorkflowInvoker.Invoke(wf);
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
System.ArgumentException:根活動的引數設定不正確。
修正工作流程定義或提供輸入值來修正這些錯誤:'Add':未提供必要活動引數 'Operand2' 的值。'Add':未提供必要活動引數 'Operand1' 的值。傳遞正確的引數後,工作流程就會成功完成,如下列範例所示。
Add wf = new Add();
ValidationResults results = ActivityValidationServices.Validate(wf);
// results has no errors or warnings, and the workflow completes
// successfully because the required arguments were passed.
try
{
Dictionary<string, object> wfparams = new Dictionary<string, object>
{
{ "Operand1", 10 },
{ "Operand2", 15 }
};
int result = WorkflowInvoker.Invoke(wf, wfparams);
Console.WriteLine("Result: {0}", result);
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
注意
在此範例中,根活動會宣告為 Add
,而非上一個範例中的 Activity
。 這樣可讓 WorkflowInvoker.Invoke
方法傳回單一整數,代表 Add
活動的結果 (而非 out
引數的字典)。 變數 wf
也可能已宣告為 Activity<int>
。
驗證根引數時,主機應用程式必須負責確保叫用工作流程時,會傳遞所有必要的引數。
叫用命令式的程式碼式驗證
命令式的程式碼驗證提供一個簡單的方式,可讓活動提供與其本身相關的驗證,而且適用於衍生自 CodeActivity、AsyncCodeActivity 和 NativeActivity 的活動。 活動中會加入用來判斷任何驗證錯誤或警告的驗證程式碼。 在活動叫用驗證時,這些警告或錯誤包含在呼叫 Validate 所傳回的集合中。 在下列範例中,會定義 CreateProduct
活動。 如果 Cost
大於 Price
,就會將驗證錯誤加入至CacheMetadata 覆寫中的中繼資料。
public sealed class CreateProduct : CodeActivity
{
public double Price { get; set; }
public double Cost { get; set; }
// [RequiredArgument] attribute will generate a validation error
// if the Description argument is not set.
[RequiredArgument]
public InArgument<string> Description { get; set; }
protected override void CacheMetadata(CodeActivityMetadata metadata)
{
base.CacheMetadata(metadata);
// Determine when the activity has been configured in an invalid way.
if (this.Cost > this.Price)
{
// Add a validation error with a custom message.
metadata.AddValidationError("The Cost must be less than or equal to the Price.");
}
}
protected override void Execute(CodeActivityContext context)
{
// Not needed for the sample.
}
}
在此範例中,會使用 CreateProduct
活動來設定工作流程。 在此工作流程中,Cost
大於 Price
,而且未設定必要的 Description
引數。 叫用驗證時,會傳回下列錯誤。
Activity wf = new Sequence
{
Activities =
{
new CreateProduct
{
Cost = 75.00,
Price = 55.00
// Cost > Price and required Description argument not set.
},
new WriteLine
{
Text = "Product added."
}
}
};
ValidationResults results = ActivityValidationServices.Validate(wf);
if (results.Errors.Count == 0 && results.Warnings.Count == 0)
{
Console.WriteLine("No warnings or errors");
}
else
{
foreach (ValidationError error in results.Errors)
{
Console.WriteLine("Error: {0}", error.Message);
}
foreach (ValidationError warning in results.Warnings)
{
Console.WriteLine("Warning: {0}", warning.Message);
}
}
錯誤:成本必須小於或等於價格。
錯誤:未提供必要的活動引數 'Description'。
注意
自訂活動作者可以在活動的 CacheMetadata 覆寫中提供驗證邏輯。 從 CacheMetadata 擲回的任何例外狀況都不會被視為驗證錯誤。 這些例外狀況會從 Validate 的呼叫中逸出,而且必須由呼叫端處理。
使用 ValidationSettings
根據預設,當 ActivityValidationServices 叫用驗證時,會評估活動樹狀結構中的所有活動。 ValidationSettings 允許透過設定驗證的三個屬性,以數種不同的方式自訂驗證。 SingleLevel 指定驗證程式是否應逐一查核整個活動樹狀,或者只需將驗證邏輯套用於所提供的活動。 此值的預設值為 false
。 AdditionalConstraints 會指定從型別至條件約束清單的其他條件約束對應。 為取得要驗證之活動樹狀結構中每個活動的基底型別,會查詢 AdditionalConstraints。 如果找到相符的條件約束清單,會為該活動評估清單中的所有條件約束。 OnlyUseAdditionalConstraints 指定驗證程式是否應評估所有條件約束,或者只需評估 AdditionalConstraints 中指定的條件約束。 預設值是 false
。 AdditionalConstraints和 OnlyUseAdditionalConstraints 適合讓工作流程主機作者用來新增額外的工作流程驗證,例如 FxCop 等工具的原則條件約束。 如需有關條件約束的詳細資訊,請參閱宣告式條件約束。
若要使用 ValidationSettings,請設定所需的屬性,然後在對 Validate 的呼叫中傳遞它。 在此範例中,會驗證包含 Sequence 的活動 (該活動具有 Add
活動)。 Add
活動具有兩個必要引數。
public sealed class Add : CodeActivity<int>
{
[RequiredArgument]
public InArgument<int> Operand1 { get; set; }
[RequiredArgument]
public InArgument<int> Operand2 { get; set; }
protected override int Execute(CodeActivityContext context)
{
return Operand1.Get(context) + Operand2.Get(context);
}
}
Add
中會使用下列 Sequence 活動,但不會繫結其兩個必要的引數。
Variable<int> Operand1 = new Variable<int> { Default = 10 };
Variable<int> Operand2 = new Variable<int> { Default = 15 };
Variable<int> Result = new Variable<int>();
Activity wf = new Sequence
{
Variables = { Operand1, Operand2, Result },
Activities =
{
new Add(),
new WriteLine
{
Text = new InArgument<string>(env => "The result is " + Result.Get(env))
}
}
};
針對下列範例,驗證執行時,SingleLevel 會設定為 true
,因此只會驗證根 Sequence 活動。
ValidationSettings settings = new ValidationSettings
{
SingleLevel = true
};
ValidationResults results = ActivityValidationServices.Validate(wf, settings);
if (results.Errors.Count == 0 && results.Warnings.Count == 0)
{
Console.WriteLine("No warnings or errors");
}
else
{
foreach (ValidationError error in results.Errors)
{
Console.WriteLine("Error: {0}", error.Message);
}
foreach (ValidationError warning in results.Warnings)
{
Console.WriteLine("Warning: {0}", warning.Message);
}
}
這個程式碼會顯示下列輸出:
沒有警告或錯誤 即使 Add
活動具有未繫結的必要引數,但因為只會評估根活動,所以驗證仍會成功。 若只驗證活動樹狀中的特定項目,例如要在設計工具中驗證單一活動的屬性變更,這種類型的驗證相當有用。 請注意,若叫用此工作流程,會評估工作流程中設定的完整驗證,而且可能會擲回 InvalidWorkflowException。 ActivityValidationServices 和 ValidationSettings 只會設定主機明確叫用的驗證,不會設定叫用工作流程時所發生的驗證。