Как использовать 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>
}

http://localhost/umbraco/Surface/My/DoSomething

Другие вопросы по тегам