将可变数量的查询字符串参数传递给单个控制器操作

时间:2016-11-08 14:33:43

标签: asp.net-web-api2

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

[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();,但在尝试使用查询字符串请求任何网址时,如果上面显示Route属性,我会收到资源未找到错误。

我提出了一个替代方案:使用路由值而不是查询字符串参数,然后使用catch-all {*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

这很有效,但是我宁愿使用查询字符串来使用命名键而不是依赖于参数的排序(同样,使用查询字符串似乎更符合我的概念匹配&#39我正在做。)

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

编辑:

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

编辑2:

如果他们有可能,我会看到两个直接的解决方案:

  1. 将整个查询字符串作为单个字符串传递给action方法 参数。然后我可以手动解析查询字符串。
  2. 能够使用ControllerContext.Request.GetQueryNameValuePairs() 在方法体内,而不是添加相应的参数 方法签名。
  3. 但是,我还没弄清楚这两件事是否可能,虽然看起来很可能是其中之一。

2 个答案:

答案 0 :(得分:0)

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

F.e。

[HttpPost]
[Route("api/xxxxx/send")]
public void SendReuqest([FromBody] Entity name)
希望能够正确理解你的问题。

答案 1 :(得分:0)

我正在发布我提出的文件替代方案的答案。我知道其中一些(全部?)将是hacky。尽管如此...

<强> ANSWER
使用方法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...
}
相关问题