如何将 ViewData 和 ViewBag 与 Umbraco 表面控制器一起使用
How to Use ViewData and ViewBag with Umbraco Surface Controllers
我刚刚花了 2 个小时试图找出为什么当我将一个字符串放入 View 时。Bag/ViewData 在我的 Surface 控制器中,当我尝试在视图中取回该字符串时我得到 null。
最后我通过将字符串放入会话变量中解决了这个问题。
想知道为什么它不起作用,以及如何解决它。
提前致谢。
更新:你在post进行重定向吗?当您刷新表单时,它会再次提示您 posting 吗?如果不是,那是因为您不小心遵循了从表单 post 进行 302ing 的最佳实践(防止用户刷新和重新 posting 表单数据)。我为登录界面控制器所遵循的示例都使用了 return RedirectToCurrentUmbracoPage()
,我盲目地遵循了这一点。但是,顾名思义,真的是在做重定向,而且真的是两个请求! (我固执的要在Fiddler里验证才相信)。 ViewData 和 ViewBag 仅适用于一个请求——因此它们在 POST 302 中根本被破坏。会话适用于多个请求,这就是它对您有用的原因。 TempData 也适用于您,因为事实证明,TempData 是一种构建在会话之上的构造,专门设计用于在两个 post 之间传输状态(在检索时删除)。我在某处读到,TempData 最好命名为 RedirectData
,这有助于它为我点击。
因此,当您处理 Surface Controller 和 POSTing 时,您有三个我知道可行的选项:
- 会话(你证明有效)
- TempData(建立在会话之上,从我读到的内容来看,这既是最佳实践,也是专门针对这种情况而构建的)
- 在表单 post 中使用
return CurrentUmbracoPage();
。我刚刚在Fiddler中验证了这恰好是一个请求(在浏览器中刷新提示repost警告)。我还验证了 ViewData 以这种方式工作。但是,因为表面控制器是使用 @Html.Action(...)
呈现为子动作,所以您必须使用 ParentActionViewContext
才能获得正确的 ViewData(我的第一个答案,我将留给发现此问题的其他人)。
当不涉及重定向时,原始答案仍然有用(GET 或 returns CurrentUmbracoPage()
的 POST)...
在很多情况下,您实际上是在执行子操作。通常你只有一层深度,但如果你混合使用宏和部分,你实际上可以获得多层深度。每个级别都有一个 ViewData,您必须使用 ParentActionViewContext
在堆栈中向上走才能到达您在控制器中填充的顶部 ViewData
。
请参阅 this comment from Shannon 对有关表面控制器和视图数据的问题的回答(Shannon 是 HQ 团队的核心贡献者,那里有很多很棒的内容)。此处引用:
If you want to access the ViewData that you've set on the master ViewContext's on a ChildAction being rendered from the master's ViewContext then you need to use @ViewContext.ParentActionViewContext.ViewData["ErrorMessage"]
The ParentActionViewContext in this example is the ViewContext that is rendering the Umbraco template, not the ChildAction. That is because when you POST (whether inside of Umbraco or normal MVC), you are posting to a new Action and the rendering process starts from scratch, when you validate your model, update the ViewData, etc... this all happens on what will become the 'master' ViewContext when the view renders. This view then will render your ChildAction.
Twamley 上面的回答非常好,除此之外,我发现使用 TempData.Add(key, value)
效果很好。
一个简单的骨头看起来像:
表面控制器
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>
}
我刚刚花了 2 个小时试图找出为什么当我将一个字符串放入 View 时。Bag/ViewData 在我的 Surface 控制器中,当我尝试在视图中取回该字符串时我得到 null。
最后我通过将字符串放入会话变量中解决了这个问题。
想知道为什么它不起作用,以及如何解决它。
提前致谢。
更新:你在post进行重定向吗?当您刷新表单时,它会再次提示您 posting 吗?如果不是,那是因为您不小心遵循了从表单 post 进行 302ing 的最佳实践(防止用户刷新和重新 posting 表单数据)。我为登录界面控制器所遵循的示例都使用了 return RedirectToCurrentUmbracoPage()
,我盲目地遵循了这一点。但是,顾名思义,真的是在做重定向,而且真的是两个请求! (我固执的要在Fiddler里验证才相信)。 ViewData 和 ViewBag 仅适用于一个请求——因此它们在 POST 302 中根本被破坏。会话适用于多个请求,这就是它对您有用的原因。 TempData 也适用于您,因为事实证明,TempData 是一种构建在会话之上的构造,专门设计用于在两个 post 之间传输状态(在检索时删除)。我在某处读到,TempData 最好命名为 RedirectData
,这有助于它为我点击。
因此,当您处理 Surface Controller 和 POSTing 时,您有三个我知道可行的选项:
- 会话(你证明有效)
- TempData(建立在会话之上,从我读到的内容来看,这既是最佳实践,也是专门针对这种情况而构建的)
- 在表单 post 中使用
return CurrentUmbracoPage();
。我刚刚在Fiddler中验证了这恰好是一个请求(在浏览器中刷新提示repost警告)。我还验证了 ViewData 以这种方式工作。但是,因为表面控制器是使用@Html.Action(...)
呈现为子动作,所以您必须使用ParentActionViewContext
才能获得正确的 ViewData(我的第一个答案,我将留给发现此问题的其他人)。
当不涉及重定向时,原始答案仍然有用(GET 或 returns CurrentUmbracoPage()
的 POST)...
在很多情况下,您实际上是在执行子操作。通常你只有一层深度,但如果你混合使用宏和部分,你实际上可以获得多层深度。每个级别都有一个 ViewData,您必须使用 ParentActionViewContext
在堆栈中向上走才能到达您在控制器中填充的顶部 ViewData
。
请参阅 this comment from Shannon 对有关表面控制器和视图数据的问题的回答(Shannon 是 HQ 团队的核心贡献者,那里有很多很棒的内容)。此处引用:
If you want to access the ViewData that you've set on the master ViewContext's on a ChildAction being rendered from the master's ViewContext then you need to use @ViewContext.ParentActionViewContext.ViewData["ErrorMessage"]
The ParentActionViewContext in this example is the ViewContext that is rendering the Umbraco template, not the ChildAction. That is because when you POST (whether inside of Umbraco or normal MVC), you are posting to a new Action and the rendering process starts from scratch, when you validate your model, update the ViewData, etc... this all happens on what will become the 'master' ViewContext when the view renders. This view then will render your ChildAction.
Twamley 上面的回答非常好,除此之外,我发现使用 TempData.Add(key, value)
效果很好。
一个简单的骨头看起来像:
表面控制器
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>
}