ASP.NET MVC ModelValidatorを核心とするModel検証システム:ModelValidatorProvider
18417 ワード
『ASP.NET MVC ModelValidatorを核心とするModel検証システム:ModelValidator』ではASP.を紹介しています.NET MVCはModel検証用の4種類のModelValidatorですが、これらのModelValidatorはどのように作成されていますか?ASP.NET MVCの多くのコンポーネント(ModelBinderやFilterなど)は、これらのModelValidatorに対応するModelValidatorProviderについて説明するProviderベースの提供メカニズムを採用しています.[本文は『How ASP.NET MVC Works?』に同期しました.]
ディレクトリ1、ModelValidatorProvider 2、DataAnnotationsModelValidator 3、ClientDataTypeModelValidatorProvider 4、DataErrorInfoModelValidatorProvider 4
一、ModelValidatorProvider
ディレクトリ1、ModelValidatorProvider 2、DataAnnotationsModelValidator 3、ClientDataTypeModelValidatorProvider 4、DataErrorInfoModelValidatorProvider 4
一、ModelValidatorProvider
ModelValidatorProviderを登録することで、対応するModelValidatorを作成し、すべてのModelValidatorProviderが直接または間接的にタイプModelValidatorProviderを継承します.以下のコード断片に示すように,ModelValidatorの提供は抽象的な方法GetValidators種で実現され,ModelValidatorの集合を返す. 1: public abstract class ModelValidatorProvider
2: {
3: public abstract IEnumerable GetValidators(ModelMetadata metadata, ModelBindingExecutionContext context);
4: }
ValueProviderが提供するデータ値は単純なタイプに限られるため、複雑なタイプのModelバインドに対しては、Modelオブジェクトとしてのすべての属性を再帰的なプロセスでバインドします.Model検証はModelバインドの後続の一環と見なすことができ、バインドされたデータに対して検証を実施するので、Model検証も再帰的なプロセスであり、属性に基づく検証規則を用いてバインドの属性値に対して検証を実施する.GetValidatorsメソッドには、2つのパラメータがあります.タイプModelMetadataのmetadataパラメータは、検証ルールまたは対応する検証ルールに使用されます.パラメータcontextは、現在のModelバインドコンテキストを表すModelBindingExecutionContextオブジェクトです.
二、DataAnnotationsModelValidator
前述したデータ寸法特性検証方式のDataAnnotationsModelValidatorに対応するModelValidatorProviderタイプは、DataAnnotationsModelValidatorProviderです.次のコード・セグメントに示すように、DataAnnotationsModelValidatorProviderは、別の抽象タイプAssociatedValidatorProviderから継承されます. 1: public class DataAnnotationsModelValidatorProvider : AssociatedValidatorProvider
2: {
3: //
4: public DataAnnotationsModelValidatorProvider();
5: protected override IEnumerable GetValidators(ModelMetadata metadata, ControllerContext context,IEnumerable attributes);
6: }
タイプ名AssociatedValidatorProviderの「Association(Association)」とは、実際には、Modelメタデータから取得された検証ルールを定義するためのプロパティのリストに基づいて、対応するModelValidatorを提供する関連プロパティのリストを表します.次のコード・セグメントに示すように、A s s o c i atedValidatorProviderは、インタフェースICustomType Descriptorを実装するタイプの指定されたタイプの記述オブジェクトを取得するための保護されたダミー・メソッドGetType Descriptorを定義します.解析された関連特性は最終的に抽象的なGetValidatorsメソッドに伝達され、ModelValidatorの提供が実現され、DataAnnotationsModelValidatorProviderは、対応するDataAnnotationsModelValidatorリストを作成するためにこの方法を実現した. 1: public abstract class AssociatedValidatorProvider : ModelValidatorProvider
2: {
3: protected virtual ICustomTypeDescriptor GetTypeDescriptor(Type type);
4: public sealed override IEnumerable GetValidators(ModelMetadata metadata, ControllerContext context);
5: protected abstract IEnumerable GetValidators(ModelMetadata metadata, ControllerContext context, IEnumerable attributes);
6: }
書き換えられたGetValidatorsメソッドでは、現在のModelメタデータがある属性に基づいている(コンテナタイプを表すContainerTypeはNullではなく属性名を持つ)場合、GetType Descriptorメソッドを呼び出してコンテナタイプ記述オブジェクトを取得し、さらに属性クラスタイプに応じて属性を記述するためのPropertyDescriptorオブジェクトを得る.最終的に、記述オブジェクトによって、対応する属性に適用されるすべての特性が得られ、抽象メソッドGetValidatorsを呼び出して、属性ベースのModelValidatorリストが返される.非属性Modelメタデータの場合、GetTypeDescriptorメソッドを直接呼び出してModelタイプ記述オブジェクトを取得し、さらにModelタイプに適用されるすべての特性を取得し、抽象メソッドGetValidatorsに転送してModelタイプに対するModelValidatorの提供を実現する.
三、ClientDataTypeModelValidatorProvider
数値および日付タイプのクライアントに対して検証されたNumericModelValidatorおよびDateModelValidatorは、最終的には、次のように定義されたClientDataTypeModelValidatorProviderによって提供されます.GetValidatorsメソッドでは、指定したModelメタデータに基づいて数値タイプ/DateTimeタイプに属するかどうかを判断します.そうであれば、単一のN u m ericModelValidator/DateModelValidatorオブジェクトを含むModelValidatorセットを直接返します.ここで数値とみなされるデータ型には、byte、sbyte、short、ushort、int、uint、long、ulong、float、double、decimalなどがある. 1: public class ClientDataTypeModelValidatorProvider : ModelValidatorProvider
2: {
3: public ClientDataTypeModelValidatorProvider();
4: public override IEnumerable GetValidators(ModelMetadata metadata, ControllerContext context);
5: }
四、DataErrorInfoModelValidatorProvider
2つの特定のDataErrorInfoModelValidator、すなわちDataErrorInfoClassModelValidatorおよびDataErrorInfoPropertyModelValidatorは、最終的には、次のように定義されたDataErrorInfoModelValidatorProviderによって提供される.GetValidatorsの特定のインプリメンテーションでは、ModelタイプがIDataErrorInfoインタフェースを実装している場合、作成したModelメタデータとControllerコンテキストに基づいて、戻ってきたModelValidtorセットにDataErrorInfoClassModelValidatorオブジェクトが作成されます.属性ベースのModelメタデータの場合、コンテナタイプがIDataErrorInfoインタフェースを実装している場合、このメソッドが返すModelValidtorセットには、指定したModelメタデータとControllerコンテキストに基づいて作成されたDataErrorInfoPropertyModelValidatorオブジェクトも含まれます. 1: public class DataErrorInfoModelValidatorProvider : ModelValidatorProvider
2: {
3: public DataErrorInfoModelValidatorProvider();
4: public override IEnumerable GetValidators(ModelMetadata metadata, ControllerContext context);
5: }
読者がDataErrorInfoModelValidatorの検証ルールをよりよく理解し、DataErrorInfoPropertyModelValidatorでの提供メカニズムを定義するために、簡単な例を示します.Visual Studioを通過するASP.NET MVCプロジェクトテンプレートによって作成された空のWebアプリケーションでは、IDataErrorInfoインタフェースを実装するContactタイプを定義します. 1: public class Contact: IDataErrorInfo
2: {
3: public string Error
4: {
5: get { return " !";}
6: }
7: public string this[string columnName]
8: {
9: get
10: {
11: switch (columnName)
12: {
13: case "Name" : return " !";
14: case "PhoneNo" : return " !";
15: case "EmailAdderss" : return " !";
16: default : return null;
17: }
18: }
19: }
20: public string Name { get; set; }
21: public string PhoneNo { get; set; }
22: public string EmailAdderss { get; set; }
23: }
次に、次のデフォルトのHomeControllerクラスを作成します.ActionメソッドIndexでは、DataErrorInfoModelValidatorProviderを使用してContactタイプの極度属性のModelメタデータに基づいてModelValidatorリストを作成し、このリストの各特定のModelValidatorを使用してContactオブジェクトを検証し、ModelValidatorのタイプと検証結果としてModelValidationResultオブジェクトのErrorMessage属性を提示します. 1: public class HomeController : Controller
2: {
3: public void Index()
4: {
5: Contact contact = new Contact();
6: ModelValidatorProvider validatorProvider = new DataErrorInfoModelValidatorProvider();
7: foreach (var validator in GetValidators(contact, validatorProvider))
8: {
9: var validationResults = validator.Validate(contact);
10: if (validationResults.Any())
11: {
12: Response.Write(validator.GetType().Name + "
");
13: }
14: foreach(var validationResult in validationResults)
15: {
16: Response.Write(validationResult.Message + "
");
17: }
18: }
19: }
20:
21: private IEnumerable GetValidators(Contact contact, ModelValidatorProvider validatorProvider)
22: {
23: ModelMetadata metadata = ModelMetadataProviders.Current.GetMetadataForType(() => contact, typeof(Contact));
24: foreach (var validator in validatorProvider.GetValidators(metadata, ControllerContext))
25: {
26: yield return validator;
27: }
28:
29: foreach (var propertyMetadata in metadata.Properties)
30: {
31: foreach (var validator in validatorProvider.GetValidators(propertyMetadata, ControllerContext))
32: {
33: yield return validator;
34: }
35: }
36: }
37: }
上記のプログラムが実行されるとブラウザで次のような出力結果が表示され、ContactタイプのModelメタデータに対してDataErrorInfoClassModelValidatorが作成され、そのプロパティのModelメタデータに対してDataErrorInfoPropertyModelValidatorオブジェクトが作成されていることがわかります.前者はContactオブジェクト自体を検証し、Error属性を検証結果のエラーメッセージとする.後者は、対応する属性について検証を実施し、検証結果のエラーメッセージは、属性名をインデックスとする値に由来する. 1: DataErrorInfoClassModelValidator
2: !
3: DataErrorInfoPropertyModelValidator
4: !
5: DataErrorInfoPropertyModelValidator
6: !
7: DataErrorInfoPropertyModelValidator
8: !
ASP.NET MVC ModelValidatorを核心とするModel検証体系:ModelValidator ASP.NET MVC ModelValidatorを核心とするModel検証体系:ModelValidatorProvider ASP.NET MVC ModelValidatorを核心とするModel検証体系:ModelValidatorProviders
1: public abstract class ModelValidatorProvider
2: {
3: public abstract IEnumerable GetValidators(ModelMetadata metadata, ModelBindingExecutionContext context);
4: }
前述したデータ寸法特性検証方式のDataAnnotationsModelValidatorに対応するModelValidatorProviderタイプは、DataAnnotationsModelValidatorProviderです.次のコード・セグメントに示すように、DataAnnotationsModelValidatorProviderは、別の抽象タイプAssociatedValidatorProviderから継承されます.
1: public class DataAnnotationsModelValidatorProvider : AssociatedValidatorProvider
2: {
3: //
4: public DataAnnotationsModelValidatorProvider();
5: protected override IEnumerable GetValidators(ModelMetadata metadata, ControllerContext context,IEnumerable attributes);
6: }
タイプ名AssociatedValidatorProviderの「Association(Association)」とは、実際には、Modelメタデータから取得された検証ルールを定義するためのプロパティのリストに基づいて、対応するModelValidatorを提供する関連プロパティのリストを表します.次のコード・セグメントに示すように、A s s o c i atedValidatorProviderは、インタフェースICustomType Descriptorを実装するタイプの指定されたタイプの記述オブジェクトを取得するための保護されたダミー・メソッドGetType Descriptorを定義します.解析された関連特性は最終的に抽象的なGetValidatorsメソッドに伝達され、ModelValidatorの提供が実現され、DataAnnotationsModelValidatorProviderは、対応するDataAnnotationsModelValidatorリストを作成するためにこの方法を実現した. 1: public abstract class AssociatedValidatorProvider : ModelValidatorProvider
2: {
3: protected virtual ICustomTypeDescriptor GetTypeDescriptor(Type type);
4: public sealed override IEnumerable GetValidators(ModelMetadata metadata, ControllerContext context);
5: protected abstract IEnumerable GetValidators(ModelMetadata metadata, ControllerContext context, IEnumerable attributes);
6: }
書き換えられたGetValidatorsメソッドでは、現在のModelメタデータがある属性に基づいている(コンテナタイプを表すContainerTypeはNullではなく属性名を持つ)場合、GetType Descriptorメソッドを呼び出してコンテナタイプ記述オブジェクトを取得し、さらに属性クラスタイプに応じて属性を記述するためのPropertyDescriptorオブジェクトを得る.最終的に、記述オブジェクトによって、対応する属性に適用されるすべての特性が得られ、抽象メソッドGetValidatorsを呼び出して、属性ベースのModelValidatorリストが返される.非属性Modelメタデータの場合、GetTypeDescriptorメソッドを直接呼び出してModelタイプ記述オブジェクトを取得し、さらにModelタイプに適用されるすべての特性を取得し、抽象メソッドGetValidatorsに転送してModelタイプに対するModelValidatorの提供を実現する.三、ClientDataTypeModelValidatorProvider
数値および日付タイプのクライアントに対して検証されたNumericModelValidatorおよびDateModelValidatorは、最終的には、次のように定義されたClientDataTypeModelValidatorProviderによって提供されます.GetValidatorsメソッドでは、指定したModelメタデータに基づいて数値タイプ/DateTimeタイプに属するかどうかを判断します.そうであれば、単一のN u m ericModelValidator/DateModelValidatorオブジェクトを含むModelValidatorセットを直接返します.ここで数値とみなされるデータ型には、byte、sbyte、short、ushort、int、uint、long、ulong、float、double、decimalなどがある. 1: public class ClientDataTypeModelValidatorProvider : ModelValidatorProvider
2: {
3: public ClientDataTypeModelValidatorProvider();
4: public override IEnumerable GetValidators(ModelMetadata metadata, ControllerContext context);
5: }
四、DataErrorInfoModelValidatorProvider
2つの特定のDataErrorInfoModelValidator、すなわちDataErrorInfoClassModelValidatorおよびDataErrorInfoPropertyModelValidatorは、最終的には、次のように定義されたDataErrorInfoModelValidatorProviderによって提供される.GetValidatorsの特定のインプリメンテーションでは、ModelタイプがIDataErrorInfoインタフェースを実装している場合、作成したModelメタデータとControllerコンテキストに基づいて、戻ってきたModelValidtorセットにDataErrorInfoClassModelValidatorオブジェクトが作成されます.属性ベースのModelメタデータの場合、コンテナタイプがIDataErrorInfoインタフェースを実装している場合、このメソッドが返すModelValidtorセットには、指定したModelメタデータとControllerコンテキストに基づいて作成されたDataErrorInfoPropertyModelValidatorオブジェクトも含まれます. 1: public class DataErrorInfoModelValidatorProvider : ModelValidatorProvider
2: {
3: public DataErrorInfoModelValidatorProvider();
4: public override IEnumerable GetValidators(ModelMetadata metadata, ControllerContext context);
5: }
読者がDataErrorInfoModelValidatorの検証ルールをよりよく理解し、DataErrorInfoPropertyModelValidatorでの提供メカニズムを定義するために、簡単な例を示します.Visual Studioを通過するASP.NET MVCプロジェクトテンプレートによって作成された空のWebアプリケーションでは、IDataErrorInfoインタフェースを実装するContactタイプを定義します. 1: public class Contact: IDataErrorInfo
2: {
3: public string Error
4: {
5: get { return " !";}
6: }
7: public string this[string columnName]
8: {
9: get
10: {
11: switch (columnName)
12: {
13: case "Name" : return " !";
14: case "PhoneNo" : return " !";
15: case "EmailAdderss" : return " !";
16: default : return null;
17: }
18: }
19: }
20: public string Name { get; set; }
21: public string PhoneNo { get; set; }
22: public string EmailAdderss { get; set; }
23: }
次に、次のデフォルトのHomeControllerクラスを作成します.ActionメソッドIndexでは、DataErrorInfoModelValidatorProviderを使用してContactタイプの極度属性のModelメタデータに基づいてModelValidatorリストを作成し、このリストの各特定のModelValidatorを使用してContactオブジェクトを検証し、ModelValidatorのタイプと検証結果としてModelValidationResultオブジェクトのErrorMessage属性を提示します. 1: public class HomeController : Controller
2: {
3: public void Index()
4: {
5: Contact contact = new Contact();
6: ModelValidatorProvider validatorProvider = new DataErrorInfoModelValidatorProvider();
7: foreach (var validator in GetValidators(contact, validatorProvider))
8: {
9: var validationResults = validator.Validate(contact);
10: if (validationResults.Any())
11: {
12: Response.Write(validator.GetType().Name + "
");
13: }
14: foreach(var validationResult in validationResults)
15: {
16: Response.Write(validationResult.Message + "
");
17: }
18: }
19: }
20:
21: private IEnumerable GetValidators(Contact contact, ModelValidatorProvider validatorProvider)
22: {
23: ModelMetadata metadata = ModelMetadataProviders.Current.GetMetadataForType(() => contact, typeof(Contact));
24: foreach (var validator in validatorProvider.GetValidators(metadata, ControllerContext))
25: {
26: yield return validator;
27: }
28:
29: foreach (var propertyMetadata in metadata.Properties)
30: {
31: foreach (var validator in validatorProvider.GetValidators(propertyMetadata, ControllerContext))
32: {
33: yield return validator;
34: }
35: }
36: }
37: }
上記のプログラムが実行されるとブラウザで次のような出力結果が表示され、ContactタイプのModelメタデータに対してDataErrorInfoClassModelValidatorが作成され、そのプロパティのModelメタデータに対してDataErrorInfoPropertyModelValidatorオブジェクトが作成されていることがわかります.前者はContactオブジェクト自体を検証し、Error属性を検証結果のエラーメッセージとする.後者は、対応する属性について検証を実施し、検証結果のエラーメッセージは、属性名をインデックスとする値に由来する. 1: DataErrorInfoClassModelValidator
2: !
3: DataErrorInfoPropertyModelValidator
4: !
5: DataErrorInfoPropertyModelValidator
6: !
7: DataErrorInfoPropertyModelValidator
8: !
ASP.NET MVC ModelValidatorを核心とするModel検証体系:ModelValidator ASP.NET MVC ModelValidatorを核心とするModel検証体系:ModelValidatorProvider ASP.NET MVC ModelValidatorを核心とするModel検証体系:ModelValidatorProviders
1: public class ClientDataTypeModelValidatorProvider : ModelValidatorProvider
2: {
3: public ClientDataTypeModelValidatorProvider();
4: public override IEnumerable GetValidators(ModelMetadata metadata, ControllerContext context);
5: }
2つの特定のDataErrorInfoModelValidator、すなわちDataErrorInfoClassModelValidatorおよびDataErrorInfoPropertyModelValidatorは、最終的には、次のように定義されたDataErrorInfoModelValidatorProviderによって提供される.GetValidatorsの特定のインプリメンテーションでは、ModelタイプがIDataErrorInfoインタフェースを実装している場合、作成したModelメタデータとControllerコンテキストに基づいて、戻ってきたModelValidtorセットにDataErrorInfoClassModelValidatorオブジェクトが作成されます.属性ベースのModelメタデータの場合、コンテナタイプがIDataErrorInfoインタフェースを実装している場合、このメソッドが返すModelValidtorセットには、指定したModelメタデータとControllerコンテキストに基づいて作成されたDataErrorInfoPropertyModelValidatorオブジェクトも含まれます.
1: public class DataErrorInfoModelValidatorProvider : ModelValidatorProvider
2: {
3: public DataErrorInfoModelValidatorProvider();
4: public override IEnumerable GetValidators(ModelMetadata metadata, ControllerContext context);
5: }
読者がDataErrorInfoModelValidatorの検証ルールをよりよく理解し、DataErrorInfoPropertyModelValidatorでの提供メカニズムを定義するために、簡単な例を示します.Visual Studioを通過するASP.NET MVCプロジェクトテンプレートによって作成された空のWebアプリケーションでは、IDataErrorInfoインタフェースを実装するContactタイプを定義します. 1: public class Contact: IDataErrorInfo
2: {
3: public string Error
4: {
5: get { return " !";}
6: }
7: public string this[string columnName]
8: {
9: get
10: {
11: switch (columnName)
12: {
13: case "Name" : return " !";
14: case "PhoneNo" : return " !";
15: case "EmailAdderss" : return " !";
16: default : return null;
17: }
18: }
19: }
20: public string Name { get; set; }
21: public string PhoneNo { get; set; }
22: public string EmailAdderss { get; set; }
23: }
次に、次のデフォルトのHomeControllerクラスを作成します.ActionメソッドIndexでは、DataErrorInfoModelValidatorProviderを使用してContactタイプの極度属性のModelメタデータに基づいてModelValidatorリストを作成し、このリストの各特定のModelValidatorを使用してContactオブジェクトを検証し、ModelValidatorのタイプと検証結果としてModelValidationResultオブジェクトのErrorMessage属性を提示します. 1: public class HomeController : Controller
2: {
3: public void Index()
4: {
5: Contact contact = new Contact();
6: ModelValidatorProvider validatorProvider = new DataErrorInfoModelValidatorProvider();
7: foreach (var validator in GetValidators(contact, validatorProvider))
8: {
9: var validationResults = validator.Validate(contact);
10: if (validationResults.Any())
11: {
12: Response.Write(validator.GetType().Name + "
");
13: }
14: foreach(var validationResult in validationResults)
15: {
16: Response.Write(validationResult.Message + "
");
17: }
18: }
19: }
20:
21: private IEnumerable GetValidators(Contact contact, ModelValidatorProvider validatorProvider)
22: {
23: ModelMetadata metadata = ModelMetadataProviders.Current.GetMetadataForType(() => contact, typeof(Contact));
24: foreach (var validator in validatorProvider.GetValidators(metadata, ControllerContext))
25: {
26: yield return validator;
27: }
28:
29: foreach (var propertyMetadata in metadata.Properties)
30: {
31: foreach (var validator in validatorProvider.GetValidators(propertyMetadata, ControllerContext))
32: {
33: yield return validator;
34: }
35: }
36: }
37: }
上記のプログラムが実行されるとブラウザで次のような出力結果が表示され、ContactタイプのModelメタデータに対してDataErrorInfoClassModelValidatorが作成され、そのプロパティのModelメタデータに対してDataErrorInfoPropertyModelValidatorオブジェクトが作成されていることがわかります.前者はContactオブジェクト自体を検証し、Error属性を検証結果のエラーメッセージとする.後者は、対応する属性について検証を実施し、検証結果のエラーメッセージは、属性名をインデックスとする値に由来する. 1: DataErrorInfoClassModelValidator
2: !
3: DataErrorInfoPropertyModelValidator
4: !
5: DataErrorInfoPropertyModelValidator
6: !
7: DataErrorInfoPropertyModelValidator
8: !
ASP.NET MVC ModelValidatorを核心とするModel検証体系:ModelValidator ASP.NET MVC ModelValidatorを核心とするModel検証体系:ModelValidatorProvider ASP.NET MVC ModelValidatorを核心とするModel検証体系:ModelValidatorProviders