Путаница между Redirect и RedirectToAction
Я изучаю сертификат MS (70-515).
Я смущен тем, что я нашел в Интернете, и тем, что я прочитал на практическом испытании.
Несколько вопросов о состоянии SO, которые используют RedirectToAction, отправляют браузеру 302, что приводит к изменению URL-адреса в адресной строке.
Но это вопрос из 1 практических тестов:
ВОПРОС:
На главном контроллере MVC в настоящее время действует только действие индекса по умолчанию. Соответствующий код показан в следующем примере кода.
public ActionResult Index()
{
ViewData["Message"] = "Hello!";
return View();
}
Вам нужно создать действие с именем FindID, которое отображает параметр ID, введенный как часть пути. Если путь не включает параметр ID, ASP.NET должен обработать действие индекса без изменения URL-адреса в адресной строке браузера и не должен генерировать исключение. Какой сегмент кода вы должны использовать?
ИСПРАВЛЯЕМЫЙ ОТВЕТ:
public ActionResult FindID(int? id)
{
if (!id.HasValue)
return RedirectToAction("Index");
ViewData["Message"] = "ID is " + id.ToString();
return View();
}
ОБЪЯСНЕНИЕ:
Вы можете использовать форму RedirectToAction ActionResult, чтобы заставить MVC обрабатывать другое действие из действия. MVC отказывается от текущего действия и обрабатывает запрос так, как будто маршрут привел непосредственно к действию, к которому вы перенаправляете. По сути, это эквивалентно вызову Server.Transfer в стандартном приложении ASP.NET.
Redirect ActionResult отправляет ответ "HTTP Error 302 - Found" в браузер, что заставляет браузер загружать указанный URL. Это изменяет адрес, который появляется в адресной строке.
Итак:
- Удаляет ли RedirectToAction URL-адрес в браузере нетронутым?
- Изменяет ли перенаправление URL-адрес в браузере?
- Правильно ли объяснение практического теста? Из этого я понимаю, что RedirectToAction НЕ делает 302.
Ответы
Ответ 1
Вы можете использовать форму RedirectToAction ActionResult, чтобы заставить MVC обрабатывать другое действие из действия. MVC отказывается от текущего действия и обрабатывает запрос так, как будто маршрут привел непосредственно к действию, к которому вы перенаправляете. По сути, это эквивалентно вызову Server.Transfer в стандартном приложении ASP.NET.
Это неверно.
Оба RedirectToRouteResult (RedirectToAction) и RedirectResult выполняют перенаправление 302, в результате чего URL-адрес в браузере меняется.
Чтобы вернуть результат индекса без изменения кода, на самом деле код:
public ActionResult FindID(int? id)
{
if (!id.HasValue)
return View("index");
ViewData["Message"] = "ID is " + id.ToString();
return View();
}
Однако я бы не рекомендовал этот подход. Если я делаю запрос mysite.com/products/some-product
и some-product
не существует, то я должен сообщить об этом пользователю с соответствующим кодом состояния (также важным для поисковых систем).
Если единственная цель вашего действия FindID состоит в том, чтобы что-то сделать с параметром id, то он не должен быть нулевым/необязательным. Таким образом, действие FindID не будет вызываться, если идентификатор не указан.
Ответ 2
Документация для метода RedirectToAction сообщает нам, что он отправляет ответ 302:
"Возвращает ответ HTTP 302 браузеру, что заставляет браузер делать запрос GET на указанное действие."
Изучение кода в dll показывает, что он возвращает объект RedirectToRouteResult
, что вызывает перенаправление, поэтому документация верна:
protected internal virtual RedirectToRouteResult RedirectToAction(string actionName, string controllerName, RouteValueDictionary routeValues) {
RouteValueDictionary routeValueDictionaries;
if (this.RouteData == null) {
routeValueDictionaries = RouteValuesHelpers.MergeRouteValues(actionName, controllerName, null, routeValues, true);
} else {
routeValueDictionaries = RouteValuesHelpers.MergeRouteValues(actionName, controllerName, this.RouteData.Values, routeValues, true);
}
return new RedirectToRouteResult(routeValueDictionaries);
}
Правильным ответом на тестовый вопрос будет использование другого представления:
public ActionResult FindID(int? id) {
if (!id.HasValue) {
ViewData["Message"] = "Hello!";
return View("Index");
}
ViewData["Message"] = "ID is " + id.ToString();
return View();
}
Это будет использовать представление Index
вместо представления FindID
, которое возвращается бесцельным вызовом View()
.