9

私のページには、特定の状況下で非表示になっている特定のパネルがあります。

たとえば、「請求先住所」と「配送先住所」があり、「ShippingSameAsBilling」チェックボックスがオンになっている場合、「配送先住所」を検証したくありません。

これを実現するために、ASP.NET MVC 2 (プレビュー 1)の新しいDataAnnotations 機能を使用しようとしています。

「配送先住所」が表示されていないときに検証を防止する必要があり、これを実現する方法を見つける必要があります。jquery を使用するのではなく、主にサーバー側で話しています。

どうすればこれを達成できますか?カスタム モデル バインディングに関連するいくつかのアイデアがありましたが、現在の最善の解決策を以下に示します。この方法に関するフィードバックはありますか?

4

7 に答える 7

6

CheckoutModel については、次のアプローチを使用しています (ほとんどのフィールドは非表示になっています)。

[ModelBinder(typeof(CheckoutModelBinder))]
public class CheckoutModel : ShoppingCartModel
{        
    public Address BillingAddress { get; set; }
    public Address ShippingAddress { get; set; }
    public bool ShipToBillingAddress { get; set; }
}

public class Address
{
    [Required(ErrorMessage = "Email is required")]
    public string Email { get; set; }

    [Required(ErrorMessage = "First name is required")]
    public string FirstName { get; set; }

    [Required()]
    public string LastName { get; set; }

    [Required()]
    public string Address1 { get; set; }
}

カスタム モデル バインダーは、「ShippingAddress」で始まるフィールドの ModelState エラーが見つかった場合、すべて削除します。その後、'TryUpdateModel()' は true を返します。

    public class CheckoutModelBinder : DefaultModelBinder
    {
        protected override void OnModelUpdated(ControllerContext controllerContext,
                                               ModelBindingContext bindingContext) {

            base.OnModelUpdated(controllerContext, bindingContext);

            var model = (CheckoutModel)bindingContext.Model;

            // if user specified Shipping and Billing are the same then 
            // remove all ModelState errors for ShippingAddress
            if (model.ShipToBillingAddress)
            {
                var keys = bindingContext.ModelState.Where(x => x.Key.StartsWith("ShippingAddress")).Select(x => x.Key).ToList();
                foreach (var key in keys)
                {
                    bindingContext.ModelState.Remove(key);
                }
            }
        }    
    }

より良い解決策はありますか?

于 2009-08-30T03:56:07.427 に答える
3

http://bradwilson.typepad.com/blog/2009/04/dataannotations-and-aspnet-mvc.html

于 2009-08-30T04:00:48.477 に答える
2

検証したくないフィールドがアクションに投稿されていないことを確認してください。実際に投稿されたフィールドのみを検証します。

編集:(質問者による)

この動作は MVC2 RC2 で変更されました。

既定の検証システムはモデル全体を検証する ASP.NET MVC 1.0 および RC 2 より前の ASP.NET MVC 2 のプレビューの既定の検証システムは、サーバーにポストされたモデル プロパティのみを検証しました。ASP.NET MVC 2 では、新しい値がポストされたかどうかに関係なく、モデルが検証されるときにすべてのモデル プロパティが検証されるという新しい動作が行われます。ASP.NET MVC 1.0 の動作に依存するアプリケーションでは、変更が必要になる場合があります。この変更の詳細については、Brad Wilson のブログの「ASP.NET MVC での入力の検証とモデルの検証」のエントリを参照してください。

于 2009-10-29T00:04:05.863 に答える
2

私はあなたの苦境を見ることができます。特定のモデルオブジェクトの複数のプロパティ、またはオブジェクトグラフ内の異なるモデルオブジェクトの多くのプロパティに適用される可能性のある複雑な検証ルールに関しても、他の検証ソリューションを探しています (リンクされたオブジェクトを検証するのに十分な運がない場合)このような)。

