4

asp.net サイトで説明されているように、IDataErrorInfo インターフェイスを使用しようとしている単純な住所入力アプリがあります。

独立して検証できるアイテムには最適ですが、一部のアイテムが他のアイテムに依存している場合はうまく機能しません。たとえば、郵便番号の検証は国によって異なります。

    private string _PostalCode;
    public string PostalCode
    {
        get
        {
            return _PostalCode;
        }
        set
        {
            switch (_Country)
            {
                case Countries.USA:
                    if (!Regex.IsMatch(value, @"^[0-9]{5}$"))
                        _errors.Add("PostalCode", "Invalid Zip Code");
                    break;
                case Countries.Canada:
                    if (!Regex.IsMatch(value, @"^([a-z][0-9][a-z]) ?([0-9][a-z][0-9])$", RegexOptions.IgnoreCase))
                        _errors.Add("PostalCode", "Invalid postal Code");
                    break;
                default:
                    throw new ArgumentException("Unknown Country");
            }
            _PostalCode = value;
        }
    }

そのため、国が設定された後にのみ郵便番号を検証できますが、その順序を制御する方法はないようです.

IDataErrorInfo のエラー文字列を使用できますが、フィールドの横にある Html.ValidationMessage には表示されません。

4

3 に答える 3

5

より複雑なビジネス ルールの検証では、型の検証ではなく、サービス レイヤーなどの設計パターンを実装する方がよい場合があります。ModelState を確認し、ロジックに基づいてエラーを追加できます。

ここで Rob Conroy のパターンの例を見ることができます

http://www.asp.net/learn/mvc/tutorial-29-cs.aspx

データ注釈に関するこの記事も役に立ちます。

http://www.asp.net/learn/mvc/tutorial-39-cs.aspx

お役に立てれば。

于 2009-10-02T20:06:37.993 に答える
1

単純なデータ注釈モデルを超えた、より複雑な検証のために私が見つけた最良のソリューションを次に示します。

IDataErrorInfo実装しようとして、実装する方法が 2 つしか作成されていないことを確認したのは、私だけではないと確信しています。ちょっと待ってください。そこに行って、すべてのために独自のカスタム ルーチンをゼロから作成する必要がありますか? また、検証するモデル レベルのものがある場合はどうでしょうか。IDataErrorInfo 実装内からこのようことをしたくない場合を除き、それを使用することに決めたときは、自分でいるようです。

私もたまたま質問者様と全く同じ症状でした。米国の郵便番号を検証したかったのですが、国が米国として選択された場合に限りました。明らかに、モデル レベルのデータ アノテーションは、郵便番号がエラーとして赤で強調表示される原因とならないため、適切ではありません。[クラス レベルのデータ アノテーションの良い例は、PropertiesMustMatchAttribute クラスの MVC 2 サンプル プロジェクトにあります]。

解決策は非常に簡単です:

まず、global.asax にモデルバインダーを登録する必要があります。必要に応じてクラス レベルの [属性] としてこれを行うこともできますが、global.asax に登録する方がより柔軟であることがわかります。

private void RegisterModelBinders()
{
     ModelBinders.Binders[typeof(UI.Address)] = new AddressModelBinder();
}

次に、モデルバインダー クラスを作成し、複雑な検証を記述します。オブジェクトのすべてのプロパティに完全にアクセスできます。これは、データ注釈が実行された後に実行されるため、検証属性のデフォルトの動作を元に戻したい場合は、いつでもモデルの状態をクリアできます。

public class AddressModelBinder : DefaultModelBinder
{
    protected override void OnModelUpdated(ControllerContext controllerContext, 
        ModelBindingContext bindingContext)
    {
        base.OnModelUpdated(controllerContext, bindingContext);

        // get the address to validate
        var address = (Address)bindingContext.Model;

        // validate US zipcode
        if (address.CountryCode == "US")
        {
            if (new Regex(@"^\d{5}([\-]\d{4})?$", RegexOptions.Compiled).
                Match(address.ZipOrPostal ?? "").Success == false)
            {
                // not a valid zipcode so highlight the zipcode field
                var ms = bindingContext.ModelState;                    
                ms.AddModelError(bindingContext.ModelName + ".ZipOrPostal", 
                "The value " + address.ZipOrPostal + " is not a valid zipcode");
            }
        }
        else {
            // we don't care about the rest of the world right now
            // so just rely on a [Required] attribute on ZipOrPostal
        }

        // all other modelbinding attributes such as [Required] 
        // will be processed as normal
    }
}

この利点は、既存のすべての検証属性 ([Required]、[EmailValidator]、[MyCustomValidator]) が引き続き機能することです。

モデル バインダーに追加のコードを追加してフィールドを設定したり、必要に応じてモデル レベルの ModelState エラーを追加したりできます。

私にとってAddressは、メインモデルの子であることに注意してください-この場合CheckoutModel、次のようになります:

public class CheckoutModel
{
    // uses AddressModelBinder
    public Address BillingAddress { get; set; }
    public Address ShippingAddress { get; set; }

    // etc.
}

そのため、「BillingAddress.ZipOrPostal」と「ShippingAddress.ZipOrPostal」にモデル エラーが設定されるようにする必要があります。bindingContext.ModelName+ ".ZipOrPostal"

PS。「単体テストの種類」からのコメントを歓迎します。これが単体テストに与える影響についてはわかりません。

于 2010-01-17T12:42:59.247 に答える
0

エラー文字列、IDataErrorInfo、および Html.ValidationMessage に関するコメントについては、次を使用してオブジェクト レベルとフィールド レベルのエラー メッセージを表示できます。

Html.ValidationMessage("address", "Error")

Html.ValidationMessage("address.PostalCode", "Error")

コントローラーで、オブジェクトのポスト メソッド ハンドラー パラメーターを [Bind(Prefix = "address")] で装飾します。HTML では、入力フィールドに次のように名前を付けます...

<input id="address_PostalCode" name="address.PostalCode" ... />

通常、Html ヘルパーは使用しません。id と name の間の命名規則に注意してください。

于 2009-10-03T02:00:09.950 に答える