【问题标题】:Pass variable number of query string parameters to single controller action将可变数量的查询字符串参数传递给单个控制器操作
【发布时间】:2016-11-08 14:33:42
【问题描述】:

我正在创建一个 API,它有一个带有一个 GET 操作的控制器:

[Route("api/xxxxx/{param1:int}/{param1:int}")]
public IHttpActionResult Get(int param1, int param2) {
    // method body...
}

网址将采用以下格式:

/api/xxxxx/1/1?p1=5&p2=hello&p3=20161108
/api/xxxxx/1/1?p1=active

查询字符串参数的数量和名称会有所不同。

我想将查询字符串参数传递给控制器​​方法,但由于名称和编号不同,我无法将它们硬编码到方法签名中。有没有办法做到这一点?我尝试调用var qsParams = ControllerContext.Request.GetQueryNameValuePairs();,但在尝试使用查询字符串请求任何URL 时出现资源未找到错误,给定上面显示的Route 属性。

我想出了一个替代方案:使用路由值而不是查询字符串参数,然后使用包罗万象的{*tags} 并将其作为方法参数传递:

[Route("api/xxxxx/{param1:int}/{param1:int}/{*tags}")]
public IHttpActionResult Get(int param1, int param2, string tags) {
    // method body...
}

网址格式

/api/xxxxx/1/1/5/john/20161108
/api/xxxxx/1/1/active

这可行,但我宁愿使用查询字符串来使用命名键,而不是依赖于参数的顺序(此外,使用查询字符串似乎更适合我正在做的事情) .

那么,如何将可变查询字符串参数传递给控制器​​操作?我说“传递”参数,但它们不一定需要作为方法参数传递,只要我可以从方法主体访问查询字符串参数,同时获取带有查询字符串的 URL 以解析为有问题的行动。

编辑:

值得一提的是,为每个可能的参数集创建多个操作方法不是一种选择。

编辑 2:

如果可能的话,我看到了两种直接的解决方案:

  1. 将整个查询字符串作为单个字符串传递给操作方法 范围。然后我可以手动解析查询字符串。
  2. 可以使用ControllerContext.Request.GetQueryNameValuePairs() 在方法体内,而不是添加相应的参数 方法签名。

但是,我还没有弄清楚这两件事是否可能,尽管看起来可能是其中之一或两者都可能。

【问题讨论】:

    标签: asp.net-web-api2


    【解决方案1】:

    如果您想将实体发送到您的控制器,您可以通过 [FromBody] 获取它 认为实体是传递它的最简单方法。

    F.e.

    [HttpPost]
    [Route("api/xxxxx/send")]
    public void SendReuqest([FromBody] Entity name)
    

    希望能正确理解您的问题。

    【讨论】:

    • 我没有任何 POST,只有 GET。此外,这似乎只是将问题转移到实体上。也就是说,现在框架将尝试将参数映射到实体,但实体必须将参数定义为属性。因此,实体必须具有不同的名称和要映射到的属性数量,这与以前的问题相同,但现在尝试在实体类中解决。顺便说一句,我没有使用实体框架。
    【解决方案2】:

    我正在发布我提出的文档替代方案的答案。我知道其中一些(全部?)将是hacky。不过……

    回答
    使用方法GetQueryNameValuePairs。这是我尝试的第一件事,但我必须在路由属性或方法签名中有所不同,因为我之前遇到过“未找到”错误。然而,现在,这工作得很好。这使得整个问题和答案对我来说基本上没有意义。

    示例网址:

    /api/xxxxx/1/1?p1=5&p2=john&p3=20161108
    

    行动:

    [Route("api/xxxxx/{param1:int}/{param1:int}")]
    public IHttpActionResult Get(int param1, int param2) {
        var qsParams = ControllerContext.Request.GetQueryNameValuePairs();
        // rest of method body...
    }
    

    选项 1
    使用控制器理解并能够解析的自定义格式的单个查询字符串参数。

    示例网址:

    /api/xxxxx/1/1?qs=p1~5|p2~john|p3~20161108
    

    行动:

    [Route("api/xxxxx/{param1:int}/{param1:int}")]
    public IHttpActionResult Get(int param1, int param2, string qs) {
        string[] qsParamsArray = qs.Split(new string[] { "|" }, StringSplitOptions.RemoveEmptyEntries);
        IDictionary<string, string> qsParams = new Dictionary<string, string>();
        foreach (string p in qsParamsArray) {
            string[] kv = p.Split(new string[] { "~" }, StringSplitOptions.None);
            if (String.IsNullOrWhiteSpace(kv[0])) {
                return NotFound();
            }
            qsParams.Add(kv[0], kv[1]);
        }
        // Use qsParams as desired...
    }
    

    选项 2
    将查询字符串参数而不是查询字符串放在路由中。必须依赖于参数的排序。

    示例网址:

    /api/xxxxx/1/1/5/john/20161108
    

    行动:

    [Route("api/xxxxx/{param1:int}/{param1:int}/{*tags}")]
    public IHttpActionResult Get(int param1, int param2, string tags) {
        // parse the "tags" parameter here...
        // rest of method body...
    }
    

    选项 3
    使用通用名称硬编码最大数量的可选参数,以及参数名称和参数值的特定查询字符串参数。

    示例网址:

    /api/xxxxx/1/1?name1=p1&value1=5&name2=p2&value2=john&name3=p3&value3=20161108
    

    行动:

    [Route("api/xxxxx/{param1:int}/{param1:int}")]
    public IHttpActionResult Get(
        int param1, 
        int param2, 
        string name1 = null, 
        string value1 = null, 
        string name2 = null, 
        string value2 = null, 
        string name3 = null, 
        string value3 = null, 
        string name4 = null, 
        string value4 = null, 
        ..., 
        string nameNMAX = null, 
        string valueNMAX = null
    ) {
        // method body...
    }
    

    【讨论】:

      猜你喜欢
      • 2019-07-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-06-13
      • 1970-01-01
      • 1970-01-01
      • 2010-10-23
      相关资源
      最近更新 更多