インターフェイスの制限は、IDataErrorInfoどのプロパティにもエラーがない場合にのみ、モデル オブジェクトが有効な状態を満たすことです。つまり、有効なオブジェクトとは、そのすべてのプロパティも有効なオブジェクトです。ただし、プロパティA、B、およびCが有効な場合、オブジェクト全体が有効であるという状況が発生する可能性があります..プロパティAが有効ではなく、BCが有効な場合、オブジェクトは有効性を満たします。IDataErrorInfoこの条件/ルールをインターフェイス/DataAnnotations属性で説明する方法がありません。

だから私はこのデリゲートアプローチを見つけました。MVC の有用な進歩の多くは、この記事を書いている時点では存在していませんでしたが、中心となる概念は役立つはずです。属性を使用してオブジェクトの検証条件を定義するのではなく、より複雑な要件を検証するデリゲート関数を作成します。それらは委任されているため、再利用できます。確かに手間はかかりますが、デリゲートを使用すると、検証ルール コードを 1 回記述し、すべての検証ルールを 1 つの場所 (おそらくサービス レイヤー) に保存し、(クールビット) MVC 2DefaultModelBinderを使用して呼び出すことさえできるはずです。検証は自動的に行われます (コントローラ アクションを大量にチェックする必要はありません。Scott のブログでDataAnnotations.「厳密に型指定された UI ヘルパー」見出しの前の最後の段落)!

Func<T>上記の記事で提案されているアプローチを、 orのような匿名デリゲートを使用して少し強化できると確信しています。Predicate<T>また、検証ルールのカスタム コード ブロックを作成すると、クロス プロパティ条件が有効になります (たとえば、ShippingSameAsBillingプロパティがtrue の場合、配送先住所などのその他のルールを無視できます)。

DataAnnotationsは、オブジェクトの単純な検証ルールを非常に簡単にするのに役立ちます。コードはほとんどありません。しかし、要件が発展するにつれて、より複雑なルールを検証する必要があります。MVC2 モデル バインダーの新しい仮想メソッドは、今後の検証の発明を MVC フレームワークに統合する方法を提供し続けるはずです。

于 2009-10-28T20:41:32.167 に答える
1

より複雑なケースでは、単純なDataAnnotationsから次のように移動しました。訪問者による検証と拡張メソッド

DataAnnotationsを利用したい場合は、次のようなものを置き換えます。

public IEnumerable<ErrorInfo> BrokenRules (Payment payment)
{   
    // snip... 
    if (string.IsNullOrEmpty (payment.CCName))
    {
      yield return new ErrorInfo ("CCName", "Credit card name is required");
    }
}

DataAnnotations(私はatmを持っていません)を介して名前でプロパティを検証するメソッドを使用します。

于 2009-11-10T19:30:14.150 に答える
1

送信されたキーのみを検証する部分モデル バインダーを作成しました。セキュリティ上の理由から (これをさらに一歩進めた場合)、モデルから除外できるフィールドをマークするデータ注釈属性を作成します。次に、OnModelUpdated はフィールド属性をチェックして、望ましくないアンダーポストが発生していないことを確認します。

public class PartialModelBinder : DefaultModelBinder
{
    protected override void OnModelUpdated(ControllerContext controllerContext, 
        ModelBindingContext bindingContext)
    {
        // default model binding to get errors
        base.OnModelUpdated(controllerContext, bindingContext);

        // remove errors from filds not posted
        // TODO: include request files
        var postedKeys = controllerContext.HttpContext.Request.Form.AllKeys;
        var unpostedKeysWithErrors = bindingContext.ModelState
            .Where(i => !postedKeys.Contains(i.Key))
            .Select(i=> i.Key).ToList();
        foreach (var key in unpostedKeysWithErrors)
        {
            bindingContext.ModelState.Remove(key);
        }
    }    
}
于 2010-10-19T19:39:01.650 に答える
0

これはDataAnnotationsとは関係ありませんが、 Fluent Validationプロジェクトを見たことがありますか? これにより、検証をきめ細かく制御できます。オブジェクト間の検証がある場合は、2 つのオブジェクトの集約オブジェクトを使用して作業を進めることができます。

また、MVC を念頭に置いて構築されているようですが、独自の「ランタイム」も備えているため、他の .NET アプリケーションでも使用できます。これは私の本のもう 1 つのボーナスです。

于 2009-11-10T18:38:49.933 に答える