27

ASP.NET MVC 2でデータ注釈検証を広範囲に使用しています。この新機能は、クライアント側の検証とサーバー側の検証の両方を1か所で定義できるようになったため、大幅な時間の節約になりました。ただし、詳細なテストを行っているときに、データアノテーションの検証のみに依存している場合、サーバー側の検証をバイパスするのは非常に簡単であることに気付きました。たとえば、プロパティに[Required]属性の注釈を付けて必須フィールドを定義し、その必須フィールドのテキストボックスをフォームに配置した場合、ユーザーはDOMからテキストボックスを削除するだけで済みます(Firebugを使用して簡単に実行できます)。これで、コントローラー内のModelBinding中に、そのプロパティでデータ注釈の検証がトリガーされなくなります。「必要な」検証がトリガーされることを確認するには、

検証に関する皆さんの推奨事項は何ですか?データ注釈の検証は十分ですか?または、すべての状況で検証がトリガーされるように、検証を繰り返す必要がありますか?

フォローアップコメント: 以下の回答に基づくと、モデルバインダーとデータアノテーションの検証だけに頼ることはできないようです。追加のサーバー側検証が必要であると結論付けているので、データアノテーションで定義されているものに基づいてサービスレイヤーが検証をトリガーする簡単な方法はありますか?これにより、両方の単語の長所が得られるようです...検証コードを繰り返す必要はありませんが、Model Binderがトリガーしなくても、検証が確実に実行されるようにします。

このフォローアップコメントは、元の質問とは異なる質問になるため、別の質問として投稿します。

4

5 に答える 5

18

サーバーの検証を優先し、これが常にフォールバックであることを確認することを選択する必要があるセキュリティについては、警戒する必要があると思います。サーバーの検証は、クライアントの検証なしで機能するはずです。クライアントの検証は UX のためのものであり、設計にとって最も重要であり、セキュリティに次ぐものです。これを念頭に置いて、検証を繰り返していることに気付くでしょう。多くの場合、目標は、サーバーとクライアントでの検証に必要な作業を減らすために、サーバーとクライアントの検証を可能な限り統合できるようにアプリを設計しようとすることです。ただし、両方を実行する必要がありますのでご安心ください。

クライアントの検証を (DOM 操作によって) バイパスすることがサーバーの検証を回避している場合 (これはあなたが示しているようです)、このインスタンスのサーバーの検証が適切に採用されていない可能性があります。コントローラー アクションまたはサービス レイヤーでサーバー検証を再度呼び出す必要があります。あなたが説明するシナリオは、サーバーの検証を無効にするべきではありません。

説明したシナリオでは、DataAnnotation 属性メソッドで十分です。フォームを送信するときにもサーバー検証が呼び出されるようにするには、いくつかのコードを変更するだけでよいようです。

于 2009-10-13T08:00:07.837 に答える
7

xValをDataAnnotationsとペアにして、検証の目的でエンティティタイプのパラメーターをチェックする独自のアクションフィルターを作成しました。したがって、ポストバックで一部のフィールドが欠落している場合、このバリデーターはModelStateディクショナリを埋めるため、モデルが無効になります。

前提条件:

  • 私のエンティティ/モデルオブジェクトはすべて、メソッドIObjectValidatorを宣言するインターフェイスを実装していますValidate()
  • 私の属性クラスはValidateBusinessObjectAttribute
  • xVal検証ライブラリ

アクションフィルターコード:

public void OnActionExecuting(ActionExecutingContext filterContext)
{
    IEnumerable<KeyValuePair<string, object>> parameters = filterContext.ActionParameters.Where<KeyValuePair<string, object>>(p => p.Value.GetType().Equals(this.ObjectType ?? p.Value.GetType()) && p.Value is IObjectValidator);
    foreach (KeyValuePair<string, object> param in parameters)
    {
        object value;
        if ((value = param.Value) != null)
        {
            IEnumerable<ErrorInfo> errors = ((IObjectValidator)value).Validate();
            if (errors.Any())
            {
                new RulesException(errors).AddModelStateErrors(filterContext.Controller.ViewData.ModelState, param.Key);
            }
        }
    }
}

