我正在尝试在一个表面控制器中编写一个childaction函数,该控制器由宏调用以呈现PartialView。
我需要在此函数中访问我当前的页面属性,然后调整渲染的PartialView。
我从Jorge Lusar的ubootstrap代码中得到了这个,它在HttpPost ActionResult函数上工作正常:
var renderModel = (UmbracoRenderModel)ControllerContext.RouteData.DataTokens["umbraco"];
var currentPage = renderModel.CurrentNode.AsDynamic();
问题是我在 [ChildActionOnly] PartialViewResult 函数上抛出此错误:
Unable to cast object of type 'System.String' to type 'Umbraco.Cms.Web.Model.UmbracoRenderModel'.
on 'var renderModel = (UmbracoRenderModel)ControllerContext.RouteData.DataTokens["umbraco"];'
DataTokens中的数据[“umbraco”]似乎在两个函数之间发生了变化。 如果我在每一个上显示 DataTokens [“umbraco”]。ToString(),则会发生以下情况:
On [ChildActionOnly] public PartialViewResult Init() - >显示“Surface”。
On [HttpPort] public HandleSubmit(myModel model) - >显示“Umbraco.Cms.Web.Model.UmbracoRenderModel”。
感谢您的任何建议。
尼古拉斯。
答案 0 :(得分:5)
我使用的是Umbraco 6.0.4,它很简单:
var currentNode = Umbraco.TypedContent(UmbracoContext.PageId);
答案 1 :(得分:2)
当我们丢失uformpostroutevals
的隐藏值时,我在Ajax Post中获取Surface Controller中的当前节点ID时遇到同样的问题。
即使我试图发布此值,也可以从表单中获取,由
呈现 @using (Html.BeginUmbracoForm("<ActionName>", "<Controller Name>Surface"))
我仍然在UmbracoContext
的所有属性中都为null,所以看起来它没有正确初始化。
HOTFIX :我将CurrentNodeId传递给我通过Ajax发送的每个表单:
在常规母版页中,我正在创建全局javascript对象:
<script type="text/javascript">
var Global = {
//..List of another variables which can be usefull of frontend
currentNodeId: @CurrentPage.Id
};
</script>
在任何请求中,Global.currentNodeId
作为data
的一个参数很容易使用var sendData = {
currentNodeId: Global.currentNodeId,
// another params
};
$.ajax({
method: 'POST',
data: JSON.stringify(sendData),
contentType: 'application/json; charset=utf-8',
url: '/Umbraco/Surface/<ControllerName>Surface/<ActionName>',
dataType: 'json',
cache: false
})
:
{{1}}
请注意它只是一个热门修复而不是一个合适的解决方案!
答案 2 :(得分:0)
要访问currentPage,请在Controller中实现此构造函数
public class CommentSurfaceController : SurfaceController
{
private readonly IUmbracoApplicationContext context;
public CommentSurfaceController(IUmbracoApplicationContext context)
{
this.context = context;
}
}
它使用umbracos依赖注入来解析Context依赖关系,并使你可以使用它。
查看SurfaceController上的文档 https://github.com/umbraco/Umbraco5Docs/blob/5.1.0/Documentation/Getting-Started/Creating-a-surface-controller.md
答案 3 :(得分:0)
虽然我更愿意找到一种更简单的方法,但我认为我找到了一个可行的解决方案。关键是要区分动作方法是作为子动作(通常是通过HTTP GET)调用还是直接(通过HTTP POST)。
以下是一个自定义基类,它公开一个“CurrentContent”属性,然后可以通过继承表面控制器来使用它。
using System.Web.Mvc;
using Umbraco.Cms.Web;
using Umbraco.Cms.Web.Surface;
using Umbraco.Cms.Web.Model;
namespace Whatever
{
public abstract class BaseSurfaceController : SurfaceController
{
private object m_currentContent = null;
public dynamic CurrentContent
{
get
{
if (m_currentContent == null)
{
if (Request.HttpMethod == "POST")
{
m_currentContent = GetContentForSubmitAction();
}
else
{
m_currentContent = GetContentForChildAction();
}
}
return m_currentContent;
}
}
// from Lee Gunn's response
// http://our.umbraco.org/forum/core/umbraco-5-general-discussion/29178-In-a-controller-how-do-I-get-the-current-pages-hiveId?p=2
private object GetContentForChildAction()
{
ViewContext vc = ControllerContext.RouteData.DataTokens[
"ParentActionViewContext"] as ViewContext;
var content = vc.ViewData.Model
as global::Umbraco.Cms.Web.Model.Content;
return content.AsDynamic();
}
// from Nicholas Ruiz
// http://our.umbraco.org/forum/core/umbraco-5-general-discussion/30928-Surface-Controller-and-Current-Node-Properties
private object GetContentForSubmitAction()
{
UmbracoRenderModel rm =
ControllerContext.RouteData.DataTokens["umbraco"] as UmbracoRenderModel;
if (rm == null)
{
return GetContentForChildAction();
}
return rm.CurrentNode.AsDynamic();
}
}
}
但是,似乎应该有一种更简单的方法来做到这一点。
布赖恩
答案 4 :(得分:0)
在Umbraco 7.2.1中,我使用ChildActionOnly属性并将模型传递给父级的部分视图。
[ChildActionOnly]
public ActionResult InitializeDataJson(KBMasterModel model)
{
var pluginUrl = string.Concat("/App_Plugins/", KBApplicationCore.PackageManifest.FolderName);
bool isAuthenticated = Request.IsAuthenticated;
IMember member = null;
if (isAuthenticated)
member = UmbracoContext.Application.Services.MemberService.GetByUsername(User.Identity.Name);
var data = new { CurrentNode = model.IContent, IsAuthenticated = isAuthenticated, LogedOnMember = member, PluginUrl = pluginUrl };
var json = JsonConvert.SerializeObject(data, Formatting.None, new JsonSerializerSettings() { ReferenceLoopHandling = ReferenceLoopHandling.Ignore });
var kbData = new TLCKBData() { InitializationJson = json };
return PartialView(kbData);
}
现在是部分视图代码:
@model TLCKBData
<script>
(function () {
var data = JSON.parse('@Html.Raw(Model.InitializationJson)');
tlckb.init(data);
})();
</script>
呈现子操作的父视图:
@section FooterScript {
@{Html.RenderAction("InitializeDataJson", "KBPartialSurface", new { model = Model });}
}
注意:我正在使用强大的模型,因为我已经路由劫持了我正在开发的插件的所有文档类型,但是如果我是路由劫持并且只使用UmbracoTemplatePage模型(默认在Umbraco中),那么我会更改参数我的孩子只采取RenderModel或UmbracoTemplatePage。
然后我会以同样的方式将模型传递给它。
因为它是表面控制器上的子操作,所以已经在Index中加载的模型只传递给子操作。这可以防止GetContent代码在管道中运行两次。
我这样做的原因是我需要一些基本数据来初始化我的角度API层。比如它是否经过身份验证,登录成员是谁等等。最终我在那里有一些标签,类别等等。
我也希望尽可能高效地构建插件,而不是冗余逻辑。我认为所有信息都在主视图模型上,为什么我要再查一次?就在那时我想出了如何做到这一点。
答案 5 :(得分:0)
var currentNode = Umbraco.TypedContent(UmbracoContext.PageId);
或者如果您在表面控制器中有对象
var currentNode = CurrentPage;
(转到定义)
//
// Summary:
// Gets the current page.
protected virtual IPublishedContent CurrentPage { get; }
请确保首先检查null,因为有一些实例可以在不解析currentPage上下文的情况下调用操作。
答案 6 :(得分:0)
这有助于我克服这一点。
在jquery包含之后,我添加了一个自定义标题标记,如下所示。
<script type="text/javascript">
$.ajaxSetup({
headers: { 'umbraco-page-id': '@CurrentPage.Id' }
});
</script>
&#13;
现在每个jquery帖子都会占用当前的umbraco页面。您可以从“请求标头”属性中访问此自定义标头。