zoukankan      html  css  js  c++  java
  • MVC模型部分验证

    ASP.NET MVC模型部分验证

    在很多情况下,我们为了代码的复用可能会存在ViewModel共用的情形。比方说,web应用中常常会遇到的一个需求就是用户找回密码的功能。用户首先要验证通过验证邮箱(通常是用户名)来获取验证码,然后再进行密码重置。那么此时假设需要4个字段:Email、Password、ConfirmPassword、VerifiCode。那么就需要2个单独的页面中队这一个model进行分步验证了。google了一下,发现了一些有价值的解决方案。为了说明问题,写了一个小的Demo如下:

    ViewModel:

     View Code
    public class ForgotPasswordMdl
    {
        [Display(Name = "邮箱")]
        [Required(ErrorMessage = "请输入注册时的邮箱地址")]
        public string Email { get; set; }
        [Display(Name = "密码")]
        [Required(ErrorMessage = "密码不能为空")]
        public string Password { get; set; }
        [Display(Name = "确认密码")]
        [Required(ErrorMessage = "确认密码不能为空")]
        public string ConfirmPassword { get; set; }
    }

    2个简单的页面一个验证邮箱、一个验证重置的密码,就不列出。

    先来看方案1:

     View Code
    [HttpPost]
    public ActionResult EmailValidate([Bind(Exclude = "Password")]ForgotPasswordMdl model)
    {
        var array = new string[] { "Password", "ConfirmPassword" };
        foreach (var key in array)
        {
            ModelState.Remove(key);
        }
        if (!ModelState.IsValid) return View(model);
        return RedirectToAction("ResetPassword");
    }

    当然如果你不想每次都定义一些需要筛选掉的字段的集合。你可以这么做:

     View Code
    [HttpPost]
    public ActionResult EmailValidate([Bind(Exclude = "Password")]ForgotPasswordMdl model)
    {
        var keysWithNoIncomingValue = ModelState.Keys.Where(x => !ValueProvider.ContainsPrefix(x));
        foreach (var key in keysWithNoIncomingValue)
            ModelState[key].Errors.Clear();
    
        if (!ModelState.IsValid) return View(model);
        return RedirectToAction("ResetPassword");
    }

    思路很简单就是从模型中移除不需要验证的元素。
    这个方法虽然有效,但是它没有分离应用程序的关注点。当需要忽略的字段一旦很多的时候可能就会变得很繁琐(当然如果需要验证的字段很少,你也可以这么做:ModelState.IsValidField(""))。

    再来看方案2:

     View Code
    //参看链接:http://blog.stevensanderson.com/2010/02/19/partial-validation-in-aspnet-mvc-2/
    public class ValidateOnlyIncomingValuesAttribute : ActionFilterAttribute
    {
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            var modelState = filterContext.Controller.ViewData.ModelState;
            var valueProvider = filterContext.Controller.ValueProvider;
            valueProvider.ContainsPrefix("Password");
            var keysWithNoIncomingValue = modelState.Keys.Where(x => !valueProvider.ContainsPrefix(x));
            foreach (var key in keysWithNoIncomingValue)
                modelState[key].Errors.Clear();
        }
    }

    控制器代码:

    思路也很简单:就是使用过滤器,在Action执行过程中移除未提供的字段。

    最后来看方案3:

     View Code
    //参看链接:http://www.codeproject.com/Articles/293894/Partial-Validation-with-Data-Annotations-in-ASP-NE
    public class IgnoreModelErrorsAttribute : 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 => System.Text.RegularExpressions.Regex.IsMatch(x, keyPattern));
                foreach (string matchingKey in matchingKeys)
                    modelState[matchingKey].Errors.Clear();
            }
        }
    }

    做法和上面的方案2一样,就是通过过滤器移除掉不需要验证的字段。它们其实是一样的。只不过方案2是通过ValueProvider值提供程序来检索对应的字段是否有值来实现筛选的。
    当然期待希望能有更多滴解决办法!!!

     
    分类: 问题开发
  • 相关阅读:
    Java实现 蓝桥杯VIP 算法训练 传球游戏
    Java实现 蓝桥杯VIP 算法训练 Hanoi问题
    Java实现 蓝桥杯VIP 算法训练 蜜蜂飞舞
    Java实现 蓝桥杯VIP 算法训练 奇偶判断
    Java实现 蓝桥杯VIP 算法训练 传球游戏
    Java实现 蓝桥杯VIP 算法训练 Hanoi问题
    Java实现 蓝桥杯VIP 算法训练 Hanoi问题
    Java实现 蓝桥杯VIP 算法训练 蜜蜂飞舞
    Java实现 蓝桥杯VIP 算法训练 蜜蜂飞舞
    Qt: 访问容器(三种方法,加上for循环就四种了)good
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/4252539.html
Copyright © 2011-2022 走看看