【问题标题】:ASP.NET Web API avoid invalid parameters in query stringASP.NET Web API 避免查询字符串中的无效参数
【发布时间】:2013-01-30 22:47:51
【问题描述】:

鉴于以下 Web API 控制器操作:

    // GET api/values
    public IEnumerable<string> Get()
    {
        return new string[] { "value1", "value2" };
    }

即使查询字符串中的参数不存在,执行以下请求也不会失败:

    http://localhost:22297/api/values?someinvalidparameter=10

有没有办法确保查询字符串中的所有参数都是正在调用的操作的有效参数?

【问题讨论】:

    标签: asp.net-web-api filter query-string


    【解决方案1】:

    您可以编写一个操作过滤器来验证操作参数中是否存在所有查询参数,如果不存在则抛出。

    using System;
    using System.Linq;
    using System.Net;
    using System.Net.Http;
    using System.Web.Http.Controllers;
    using System.Web.Http.Filters;
    
    namespace My.Namespace.Filters
    {
        /// <summary>
        /// Action filter that checks that parameters passed in the query string
        /// are only those that we specified in methods signatures.
        /// Otherwise returns 404 Bad Request.
        /// </summary>
        public class ValidateQueryParametersAttribute : ActionFilterAttribute
        {
            /// <summary>
            /// This method runs before every WS invocation
            /// </summary>
            /// <param name="actionContext"></param>
            public override void OnActionExecuting(HttpActionContext actionContext)
            {
                //check that client does not use any invalid parameter
                //but just those that are required by WS methods
                var parameters = actionContext.ActionDescriptor.GetParameters();
                var queryParameters = actionContext.Request.GetQueryNameValuePairs();
    
                if (queryParameters.Select(kvp => kvp.Key).Any(queryParameter => !parameters.Any(p => p.ParameterName == queryParameter)))
                {
                    actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.BadRequest);
                }
            }
        }
    }
    

    【讨论】:

    • 你不需要这个,因为如果没有必要的简单类型参数,默认动作选择器不会选择动作,基本上返回 404。
    • 如果所有参数都是可选的,即Get(int?p1 = null, int?p2 = null),即使查询字符串包含无效参数也会执行动作,所以我认为这种做法应该工作。我试试看,谢谢!
    • 啊,是的。默认操作选择器不考虑可选参数。
    【解决方案2】:

    为了更好地使用开箱即用的验证支持,我创建了自己的操作选择器,它可以将 URI 参数绑定到复杂类型的对象而不会重复。

    因此,您可以使用此操作选择器执行以下操作:

    public class CarsByCategoryRequestCommand {
    
        public int CategoryId { get; set; }
        public int Page { get; set; }
    
        [Range(1, 50)]
        public int Take { get; set; }
    }
    
    public class CarsByColorRequestCommand {
    
        public int ColorId { get; set; }
        public int Page { get; set; }
    
        [Range(1, 50)]
        public int Take { get; set; }
    }
    
    [InvalidModelStateFilter]
    public class CarsController : ApiController {
    
        public string[] GetCarsByCategoryId(
            [FromUri]CarsByCategoryRequestCommand cmd) {
    
            return new[] { 
                "Car 1",
                "Car 2",
                "Car 3"
            };
        }
    
        public string[] GetCarsByColorId(
            [FromUri]CarsByColorRequestCommand cmd) {
    
            return new[] { 
                "Car 1",
                "Car 2"
            };
        }
    }
    

    然后,您可以注册一个操作过滤器来验证用户输入以终止请求并返回“400 Bad Request”响应以及验证错误消息:

    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
    public class InvalidModelStateFilterAttribute : ActionFilterAttribute {
    
        public override void OnActionExecuting(HttpActionContext actionContext) {
    
            if (!actionContext.ModelState.IsValid) {
    
                actionContext.Response = actionContext.Request.CreateErrorResponse(
                    HttpStatusCode.BadRequest, actionContext.ModelState);
            }
        }
    }
    

    查看以下帖子,了解有关此操作选择器以及如何获取它的更多信息:

    【讨论】:

    • 看起来不错,我先试试RaghuRam建议的更简单的方法,无论如何,这很有趣,谢谢分享:)
    【解决方案3】:

    对于 .net core web-api 会有些不同:

     public class ValidateQueryParametersAttribute : ActionFilterAttribute
    {
    
        public override void OnActionExecuting(ActionExecutingContext actionContext)
        {
    
            var parameters = actionContext.ActionDescriptor.Parameters.ToList();
            var queryParameters = actionContext.HttpContext.Request.Query.Keys.ToList();
    
            if (queryParameters.Any(queryParameter => !parameters.Any(p => p.Name == queryParameter)))
            {
                actionContext.Result = new JsonResult(new { HttpStatusCode.BadRequest });
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2012-08-05
      • 1970-01-01
      • 1970-01-01
      • 2015-02-02
      • 1970-01-01
      • 1970-01-01
      • 2012-08-19
      • 1970-01-01
      • 2020-01-06
      相关资源
      最近更新 更多