アクティビティの検証では、アクティビティの実行前にアクティビティの構成でエラーを識別して報告するメソッドが提供されます。 検証は、ワークフロー デザイナーでワークフローが変更され、検証エラーまたは警告がワークフロー デザイナーに表示されるときに発生します。 検証は、ワークフローが呼び出されたときに実行時にも発生し、検証エラーが発生した場合は、既定の検証ロジックによって InvalidWorkflowException がスローされます。 Windows Workflow Foundation (WF) には、ワークフロー アプリケーションおよびツール開発者がアクティビティを明示的に検証するために使用できる ActivityValidationServices クラスが用意されています。 このトピックでは、 ActivityValidationServices を使用してアクティビティの検証を実行する方法について説明します。
ActivityValidationServices の使用
ActivityValidationServices には、アクティビティの検証ロジックを呼び出すために使用される 2 つの Validate オーバーロードがあります。 最初のオーバーロードは、検証するルート アクティビティを受け取り、検証エラーと警告のコレクションを返します。 次の例では、2 つの必須引数を持つカスタム 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内で使用されますが、次の例に示すように、2 つの必須引数はバインドされません。
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 が呼び出されると、2 つの検証エラーが返されます。
エラー: 必須のアクティビティ引数 'Operand2' の値が指定されませんでした。エラー: 必須のアクティビティ引数 'Operand1' の値が指定されませんでした。 このワークフローが呼び出された場合、次の例に示すように、 InvalidWorkflowException がスローされます。
try
{
WorkflowInvoker.Invoke(wf);
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
System.Activities.InvalidWorkflowException:ワークフロー ツリーの処理中に次のエラーが発生しました:'Add': 必要なアクティビティ引数 'Operand2' の値が指定されませんでした。'Add': 必須のアクティビティ引数 'Operand1' の値が指定されませんでした。 このワークフロー例を有効にするには、 Add アクティビティの 2 つの必須引数をバインドする必要があります。 次の例では、2 つの必須引数が結果値と共にワークフロー変数にバインドされています。 この例では、 Result 引数は 2 つの必須引数と共にバインドされます。
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 アクティビティの結果を表す 1 つの整数 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 では、3 つのプロパティを構成することで、検証をいくつかの異なる方法でカスタマイズできます。
SingleLevel は、バリデーターがアクティビティ ツリー全体をウォークするか、指定されたアクティビティにのみ検証ロジックを適用するかを指定します。 この値の既定値は false です。
AdditionalConstraints は、型から制約の一覧への追加の制約マッピングを指定します。 検証対象のアクティビティ ツリー内の各アクティビティの基本型には、 AdditionalConstraintsへの参照があります。 一致する制約リストが見つかった場合、リスト内のすべての制約がアクティビティに対して評価されます。
OnlyUseAdditionalConstraints では、検証コントロールですべての制約を評価するか、 AdditionalConstraintsで指定された制約のみを評価するかを指定します。 既定値は false です。
AdditionalConstraints と OnlyUseAdditionalConstraints は、ワークフロー ホストの作成者が、FxCop などのツールのポリシー制約など、ワークフローの検証を追加するのに役立ちます。 制約の詳細については、「 宣言型制約」を参照してください。
ValidationSettingsを使用するには、目的のプロパティを構成し、Validateの呼び出しで渡します。 この例では、カスタム Sequence アクティビティを含むAddで構成されるワークフローが検証されます。
Add アクティビティには、2 つの必須引数があります。
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で使用されますが、その 2 つの必須引数はバインドされていません。
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 アクティビティにはバインドされていない必須の引数がありますが、ルート アクティビティのみが評価されるため、検証は成功します。 この種類の検証は、デザイナーの 1 つのアクティビティのプロパティ変更の検証など、アクティビティ ツリー内の特定の要素のみを検証する場合に便利です。 このワークフローが呼び出されると、ワークフローで構成されている完全な検証が評価され、 InvalidWorkflowException がスローされることに注意してください。
ActivityValidationServices と ValidationSettings 、ワークフローが呼び出されたときに発生する検証ではなく、ホストによって明示的に呼び出された検証のみを構成します。
.NET