私のコントローラーアクションは次のように定義されます:

[ValidateBusinessObject]
public ActionResult Register(User user, Company company, RegistrationData registrationData)
{
    if (!this.ModelState.IsValid)
    {
        return View();
    }
    ...
}
于 2009-10-13T13:32:49.983 に答える
2

DataAnnotationは確かに十分ではありません。ドメインモデルへの呼び出しを事前に検証して、エラーレポートを改善し、できるだけ早く失敗するようにするためにも、これを幅広く使用しています。

ただし、DataAnnotationモデルを自分で微調整して、[必須]のプロパティを投稿する必要があることを確認できます。(本日遅くにコードをフォローアップします)。

UPDATE DataAnnotations Model Binderのソースを取得し、DataAnnotationsModelBinder.csでこの行を見つけます

// Only bind properties that are part of the request
if (bindingContext.ValueProvider.DoesAnyKeyHavePrefix(fullPropertyKey)) {

に変更します

// Only bind properties that are part of the request
bool contextHasKey = bindingContext.ValueProvider.DoesAnyKeyHavePrefix(fullPropertyKey);
bool isRequired = GetValidationAttributes(propertyDescriptor).OfType<RequiredAttribute>().Count() > 0;
if (contextHasKey || (!contextHasKey && isRequired)) {
于 2009-10-13T06:44:40.313 に答える
2

データ注釈を使用したcodeProjectサーバー側入力検証を参照してください。

入力の検証は、ASP.NET MVC のクライアント側で自動的に行うか、ルールに対してモデルを明示的に検証することができます。このヒントでは、ASP.NET アプリケーションのサーバー側または WPF アプリケーションのリポジトリ コード内で手動で行う方法について説明します。

        // Use the ValidationContext to validate the Product model against the product data annotations
        // before saving it to the database
        var validationContext = new ValidationContext(productViewModel, serviceProvider: null, items:null);
        var validationResults = new List<ValidationResult>();

        var isValid = Validator.TryValidateObject(productViewModel, validationContext,validationResults, true);
于 2012-12-06T21:04:42.087 に答える
2

xVal の DataAnnotationsRuleProvider と Microsoft の DataAnnotationsModelBinder (および Martijn のコメント) の両方からパターンをコピーして、MVC 1.0 用の独自の ValidationService を作成しました。サービス インターフェイスは次のとおりです。

public interface IValidationService
{
    void Validate(object instance);

    IEnumerable<ErrorInfo> GetErrors(object instance);
}

public abstract class BaseValidationService : IValidationService
{
    public void Validate(object instance)
    {
        var errors = GetErrors(instance);

        if (errors.Any())
            throw new RulesException(errors);
    }

    public abstract IEnumerable<ErrorInfo> GetErrors(object instance);
}

このサービスは、受け取ったオブジェクト インスタンスのプロパティ ツリーをたどり、各プロパティで検出した検証属性を実際に実行する検証ランナーであり、属性が有効でない場合に ErrorInfo オブジェクトのリストを作成します。(ソース全体を投稿したいのですが、それはクライアント向けに書かれたものであり、そうする権限があるかどうかはまだわかりません。)

その後、検証のためにモデル バインダーのみに依存するのではなく、準備ができたら、コントローラーやビジネス ロジック サービスで検証を明示的に呼び出すことができます。

他にも注意すべき落とし穴がいくつかあります。

  • データ注釈のデフォルトの DataTypeAttribute は、実際にはデータ型の検証を行わないため、実際に xVal 正規表現 (またはその他のもの) を使用してサーバー側のデータ型検証を実行する新しい属性を記述する必要があります。
  • xVal は、クライアント側の検証を作成するためにプロパティをウォークしないため、より堅牢なクライアント側の検証を取得するためにいくつかの変更を加えることができます。

許可されて時間があれば、より多くのソースを利用できるようにします...

于 2009-11-04T16:04:22.007 に答える