【问题标题】:Why is StringValues used for Request.Query values?为什么 StringValues 用于 Request.Query 值?
【发布时间】:2018-06-19 17:06:11
【问题描述】:

假设我有一些如下所示的网址: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
  }

但必须像这样检查

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

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

【问题讨论】:

  • 您希望 www.myhost.com/mypage 的值是多少?color=blue&color=red&color=green
  • @podiluska 我不知道多次指定参数是否有效。如果我这样做了,我希望只收到最后一个,即您的示例中的绿色。
  • 不要使用Request.Query,而是使用model binding
  • @RonC 我很确定这就是查询字符串 使用 的工作方式。但是当前在查询字符串上提供集合的“智慧”是重复键。你和我是否同意这一点无关紧要:)
  • 你可以使用var color = Request.Query["color"]; if (StringValues.IsNullOrEmpty(color)) { // do something };

标签: c# asp.net-core


【解决方案1】:

Request.Query["color"] 返回StringValues,因为可以传递string 值的集合。所以,我建议你把它当作动作参数,模型绑定来处理。

public ActionResult SaveColor([FromUri] string[] color);

【讨论】:

  • 如果 url 是 @Jamiec 和 @podiluska 提到的 @Jamiec 和 @podiluska 提到的 www.myhost.com/mypage?color=blue&color=red&color=yellow,这段代码会返回什么。
  • 如果您希望字符串列表更改参数为“string[]”。
【解决方案2】:

只是为好奇的灵魂发帖,可能与问题无关。只是警告。

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

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

    您会发现自己在pageSize 参数中抛出异常Count StringValues 上的属性将为您提供值 1,但基础 _value""(空 字符串)和_valuesnull。注意 - 您尝试转换时发生异常或 从 IQueryCollection 访问值)

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

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

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

【讨论】:

  • 您的回答与问题非常相关。有趣的是StringValue.IsNullOrEmpty(StringValue value) 有效。正如我所提到的,我最终使用 Request.Query["color"].Count == 0 检查 null 但我认为你的方法读起来更好。
【解决方案3】:

正如其他人已经提到的,类型是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

然而,最初的“问题”是Request.Query[x]总是返回一个非空的StringValues 对象(因此检查任何值都是安全的)。如果要检查查询参数中是否存在键,则应使用ContainsKey

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

或者,使用TryGetValue:

if (Request.Query.TryGetValue("color", out var colorValue))
{
    DoSomething(colorValue);
}

话虽如此,大多数时候访问Request.Query 并不是必需的。您应该只使用 model binding 来代替,它会自动为您提供所需的查询参数,只需将它们放在操作的签名中即可:

public ActionResult MyAction(string color)
{
    DoSomething(color);
}

【讨论】:

  • 感谢您指出StringValues 确实支持到string 的隐式转换,因此String color= Request.Query["color"]; 确实有效。我以为我看到了其他情况,我的错。
  • 这是我希望我可以将 OP 的接受标记转移到不同答案的时候之一。虽然我在技术上“回答”了这个问题,但这个问题应该得到了正确答案的认可。特别是最后一点关于不直接调用Query,而是使用模型绑定。
  • 我建议使用StringValues.IsNullOrEmpty() 而不是Count == 0。您需要添加using Microsoft.Extensions.Primitives
  • @Steve 在我的回答中,我实际上是在争论 反对 检查 value 而是检查密钥是否存在。话虽如此,StringValues.IsNullOrEmpty 的语义确实与检查 Empty 或检查计数略有不同。
  • @Jamiec 抱歉,我花了这么长时间才注意到您关于更改已接受标记的评论。我同意并已更改。我最初没有,因为您的回答是第一个帮助我了解情况的答案,但我同意您的观点,即这个答案更可靠。
【解决方案4】:

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

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

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

【讨论】:

  • 谢谢,我不知道在查询字符串中多次指定相同的查询参数是有效的。考虑到它在网络上的使用频率(之前从未见过它,并且自 1995 年以来一直在进行网络开发),我希望它不会被允许,因为它会使代码在很少使用的边缘情况下不那么优雅。但现在我明白为什么要引入“StringValues”了。有趣的是 StringValues 的概念直到 Asp.Net Core 才被引入,Asp.Net 的早期版本返回字符串。
  • 我想知道为什么 .NET Core 中的 QueryHelpers.AddQueryString 是:QueryHelpers.AddQueryString(string uri, IDictionary queryString)
猜你喜欢
  • 1970-01-01
  • 2020-08-01
  • 2023-01-21
  • 1970-01-01
  • 2022-10-16
  • 2020-03-21
  • 1970-01-01
  • 2022-01-08
  • 1970-01-01
相关资源
最近更新 更多