为什么StringValues用于Request.Query值?

Ron*_*n C 28 c# asp.net-core

假设我有一些看起来像这样的网址:www.myhost.com/mypage?color = blue

在Asp.Net Core中,我希望通过执行以下操作获取颜色查询参数值:

string color = Request.Query["color"];

但事实证明,Request.Query["color"]返回类型的值StringValues而不是string.这是为什么?

显然,StringValues类型可以包含一个字符串数组,并且包含对隐式转换的支持string[]很酷,但为什么查询参数值需要?

必须获得这样的价值似乎很奇怪:

string color = Request.Query["color"].ToString();

更糟糕的是,检查一个值以查看是否指定了查询参数不能再这样做了

  if(Request.Query["color"] == null) { 
      //param was not specified
  }
Run Code Online (Sandbox Code Playgroud)

但必须像这样检查

 if(Request.Query["color"].Count == 0) { 
      //param was not specified
 }
Run Code Online (Sandbox Code Playgroud)

由于单个查询参数不能有多个值(据我所知)为什么Request.Query["color"]返回一个StringValues对象而不是一个字符串?

Jam*_*iec 27

因为您的查询可能如下所示:

www.myhost.com/mypage?color=blue&color=red&color=yellow

然后color从一个Request.Query["color"]参数中获取所有这些值

  • 谢谢,我不知道在查询字符串中多次指定相同的查询参数是有效的.鉴于它在网络上的使用频率(自1995年以来从未见过它并且一直在进行网络开发)我希望它不被允许,因为它使得代码不那么优雅,对于很少使用的边缘情况.但现在我明白了为什么'StringValues'被引入了.有趣的是,在Asp.Net Core,Asp.Net的先前版本返回字符串之前,没有引入`StringValues`的概念. (2认同)

pok*_*oke 14

正如其他人已经提到的那样,类型是一个StringValues对象,因为从技术上讲,允许多个值.虽然通常的做法是只设置一个值,但URI规范并不会多次禁止设置值.并由应用程序决定如何处理它.

话虽这么说,StringValues有一个隐式转换string,所以你实际上不需要调用ToString()它,你可以使用它,就好像它是一个字符串.所以做一些事情Request.Query["color"] == "red",或者将它传递给一个需要字符串的方法才能正常工作.

更糟糕的是,检查一个值以查看是否指定了查询参数不能再这样做了,Request.Query["color"] == null而是必须像这样检查Request.Query["color"].Count == 0

这只是半真的.是的,为了检查StringValues对象是否为空,您可以检查其Count属性.您还可以检查StringValues.Empty:

Request.Query["color"] == StringValues.Empty
Run Code Online (Sandbox Code Playgroud)

然而,最初的"问题"是Request.Query[x]始终返回一个非空的StringValues对象(所以它的安全检查任何价值).如果要检查查询参数中是否存在密钥,则应使用ContainsKey:

if (Request.Query.ContainsKey("color"))
{
    // only now actually retrieve the value
    string colorValue = Request.Query["color"];
}
Run Code Online (Sandbox Code Playgroud)

或者,使用TryGetValue:

if (Request.Query.TryGetValue("color", out var colorValue))
{
    DoSomething(colorValue);
}
Run Code Online (Sandbox Code Playgroud)

总而言之,Request.Query大多数时候访问并不是必需的.您应该只使用模型绑定,它会自动为您提供所需的查询参数,只需将它们放在操作的签名中即可:

public ActionResult MyAction(string color)
{
    DoSomething(color);
}
Run Code Online (Sandbox Code Playgroud)

  • 这是我希望我可以将OP的接受标记转移到不同答案的次数之一。虽然我的技术上“回答”了这个问题,但这应该被认为是正确的答案。特别是最后一点关于不直接调用“Query”,而是使用模型绑定。 (2认同)

小智 5

只是为好奇的灵魂发帖,可能与问题无关。只是注意事项。

我发现自己遇到了类似的问题。这种类型还有其他几个问题。

  1. 如果您有没有值的查询参数。例如:/products?pageNo=1&pageSize=

    您会发现自己为pageSize参数抛出异常,因为Count 属性 onStringValues将为您提供值 1,但底层_valueis ""(空字符串) 和_valuesis null。注意 - 您尝试从 IQueryCollection 转换或访问值时发生异常)

  2. 使用TryGetValue将使您安全地摆脱价值,StringValues但如果它为空(如pageSize上面的参数的情况),您将很难弄清楚为什么不能转换StringValues为简单String或为什么不能比较以null对其进行进一步的操作,例如验证等

  3. 要对StringValues类型进行任何检查,请使用类型提供的方法。

检查空或空使用 - StringValues.IsNullOrEmpty(StringValues value)