Ответ 1
Потому что ваш запрос может выглядеть так:
www.myhost.com/mypage?color=blue&color=red&color=yellow
И вы получите все эти значения color
из одного параметра Request.Query["color"]
Допустим, у меня есть URL-адрес, который выглядит следующим образом: 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=yellow
И вы получите все эти значения color
из одного параметра Request.Query["color"]
Как уже упоминалось другими, тип является объектом 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
на самом деле не нужен в большинстве случаев. Вы должны просто использовать вместо привязку к модели, которая автоматически предоставит вам необходимые аргументы запроса, просто используя их в сигнатуре действий:
public ActionResult MyAction(string color)
{
DoSomething(color);
}
Нельзя использовать Request.Query
,
public ActionResult SaveColor(string color);
Пусть Mvc обрабатывает его.
Просто пост для любопытных душ и, вероятно, мало что делать с вопросом. Просто предупреждающая заметка.
Я оказался в подобной проблеме. Есть несколько других проблем с этим типом.
Если у вас есть параметр запроса без значения. Например: /products?pageNo=1&pageSize=
Вы получите исключение для параметра pageSize
как Count
свойство в StringValue
даст вам значение 1, но в основе _value
лежит ""
(пусто)
строка) и _values
- это null
. Примечание. Исключение - вы пытаетесь конвертировать или
доступ к значениям из IQueryCollection)
Использование TryGetValue
безопасно вытащит вас из StringValue
, но если оно будет нулевым
(как в случае с параметром pageSize
выше), вам будет сложно понять, почему
Вы не можете преобразовать StringValue
в простой String
или почему не можете сравнить с null
в
выполнять дальнейшие операции над ним, такие как проверки и т.д.
Чтобы выполнить любую проверку типа StringValue
, используйте методы, предоставляемые этим типом.
Для проверки на нулевое или пустое использование - StringValue.IsNullOrEmpty(StringValue value)