Как использовать ViewData и ViewBag с контроллерами поверхности Umbraco
Я только что потратил 2 часа, пытаясь понять, почему, когда я помещаю строку в View.Bag/ViewData внутри моего контроллера Surface, когда я пытаюсь вернуть строку в представление, я получаю нулевое значение.
В конце концов я решил проблему, поместив строку в переменную сеанса insted.
Хотелось бы узнать, почему это не работает, и как это исправить.
Заранее спасибо.
1 ответ
Обновление: вы публикуете и перенаправляете? Когда вы обновляете форму, она запрашивает повторную публикацию? Если нет, то это потому, что вы случайно выполнили рекомендации по использованию 302 из сообщения формы (предотвращает обновление и перепечатку данных формы пользователем). Все примеры, которые я использовал для контроллеров поверхности входа return RedirectToCurrentUmbracoPage()
за которым я слепо следовал. Но, как следует из названия, на самом деле выполняется перенаправление, и это действительно два запроса! (Я упорно пришлось убедиться в Fiddler, прежде чем я поверил). ViewData и ViewBag хороши только для одного запроса - поэтому они в корне нарушены в POST 302. Сеанс хорош для нескольких запросов, поэтому он работает для вас. TempData будет работать и для вас, потому что, как оказалось, TempData - это конструкция, которая построена поверх сеанса и была специально разработана для переноса состояния между двумя сообщениями (удаляется при извлечении). Я где-то читал, что TempData был бы лучше назван RedirectData
и это помогло мне щелкнуть.
Поэтому, когда вы имеете дело с контроллерами поверхности и POSTing, у вас есть три варианта работы, которые я знаю:
- Сессия (которую вы доказали сработавшей)
- TempData (который основан на сеансе, и из того, что я прочитал, является наилучшей практикой и создан специально для этой ситуации)
- использование
return CurrentUmbracoPage();
в вашей форме пост. Я только что проверил в Fiddler, что это ровно один запрос (обновление в браузере выдает предупреждение о повторной публикации). Я также проверил, что ViewData работает таким образом. Но, потому что контроллер поверхности визуализируется как дочернее действие, используя@Html.Action(...)
ты должен использоватьParentActionViewContext
чтобы получить правильные ViewData (мой первый ответ, который я оставлю для тех, кто находит этот вопрос).
Оригинальный ответ по-прежнему полезен, когда перенаправление не включено (GET или POST, который возвращает CurrentUmbracoPage()
)...
Во многих случаях вы фактически делаете детское действие. Обычно у вас только один уровень глубины, но если вы смешаете макросы и партиалы, вы можете получить несколько уровней. Существует ViewData для каждого уровня, и вы должны идти вверх по стеку с ParentActionViewContext
добраться до вершины ViewData
что вы заселили в свой контроллер.
См. Этот комментарий от Шеннон в ответ на вопрос о контроллерах поверхности и данных о взглядах (Шеннон является основным участником команды HQ и имеет много отличного контента). Цитирую здесь:
Если вы хотите получить доступ к ViewData, который вы установили в главном ViewContext для объекта Child Action, отображаемого из главного ViewContext, вам нужно использовать @ViewContext.ParentActionViewContext.ViewData["ErrorMessage"]
ParentActionViewContext в этом примере - это ViewContext, который отображает шаблон Umbraco, а не ChildAction. Это потому, что когда вы POST (будь то внутри Umbraco или обычного MVC), вы публикуете новое действие, и процесс рендеринга начинается с нуля, когда вы проверяете свою модель, обновляете ViewData и т. Д.... все это происходит на том, что станет "основным" ViewContext при отображении представления. Затем этот вид будет отображать ваше ChildAction.
Ответ Твэмли выше превосходен, в дополнение к этому, я обнаружил, что используя TempData.Add(key, value)
работает хорошо.
Голые кости будут выглядеть так:
SurfaceController
public class MyController : Umbraco.Web.Mvc.SurfaceController
{
public MyController()
{}
public ActionResult DoSomething()
{
// surface controller does something
// get a page by it's document/model type alias
var umbracoHelper = new UmbracoHelper(UmbracoContext.Current);
var node = umbracoHelper.TypedContentSingleAtXPath("//" + "Home")
TempData.Add("Message", "This value will be passed through");
return redirectToUmbracoPage(node);
}
}
Посмотреть
@inherits UmbracoTemplatePage
@{
Layout = null;
}
@if (TempData.ContainsKey("Message"))
{
<p>@TempData["Message"]</p>
}