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值提供程序来检索对应的字段是否有值来实现筛选的。
    当然期待希望能有更多滴解决办法!!!

     
    分类: 问题开发
  • 相关阅读:
    tcpdump 抓包
    mysql常用日期函数
    接口自动化测试,一键快速校验接口返回值全部字段
    实训项目
    vue proxyTable 代理方式 解决 跨域pathRewrite
    cookie, session, token 发展史
    Failed to set locale, defaulting to C.UTF-8
    java String与Integer的相互转化
    java LocalDateTime 常用 转换 方法
    Java命令里面的EQ、NE、GT、LT、GE、LE分别代表含义
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/4252539.html
Copyright © 2011-2022 走看看