2

IValidatableObject次のような文字列と別のビューモデルのコレクションを含む実装するビューモデルがあります。

public sealed class MainViewModel
{
    public string Name { get; set; }
    public ICollection<OtherViewModel> Others { get; set; }
}

私の検証ではOthers、によって提供されるコントラクトを使用して、さまざまなルールに対して各オブジェクトをチェックしIValidatableObjectます。

public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
    foreach (var other in this.Others)
    {
        // validate or yield return new ValidationResult
    }
}

実物の複雑な構造のため、MainViewModelモデルを再構築し、関連するコンポーネントに POST データを割り当てるカスタム モデル バインダーを作成する必要がありました。私が得ている問題は、特定のデータベースの制約に違反しているため、何も検証されず、コンテキストレベルで検証エラーが発生し、何が間違っているのかわからないことです-ビューでメソッドをModelState.IsValid呼び出すと想定しましたValidateモデルですが、それほど下がらないようです。

私のモデル バインダーは次のようになります。

public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
    int modelId = (int)controllerContext.RouteData.Values["id"];

    // query the database and re-build the components of the view model

    // iterate the POST data and assign to the model where necessary

    // should I be calling something here to validate the model before it's passed to the controller?

    return model;
}

どんな助けでも大歓迎です!

Validator.TryValidateObject

OK、少し近づいたようです。IValidatableObjectカスタム モデル バインダーに以下を追加することで、メソッドを実行できるようになりました。

var validationResults = new HashSet<ValidationResult>();
var isValid = Validator.TryValidateObject(model, new ValidationContext(model, null, null), validationResults, true);

検証メソッドをValidator.TryValidateObject呼び出し、最後のパラメーターを設定してtrueすべてのプロパティを検証するようです。validationResultsただし、意味のある方法で使用できるように、コントローラーにを取得することにこだわっています。

4

2 に答える 2

10

カスタムバインダーを介してを使用できることに気付くべきModelState.AddModelErrorでした。モデルをコントローラーに返す前に、カスタムモデルバインダーに次を追加することで、これを正しく機能させることができました。

var validationResults = new HashSet<ValidationResult>();
var isValid = Validator.TryValidateObject(model, new ValidationContext(model, null, null), validationResults, true);
if (!isValid)
{
    foreach (var result in validationResults)
    {
        bindingContext.ModelState.AddModelError("", result.ErrorMessage);
    }
}

return model;

これにより、すべてのエラーのリストがページに返さModelState.IsValidれ、コントローラー アクションのチェックが返されるようになりましたfalse

于 2012-12-03T13:51:27.490 に答える
2

ポールの素晴らしい答えは、次のように一般的な検証および変換ModelStateメソッドにリファクタリングできます(たとえば、ヘルパーまたはCustomModelBinderベースで)。さらに、検証済みのプロパティへのバインディングが保持されます。

public static void DoValidation(ModelBindingContext bindingContext, 
                                IValidatableObject model)
{
    var validationResults = new HashSet<ValidationResult>();
    var isValid = Validator.TryValidateObject(model, 
        new ValidationContext(model, null, null), validationResults, true);
    if (!isValid)
    {
        var resultsGroupedByMembers = validationResults
            .SelectMany(_ => _.MemberNames.Select(
                 x => new {MemberName = x ?? "", 
                           Error = _.ErrorMessage}))
            .GroupBy(_ => _.MemberName);

        foreach (var member in resultsGroupedByMembers)
        {
            bindingContext.ModelState.AddModelError(
                member.Key,
                string.Join(". ", member.Select(_ => _.Error)));
        }
    }
}
于 2014-03-26T05:26:33.373 に答える