• 自定义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();
            }
        }
    

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

  • 相关阅读:
    【iOS开发】动态添加子视图 UIView 的正确方法
    70.容器分配ip
    79.scp命令
    78.ssh隧道
    77.手撕sql语句
    76.ssh基于秘钥形式连接
    75.python删除目录
    74.ssh服务介绍(基于密码连接)
    73.nginx跨域
    72.nginx文件配置
  • 原文地址:https://www.cnblogs.com/coce/p/6840156.html
Copyright © 2020-2023  润新知