ASP.NET MVC 3对嵌套对象的验证无法按预期工作 - 验证子对象两次而不是父对象

noo*_*otn 7 validation asp.net-mvc defaultmodelbinder asp.net-mvc-3

我试图让ASP.NET MVC 3从复杂的嵌套对象生成表单.我发现有一个验证行为是意外的,我不确定它是否是DefaultModelBinder中的错误.

如果我有两个对象,让我们调用"父"一个"OuterObject",它有一个"InnerObject"类型的属性(子):

    public class OuterObject : IValidatableObject
{
    [Required]
    public string OuterObjectName { get; set; }

    public InnerObject FirstInnerObject { get; set; }

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        if (!string.IsNullOrWhiteSpace(OuterObjectName) && string.Equals(OuterObjectName, "test", StringComparison.CurrentCultureIgnoreCase))
        {
            yield return new ValidationResult("OuterObjectName must not be 'test'", new[] { "OuterObjectName" });
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这是InnerObject:

    public class InnerObject : IValidatableObject
{
    [Required]
    public string InnerObjectName { get; set; }

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        if (!string.IsNullOrWhiteSpace(InnerObjectName) && string.Equals(InnerObjectName, "test", StringComparison.CurrentCultureIgnoreCase))
        {
            yield return new ValidationResult("InnerObjectName must not be 'test'", new[] { "InnerObjectName" });
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

你会注意到我在两者上的验证......只是一些虚拟验证,说某些值不能等于"测试".

以下是将在(Index.cshtml)中显示的视图:

@model MvcNestedObjectTest.Models.OuterObject
@{
    ViewBag.Title = "Home Page";
}

@using (Html.BeginForm()) {
<div>
    <fieldset>
        <legend>Using "For" Lambda</legend>

        <div class="editor-label">
            @Html.LabelFor(m => m.OuterObjectName)
        </div>
        <div class="editor-field">
            @Html.TextBoxFor(m => m.OuterObjectName)
            @Html.ValidationMessageFor(m => m.OuterObjectName)
        </div>

        <div class="editor-label">
            @Html.LabelFor(m => m.FirstInnerObject.InnerObjectName)
        </div>
        <div class="editor-field">
            @Html.TextBoxFor(m => m.FirstInnerObject.InnerObjectName)
            @Html.ValidationMessageFor(m => m.FirstInnerObject.InnerObjectName)
        </div>

        <p>
            <input type="submit" value="Test Submit" />
        </p>
    </fieldset>
</div>
}
Run Code Online (Sandbox Code Playgroud)

..最后这里是HomeController:

    public class HomeController : Controller
{
    public ActionResult Index()
    {
        var model = new OuterObject();
        model.FirstInnerObject = new InnerObject();
        return View(model);
    }

    [HttpPost]
    public ActionResult Index(OuterObject model)
    {
        if (ModelState.IsValid)
        {
            return RedirectToAction("Index");
        }
        return View(model);
    }
}
Run Code Online (Sandbox Code Playgroud)

你会发现,当模型被DefaultModelBinder验证时,"InnerObject"中的"Validate"方法被击中两次,但"OuterObject"中的"Validate"方法根本没有被击中.

如果你从"InnerObject"中取下IValidatableObject,那么"OuterObject"上的那个就会被击中.

这是一个错误,还是我希望它能以这种方式工作?如果我期待它,最好的解决方法是什么?

amy*_*n04 0

您是否应该为 InnerObject 创建 OuterObject 基类,而不是像您那样创建关系?(反之亦然)并提供视图基础对象作为 ViewModel?

这意味着当模型绑定时,将调用 OuterObject(或您的基类)的默认构造函数,从而间接调用两个对象上的 Validate。

即类:

public class OuterObject : InnerObject, IValidateableObject
{
...
}
Run Code Online (Sandbox Code Playgroud)

看法:

@model MvcNestedObjectTest.Models.OuterObject
Run Code Online (Sandbox Code Playgroud)

控制器动作:

public ActionResult Index(OuterObject model)
Run Code Online (Sandbox Code Playgroud)