MVC 如何忽略嵌套视图模型的验证

问题描述 投票:0回答:5

我有一个页面,我用它向控制器发布两个视图模型:查询和预约。预约嵌套在查询中。用户可以选择向我们提交查询,而无需创建预约。

我在视图模型属性上使用内置的 MVC 所需属性。

我的问题是,当用户选择创建没有预约的查询时,如何优雅地忽略嵌套 Appointment 视图模型上的验证器并让 ModelState.IsValid 返回 true?

if(!viewModel.CreateAppointment)
            {
                //ignore the nested view models validation                            
            }
asp.net-mvc-3
5个回答
6
投票

您可以创建一个自定义 IgnoreModelError 属性,如下所示,并在视图中使用 2 个单独的按钮,一个仅用于查询,一个用于预约。

// C#
public class IgnoreModelErrorAttribute : ActionFilterAttribute
{
    private string keysString;

    public IgnoreModelErrorsAttribute(string keys)
        : base()
    {
        this.keysString = keys;
    }

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        ModelStateDictionary modelState = filterContext.Controller.ViewData.ModelState;
        string[] keyPatterns = keysString.Split(new char[] { ',' }, 
                 StringSplitOptions.RemoveEmptyEntries);
        for (int i = 0; i < keyPatterns.Length; i++)
        {
            string keyPattern = keyPatterns[i]
                .Trim()
                .Replace(@".", @"\.")
                .Replace(@"[", @"\[")
                .Replace(@"]", @"\]")
                .Replace(@"\[\]", @"\[[0-9]+\]")
                .Replace(@"*", @"[A-Za-z0-9]+");
            IEnumerable<string> matchingKeys = _
               modelState.Keys.Where(x => Regex.IsMatch(x, keyPattern));
            foreach (string matchingKey in matchingKeys)
                modelState[matchingKey].Errors.Clear();
        }
    }
}


[HttpPost]
[IgnoreModelErrors("Enquiry.Appointment")]
public ActionResult CreateEnquiryOnly(Enquiry enquiry)
{
    // Code for enquiry only.
}

[HttpPost]
public ActionResult CreateAppointment(Enquiry enquiry)
{
    // Code for appointment.
}

3
投票

嗯,在使用标准数据属性时,没有办法“优雅地”忽略错误。

不过您有多种选择。快速而肮脏(即不优雅)的方法是从控制器中的 ModelState 中清除相关错误。

if (some condition) {
    ModelState["controlName"].Errors.Clear();
}

您还可以编写自己的使用条件测试的自定义数据属性。就像这里描述的那样:

http://blogs.msdn.com/b/simonince/archive/2011/02/04/conditional-validation-in-asp-net-mvc-3.aspx

第三种方法是避开属性并使用验证框架,例如 FluentValidation

最后一个选择是使用 JavaScript 来确定数据的正确状态,然后修改表单操作 URL 以发布到不同的操作方法。然后,您可以使用 Bind 属性来装饰操作方法参数,以排除您不需要的数据项。但是,我不推荐这个,因为它需要客户端参与服务器端验证过程。


2
投票

这就是我最终所做的。

这使我能够清除嵌套约会 ViewModel 上的所有错误。

if (!viewModel.CreateAppointment)
            {
                foreach (var modelError in ModelState)
                {
                    string propertyName = modelError.Key;

                    if (propertyName.Contains("AppointmentsViewModel"))
                    {
                        ModelState[propertyName].Errors.Clear();
                    }
                }
            }

0
投票

另一个选项是不在查询中嵌套约会,而是为页面创建一个分别包含约会和查询模型的 ViewModel,然后您可以使用 Bind 属性和 Property Include 或 Exclude 来有选择地选择要绑定或排除的模型,如图所示下面。

    Public Class EnquiryViewModel
    {
        public Appointment App {get; set;}
        public Enquiry Enq {get; set; }
    } 

    [HttpPost]
    //Only bind Enquiry model and it's errors.
    public ActionResult CreateEnquiryOnly([Bind(Include = "Enq")]EnquiryViewModel enquiry)
    {
        if(ModelState.IsValid)
        {
        // Code for enquiry only.
        }
    }

0
投票

我做了与 Erik 类似的操作 - 从控制器的

ModelState
中删除了忽略属性的错误。

public async Task<IActionResult> AddRankAssignment(RankAssignmentVm rankAssignmentVm)
{
    ModelState.Remove(nameof(rankAssignmentVm.Order));

    if (!ModelState.IsValid)
    {
        return BadRequest(ModelState);
    }

    ...
}
最新问题
© www.soinside.com 2019 - 2024. All rights reserved.