代码之家  ›  专栏  ›  技术社区  ›  Denis

输入参数的自定义验证器

  •  0
  • Denis  · 技术社区  · 8 年前

    我现在有这个控制器

    /// <summary>
    /// API methods for working with test
    /// </summary>
    [RoutePrefix("api/terminal")]
    public class TerminalController : ApiController
    {
        [HttpGet]
        [Route("{terminalId}/validation")]
        public IHttpActionResult ValidateTerminal([MinUnsignValue(10)] long terminalId)
        {
            return Ok();
        }
    }
    

    和输入参数的自定义验证器

    public class MinUnsignValueAttribute : ValidationAttribute
    {
        private readonly ulong _minValue;
    
        public MinUnsignValueAttribute(ulong minValue)
        {
            _minValue = minValue;
        }
    
        protected override ValidationResult IsValid(object value, ValidationContext validationContext)
        {
            //if value < _minValue return new ValidationResult("false")
    
            return ValidationResult.Success;
        }
    }
    

    当我发送6时,验证器被忽略,操作被调用。是因为 web api pipeline 由iactionfilter[]iaauthenticationfilter[]iaauthorizationfilter[]authorizationfilters iexceptionfilter[]组成。

    是否有方法将我的自定义属性集成到管道?

    1 回复  |  直到 7 年前
        1
  •  0
  •   Denis    8 年前

    好吧,我没找到答案。我自己写的

    public class ParametersFilter : ActionFilterAttribute
    {
        class Wrapper
        {
            public Wrapper(MethodInfo methodInfo, object validationAttributeInstance)
            {
                MethodInfo = methodInfo;
                ValidationAttributeInstance = validationAttributeInstance;
            }
    
            public MethodInfo MethodInfo { get; }
            public object ValidationAttributeInstance { get; }
        }
    
        static readonly ConcurrentDictionary<string, Wrapper> Cache = new ConcurrentDictionary<string, Wrapper>();
        static readonly HashSet<string> Registry = new HashSet<string>();
    
        public override void OnActionExecuting(HttpActionContext actionContext)
        {
            if (!Registry.Contains(actionContext.ActionDescriptor.ActionName))
            {
                Registry.Add(actionContext.ActionDescriptor.ActionName);
    
                //first invokation, have to check
                Type controllerType = actionContext.ControllerContext.Controller.GetType();
                foreach (MethodInfo methodInfo in controllerType.GetMethods())
                {
                    if (actionContext.ActionDescriptor.ActionName != methodInfo.Name) continue;
    
                    ParameterInfo[] parameters = methodInfo.GetParameters();
                    if (parameters.Length != actionContext.ActionArguments.Count) continue;
    
                    foreach (ParameterInfo parameterInfo in parameters)
                    {
                        //The primitive types are Boolean, Byte, SByte, Int16, UInt16, Int32, UInt32, Int64, UInt64, IntPtr, UIntPtr, Char, Double, and Single.
                        if (!parameterInfo.ParameterType.IsPrimitive) continue;
                        if (!actionContext.ActionArguments.ContainsKey(parameterInfo.Name)) continue;
    
                        var customAttributesData = parameterInfo.GetCustomAttributesData();
                        foreach (CustomAttributeData customAttributeData in customAttributesData)
                        {
                            if (!customAttributeData.AttributeType.IsSubclassOf(typeof(ValidationAttribute))) continue;
    
                            var validationAttributeInstance = customAttributeData.Constructor.Invoke(customAttributeData.ConstructorArguments.Select(x => x.Value).ToArray()) as ValidationAttribute;
                            if (validationAttributeInstance == null) continue;
    
                            MethodInfo method = validationAttributeInstance
                                .GetType()
                                .GetMethod("IsValid", BindingFlags.NonPublic | BindingFlags.Instance);
    
                            Cache.TryAdd(
                               $"{actionContext.ActionDescriptor.ActionName}{parameterInfo.Name}",
                               new Wrapper(method, validationAttributeInstance));
                        }
                    }
                }
            }
    
            foreach (var actionArgument in actionContext.ActionArguments)
            {
                Wrapper wrapper;
                if (!Cache.TryGetValue(
                    $"{actionContext.ActionDescriptor.ActionName}{actionArgument.Key}", out wrapper))
                {
                    continue;
                }
    
                object instance = actionArgument.Value;
                var context = new ValidationContext(instance)
                {
                    DisplayName = actionArgument.Key,
                    MemberName = actionArgument.Key
                };
    
                var results = wrapper.MethodInfo.Invoke(wrapper.ValidationAttributeInstance, new[] { instance, context }) as ValidationResult;
                if (results != ValidationResult.Success)
                {
                    var response = new Utils.WebApi.Common.Response.WebResponse
                    {
                        IsSuccess = false,
                        ErrorMessage = results?.ErrorMessage
                    };
    
                    actionContext.Response = new HttpResponseMessage
                    {
                        StatusCode = HttpStatusCode.BadRequest,
                        Content = new ObjectContent(
                            response.GetType(),
                            response,
                            new JsonMediaTypeFormatter())
                    };
                    break;
                }
            }
    
            base.OnActionExecuting(actionContext);
        }
    }
    
    推荐文章
    Robin  ·  自定义验证代码
    12 年前