4

我有两个单独的视图访问同一个模型。当我将验证器数据注释放在模型上时,它会像宣传的那样工作,如果留空或不在范围内,它会阻止提交数据(对于两个视图)。但是,我有一个视图应该能够允许为属性保存空值或空值,而另一个视图需要在允许它通过之前输入或选择信息。换句话说,我想为一个视图关闭模型中属性的验证器,并为另一个视图保留它。这是示例代码:

模型:

[Range(1, 999, ErrorMessage = "A submittal is required")]
public int SubmittalId { get; set; }

查看#1:

 <label>@Model.AuditDoc.SubmittalsLabel.ConfigurableLabelDesc</label> @Html.ValidationMessageFor(x => x.AuditDoc.SubmittalId) @Html.DropDownListFor(x => x.AuditDoc.SubmittalId, new SelectList(Model.AuditDoc.ListOfSubmittals, "Id", "Name"))

查看#2:

 <label>@Model.AuditDoc.SubmittalsLabel.ConfigurableLabelDesc</label> @Html.DropDownListFor(x => x.AuditDoc.SubmittalId, new SelectList(Model.AuditDoc.ListOfSubmittals, "Id", "Name"))

如您所见,我想为 View #2 禁用该验证器数据注释,并为 View #1 保留它。

4

3 回答 3

2

这是不可能通过默认的数据注释集实现的。但是,您可以选择使用 2 个单独的视图模型或编写自己的验证属性。

我写过一次..虽然我讨厌使用它..

public class RequiredOnAttribute : ValidationAttribute
{
    public string[] URLs { get; set; }

    public override bool IsValid(object value)
    {
        if (URLs.Contains(System.Web.HttpContext.Current.Request.Url.AbsolutePath))
        {
            if (string.IsNullOrEmpty(value as string))
            {
                return false;
            }
        }
        return true;
    }
}

用法:

[RequiredOn(URLs = new string[] { "/create", "/edit" })]
public string MyModelField { get; set; }

你可以对 Range、RegEx 等做同样的事情。

于 2012-08-08T22:27:24.130 回答
2

我使用不同的方法解决了这个问题。

诀窍不是禁用验证本身,而是在调用控制器的操作之前清除任何不适当的验证错误(因此 ModelState.IsValid 返回 true)。

如果一个模型(或视图模型)对象需要自定义验证,那么它会实现我定义的一个接口ICustomValidation,它看起来像这样:

public interface ICustomValidation {
    void PerformValidation(ModelStateDictionary modelState);
}

我的BaseController类(我所有的控制器子类)都有这个方法覆盖:

protected override void OnActionExecuting(ActionExecutingContext filterContext) {
    base.OnActionExecuting(filterContext);

    // Unfortunately it seems this is the only way to get the Model object
    if( filterContext.ActionParameters.ContainsKey("model") ) {

        Object                    model = filterContext.ActionParameters["model"];
        ModelStateDictionary modelState = filterContext.Controller.ViewData.ModelState; // ViewData.Model always returns null at this point.

        ICustomValidation modelValidation = model as ICustomValidation;
        if( modelValidation != null ) {
            modelValidation.PerformValidation( modelState );
        }
    }

}

因此,在示例 ViewModel 类中,如果我想禁用(或者更确切地说:忽略)某些验证错误,那么它只需要这样做:

public class SomeModel : ICustomValidation {

    [Required]
    public Boolean NamePresent { get; set; }

    [Required]
    public String Name { get; set; }

    public void PerformValidation(ModelStateDictionary modelState) {
        if( !NamePresent ) dict.Remove("Name");
    }
}

在我的实际代码中,有更多的逻辑可以在模型递归和按前缀的方法中清除 ModelStateDictionary,从而保持它的健壮性。

我的解决方案与您的问题不完全匹配,但使用类似的方法您应该能够让它为您工作。

于 2012-08-08T22:57:11.013 回答
0

我也建议使用不同的视图模型对象。这篇文章有一个很好的例子来说明如何干净地实现它http://lostechies.com/jimmybogard/2009/06/30/how-we-do-mvc-view-models/

或者,您可以简单地不在控制器上调用 ModelState.IsValid。

于 2012-08-08T22:39:00.947 回答