zoukankan      html  css  js  c++  java
  • 自定义Remote验证(对博客园文章“Asp.net MVC验证哪些事(3)-- Remote验证及其改进(附源码)”自定义验证的改进)

    最近拜读了博客园我一直很敬仰的大神几年前关于asp.net mvc中自定义Remote验证的文章:

    Asp.net MVC验证哪些事(3)-- Remote验证及其改进(附源码)

    获益匪浅。但是文中给出的解决方案,个人觉得里面动态执行验证方法的那段代码有可以完善的地方(并没有半点对大神的诋毁,代码为下面标色部分):

    public class CustomModelBinder : DefaultModelBinder
        {
            protected override void BindProperty(ControllerContext controllerContext,
            ModelBindingContext bindingContext,
            PropertyDescriptor propertyDescriptor)
            {
                if (propertyDescriptor.PropertyType == typeof(string))
                {
                    //检查Model绑定的属性中,是否应用了CustomRemoteAttribute
                    var remoteAttribute =
                      propertyDescriptor.Attributes.OfType<CustomRemoteAttribute>()
                        .FirstOrDefault();
    
                    if (remoteAttribute != null)
                    {
                        //如果使用了CustomRemoteAttribute, 就开始找到CustomAttribute中指定的Controller
                        var allControllers = GetControllerNames();
                        var controllerType = allControllers.FirstOrDefault(x => x.Name ==
                                                                                 remoteAttribute.Controller + "Controller");
                        if (controllerType != null)
                        {
                            //查找Controller中的Action方法
                            var methodInfo = controllerType.GetMethod(remoteAttribute.Action);
                            if (methodInfo != null)
                            {
                                //调用方法,得到验证的返回结果
                                bool isValidate = callRemoteValidationFunction(
                                controllerContext,
                                bindingContext,
                                propertyDescriptor,
                                controllerType,
                                methodInfo,
                                remoteAttribute.AdditionalFields);
                                //如果验证失败,添加ModelError
                                if (!isValidate)
                                {
                                    bindingContext.ModelState.AddModelError(propertyDescriptor.Name, remoteAttribute.ErrorMessage);
                                }
                            }
                        }
                    }
                }
                base.BindProperty(controllerContext, bindingContext, propertyDescriptor);
            }
    
            /// This function calls the indicated method on a new instance of the supplied
            /// controller type and return the error string. (NULL if not)
            private bool callRemoteValidationFunction(
              ControllerContext controllerContext,
              ModelBindingContext bindingContext,
              MemberDescriptor propertyDescriptor,
              Type controllerType,
              MethodInfo methodInfo,
              string additionalFields)
            {
    
                var propertyValue = controllerContext.RequestContext.HttpContext.Request.Form[
                    bindingContext.ModelName + propertyDescriptor.Name];
                var controller = (Controller)Activator.CreateInstance(controllerType);
                object result = null;
                var parameters = methodInfo.GetParameters();
                if (parameters.Length == 0)
                {
                    result = methodInfo.Invoke(controller, null);
                }
                else
                {
                    var parametersArray = new List<object>();
                    if (!string.IsNullOrEmpty(additionalFields))
                    {
                        int i = 0;
                        foreach (var field in additionalFields.Split(','))
                        {
                            //可以根据参数名字对应,这里根据参数顺序对应
                            string value = controllerContext.RequestContext.HttpContext
                                        .Request.Form[bindingContext.ModelName + field];
                            parametersArray.Add(Convert.ChangeType(value, parameters[i].ParameterType));
                            i++;
                        }
                        if (parametersArray.Count == parameters.Length)
                        {
                            result = methodInfo.Invoke(controller, parametersArray.ToArray());
                        }
                    }
                }
                if (result != null)
                {
                    return Convert.ToBoolean(((JsonResult)result).Data);
                }
                return false; ;
            }
    
            /// Returns a list of all Controller types
            private static IEnumerable<Type> GetControllerNames()
            {
                var controllerNames = new List<Type>();
                GetSubClasses<Controller>().ForEach(controllerNames.Add);
                return controllerNames;
            }
    
            private static List<Type> GetSubClasses<T>()
            {
                return Assembly.GetCallingAssembly().GetTypes().Where(
                  type => type.IsSubclassOf(typeof(T))).ToList();
            }
        }

    当然这段代码是没有任何问题的,也考虑到了验证方法包含多个参数的问题,但是有个问题就是:Remote验证方法的参数都被指定成了string类型,但是实际中,我们不能保证我们的验证方法的参数都是string类型。这里给出自己改进的代码部分

    var parametersArray = new List<object>();
    if (!string.IsNullOrEmpty(additionalFields))
    {
        int i = 0;
        foreach (var field in additionalFields.Split(','))
        {
            //可以根据参数名字对应,这里根据参数顺序对应
            string value = controllerContext.RequestContext.HttpContext
                        .Request.Form[bindingContext.ModelName + field];
            parametersArray.Add(Convert.ChangeType(value, parameters[i].ParameterType));
            i++;
        }
        if (parametersArray.Count == parameters.Length)
        {
            result = methodInfo.Invoke(controller, parametersArray.ToArray());
        }
    }
    

     上面是根据验证参数顺序来对应的,当然,你也可以根据参数名称来对应了。下面是调用方法:

    [Required]
    [CustomRemote("CheckMMSRecord", "MMSRecord", AdditionalFields = "CustPhone,Type,VCode", ErrorMessage = "请输入正确的手机验证码")]
    public string VCode { get; set; }
    

    验证方法定义为:

    public JsonResult CheckMMSRecord2(string Mobile, int Type, string VCode)
    

    CustomModelBinder完整如下:

    public class CustomModelBinder : DefaultModelBinder
        {
            protected override void BindProperty(ControllerContext controllerContext,
            ModelBindingContext bindingContext,
            PropertyDescriptor propertyDescriptor)
            {
                if (propertyDescriptor.PropertyType == typeof(string))
                {
                    //检查Model绑定的属性中,是否应用了CustomRemoteAttribute
                    var remoteAttribute =
                      propertyDescriptor.Attributes.OfType<CustomRemoteAttribute>()
                        .FirstOrDefault();
    
                    if (remoteAttribute != null)
                    {
                        //如果使用了CustomRemoteAttribute, 就开始找到CustomAttribute中指定的Controller
                        var allControllers = GetControllerNames();
                        var controllerType = allControllers.FirstOrDefault(x => x.Name ==
                                                                                 remoteAttribute.Controller + "Controller");
                        if (controllerType != null)
                        {
                            //查找Controller中的Action方法
                            var methodInfo = controllerType.GetMethod(remoteAttribute.Action);
                            if (methodInfo != null)
                            {
                                //调用方法,得到验证的返回结果
                                bool isValidate = callRemoteValidationFunction(
                                controllerContext,
                                bindingContext,
                                propertyDescriptor,
                                controllerType,
                                methodInfo,
                                remoteAttribute.AdditionalFields);
                                //如果验证失败,添加ModelError
                                if (!isValidate)
                                {
                                    bindingContext.ModelState.AddModelError(propertyDescriptor.Name, remoteAttribute.ErrorMessage);
                                }
                            }
                        }
                    }
                }
                base.BindProperty(controllerContext, bindingContext, propertyDescriptor);
            }
    
            /// This function calls the indicated method on a new instance of the supplied
            /// controller type and return the error string. (NULL if not)
            private bool callRemoteValidationFunction(
              ControllerContext controllerContext,
              ModelBindingContext bindingContext,
              MemberDescriptor propertyDescriptor,
              Type controllerType,
              MethodInfo methodInfo,
              string additionalFields)
            {
    
                var propertyValue = controllerContext.RequestContext.HttpContext.Request.Form[
                    bindingContext.ModelName + propertyDescriptor.Name];
                var controller = (Controller)Activator.CreateInstance(controllerType);
                object result = null;
                var parameters = methodInfo.GetParameters();
                if (parameters.Length == 0)
                {
                    result = methodInfo.Invoke(controller, null);
                }
                else
                {
                    var parametersArray = new List<object>();
                    if (!string.IsNullOrEmpty(additionalFields))
                    {
                        int i = 0;
                        foreach (var field in additionalFields.Split(','))
                        {
                            //可以根据参数名字对应,这里根据参数顺序对应
                            string value = controllerContext.RequestContext.HttpContext
                                        .Request.Form[bindingContext.ModelName + field];
                            parametersArray.Add(Convert.ChangeType(value, parameters[i].ParameterType));
                            i++;
                        }
                        if (parametersArray.Count == parameters.Length)
                        {
                            result = methodInfo.Invoke(controller, parametersArray.ToArray());
                        }
                    }
                }
                if (result != null)
                {
                    return Convert.ToBoolean(((JsonResult)result).Data);
                }
                return false; ;
            }
    
            /// Returns a list of all Controller types
            private static IEnumerable<Type> GetControllerNames()
            {
                var controllerNames = new List<Type>();
                GetSubClasses<Controller>().ForEach(controllerNames.Add);
                return controllerNames;
            }
    
            private static List<Type> GetSubClasses<T>()
            {
                return Assembly.GetCallingAssembly().GetTypes().Where(
                  type => type.IsSubclassOf(typeof(T))).ToList();
            }
        }
    

    以上仅为个人遇见,有不对之处,还望斧正。

  • 相关阅读:
    Java虚拟机垃圾收集器parallel Scavenge 与 Parallel Old 收集器
    docker部署单机rabbitmq(自测用)
    Json 字符串转 Json 对象,Json 字符串转 DataTable
    生产管理系统 品质管理 溯源系统 电子行业 制造业 MES 生产过程追溯 电子看板
    几何视角下的三角形面积最值问题探究|思维养成
    极坐标与直角坐标的相互转化
    《手把手教你》系列技巧篇(四十八)java+ selenium自动化测试判断元素是否可操作(详解教程) 北京
    《手把手教你》系列技巧篇(四十六)java+ selenium自动化测试web页面定位toast下篇(详解教程) 北京
    《手把手教你》系列技巧篇(五十二)java+ selenium自动化测试处理面包屑(详细教程) 北京
    《手把手教你》系列技巧篇(四十七)java+ selenium自动化测试判断元素是否显示(详解教程) 北京
  • 原文地址:https://www.cnblogs.com/coce/p/6840156.html
Copyright © 2011-2022 走看看