明らかに、実行時にDataAnnotation属性をオブジェクトプロパティに動的にアタッチして、動的検証を実現することが可能です。
誰かがこれに関するコードサンプルを提供できますか?
MVCには、独自のModelValidatorProviderを提供するためのフックがあります。デフォルトでは、MVC 2は、検証にSystem.DataAnnotations.ComponentModel.ValidationAttribute属性を使用できるDataAnnotationsModelValidatorProviderと呼ばれるModelValidatorProviderのサブクラスを使用します。
DataAnnotationsModelValidatorProviderは、リフレクションを使用してすべてのValidationAttributesを検索し、コレクションをループしてモデルを検証します。 GetValidatorsというメソッドをオーバーライドし、選択したソースから独自の属性を挿入するだけです。私はこの手法を使用して規則の検証を行い、DataType.Email属性を持つプロパティは常に正規表現を介して渡され、この手法を使用してデータベースから情報を取得し、「非パワー」ユーザーに対してより制限的な検証を適用します。
次の例では、「常にFirstNameプロパティを必須にする」と単純に述べています。
public class CustomMetadataValidationProvider : DataAnnotationsModelValidatorProvider
{
protected override IEnumerable<ModelValidator> GetValidators(ModelMetadata metadata, ControllerContext context, IEnumerable<Attribute> attributes)
{
//go to db if you want
//var repository = ((MyBaseController) context.Controller).RepositorySomething;
//find user if you need it
var user = context.HttpContext.User;
if (!string.IsNullOrWhiteSpace(metadata.PropertyName) && metadata.PropertyName == "FirstName")
attributes = new List<Attribute>() {new RequiredAttribute()};
return base.GetValidators(metadata, context, attributes);
}
}
あなたがしなければならないのはあなたのGlobal.asax.csファイルにプロバイダーを登録することです:
protected void Application_Start()
{
ModelValidatorProviders.Providers.Add(new CustomMetadataValidationProvider());
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
}
最終結果:
このモデルで:
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime Birthday { get; set; }
}
Global.asaxで、新しいモデルを追加する前にModelValidatorProvidersをクリアする必要があります。それ以外の場合は、すべての注釈が2回追加され、「目立たないクライアント検証ルールの検証タイプ名は一意である必要があります。」-エラーが発生します。
protected void Application_Start()
{
ModelValidatorProviders.Providers.Clear();
ModelValidatorProviders.Providers.Add(new CustomMetadataValidationProvider());
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
}
オーバーライドされたMetadataValidationProvider
でカスタムGetValidators
を使用するアプローチには、いくつかの弱点があります。
DisplayAttribute
などの一部の属性は検証に関連していないため、検証段階でそれらを追加しても機能しません。動的に適用されるデータ注釈を一貫して機能させたい場合は、DataAnnotationsModelMetadataProvider
とDataAnnotationsModelValidatorProvider
をサブクラス化できます。これを行った後、replaceアプリケーションの起動時にModelMetadataProviders.Current
およびModelValidatorProviders.Providers
を介してフレームワークのものを置き換えます。 (Application_Start
でそれを行うことができます。)
組み込みプロバイダーをサブクラス化する場合、独自の属性を適用するための体系的で将来性のある方法は、GetTypeDescriptor
をオーバーライドすることです。私はこれを成功させましたが、ICustomTypeDescriptor
とPropertyDescriptor
の実装を作成する必要があり、多くのコードと時間が必要でした。