宣言型制約は、アクティビティとその他のアクティビティとの関係を検証する強力な方法を提供します。 制約は、作成プロセス中にアクティビティに対して構成されますが、ワークフロー ホストによって追加の制約を指定することもできます。 このトピックでは、宣言型制約を使用してアクティビティの検証を行う方法の概要について説明します。
宣言型制約の使用
制約は、検証ロジックを含むアクティビティです。 この制約アクティビティは、コードまたは XAML で作成できます。 制約アクティビティが作成された後、アクティビティの作成者は、検証するアクティビティのConstraints プロパティにこの制約を追加するか、制約を使用して、ValidationSettings インスタンスのAdditionalConstraints プロパティを使用して追加の検証を提供します。 検証ロジックは、アクティビティのメタデータの検証などの単純な検証で構成できますが、現在のアクティビティの親、子、兄弟アクティビティとの関係を考慮して検証を実行することもできます。 制約は Constraint<T> アクティビティを使用して作成され、検証エラーと警告の作成を支援し、ワークフロー内の関連アクティビティに関する情報を提供するために、いくつかの追加の検証アクティビティが提供されます。
AssertValidation と AddValidationError
AssertValidation アクティビティは、Assertion プロパティによって参照される式を評価し、式がfalse
と評価された場合、検証エラーまたは警告がValidationResultsに追加されます。
Message プロパティは検証エラーを示し、IsWarning プロパティは検証エラーがエラーか警告かを示します。
IsWarning の既定値は false
です。
次の例では、検証中のアクティビティの DisplayName が 2 文字以下の場合に検証警告を返す制約が宣言されています。 Constraint<T>に使用されるジェネリック型パラメーターは、制約によって検証されるアクティビティの型を指定します。 この制約では、ジェネリック型として Activity を使用し、すべての種類のアクティビティを検証するために使用できます。
public static Constraint ActivityDisplayNameIsNotSetWarning()
{
DelegateInArgument<Activity> element = new DelegateInArgument<Activity>();
return new Constraint<Activity>
{
Body = new ActivityAction<Activity, ValidationContext>
{
Argument1 = element,
Handler = new AssertValidation
{
IsWarning = true,
Assertion = new InArgument<bool>(env => (element.Get(env).DisplayName.Length > 2)),
Message = new InArgument<string>("It is a best practice to have a DisplayName of more than 2 characters."),
}
}
};
}
アクティビティに対してこの制約を指定するために、次のコード例に示すように、アクティビティの Constraints に追加されます。
public sealed class SampleActivity : CodeActivity
{
public SampleActivity()
{
base.Constraints.Add(ActivityDisplayNameIsNotSetWarning());
}
// Activity implementation omitted.
}
ホストは、次のセクションで説明する AdditionalConstraintsを使用して、ワークフロー内のアクティビティに対してこの制約を指定することもできます。
AddValidationError アクティビティは、式の評価を必要とせずに検証エラーまたは警告を生成するために使用されます。 プロパティは AssertValidation に似ていますが、 If アクティビティなどの制約のフロー制御アクティビティと組み合わせて使用できます。
ワークフローリレーションシップアクティビティ
検証対象のアクティビティに関連して、ワークフロー内の他のアクティビティに関する情報を提供するいくつかの検証アクティビティを使用できます。 GetParentChain は、現在のアクティビティとルート アクティビティの間のすべてのアクティビティを含むアクティビティのコレクションを返します。 GetChildSubtree は、再帰パターン内の子アクティビティを含むアクティビティのコレクションを提供し、 GetWorkflowTree はワークフロー内のすべてのアクティビティを取得します。
次の例では、 CreateState
アクティビティを定義します。
CreateState
アクティビティはCreateCountry
アクティビティ内に含まれている必要があり、GetParent
メソッドは、この要件を適用する制約を返します。
GetParent
では、 GetParentChain アクティビティを ForEach<T> アクティビティと組み合わせて使用して、 CreateState
アクティビティの親アクティビティを調べて、要件が満たされているかどうかを判断します。
public sealed class CreateState : CodeActivity
{
public CreateState()
{
base.Constraints.Add(CheckParent());
this.Cities = new List<Activity>();
}
public List<Activity> Cities { get; set; }
public string Name { get; set; }
static Constraint CheckParent()
{
DelegateInArgument<CreateState> element = new DelegateInArgument<CreateState>();
DelegateInArgument<ValidationContext> context = new DelegateInArgument<ValidationContext>();
Variable<bool> result = new Variable<bool>();
DelegateInArgument<Activity> parent = new DelegateInArgument<Activity>();
return new Constraint<CreateState>
{
Body = new ActivityAction<CreateState,ValidationContext>
{
Argument1 = element,
Argument2 = context,
Handler = new Sequence
{
Variables =
{
result
},
Activities =
{
new ForEach<Activity>
{
Values = new GetParentChain
{
ValidationContext = context
},
Body = new ActivityAction<Activity>
{
Argument = parent,
Handler = new If()
{
Condition = new InArgument<bool>((env) => object.Equals(parent.Get(env).GetType(),typeof(CreateCountry))),
Then = new Assign<bool>
{
Value = true,
To = result
}
}
}
},
new AssertValidation
{
Assertion = new InArgument<bool>(result),
Message = new InArgument<string> ("CreateState has to be inside a CreateCountry activity"),
}
}
}
}
};
}
protected override void Execute(CodeActivityContext context)
{
// not needed for the sample
}
}
その他の制約
ワークフロー ホストの作成者は、制約を作成し、ValidationSettings インスタンスのAdditionalConstraintsディクショナリに追加することで、ワークフロー内のアクティビティに追加の検証制約を指定できます。
AdditionalConstraintsの各項目には、制約が適用されるアクティビティの種類と、その種類のアクティビティに対する追加の制約の一覧が含まれています。 ワークフローに対して検証が呼び出されると、派生クラスを含む、指定された型の各アクティビティによって制約が評価されます。 この例では、前のセクションの ActivityDisplayNameIsNotSetWarning
制約がワークフロー内のすべてのアクティビティに適用されます。
Activity wf = new Sequence
{
// Workflow Details Omitted.
};
ValidationSettings settings = new ValidationSettings()
{
AdditionalConstraints =
{
{typeof(Activity), new List<Constraint> {ActivityDisplayNameIsNotSetWarning()}},
}
};
// Validate the workflow.
ValidationResults results = ActivityValidationServices.Validate(wf, settings);
// Evaluate the results.
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 in " + error.Source.DisplayName + ": " + error.Message);
}
foreach (ValidationError warning in results.Warnings)
{
Console.WriteLine("Warning in " + warning.Source.DisplayName + ": " + warning.Message);
}
}
ValidationSettingsのOnlyUseAdditionalConstraints プロパティがtrue
場合、Validateを呼び出して検証が呼び出されたときに、指定された追加の制約のみが評価されます。 これは、特定の検証構成のワークフローを検査する場合に役立ちます。 ただし、ワークフローが呼び出されると、ワークフローで構成された検証ロジックが評価され、ワークフローが正常に開始するには合格する必要があることに注意してください。 検証の呼び出しの詳細については、「 アクティビティ検証の呼び出し」を参照してください。
.NET