MVC表面控制器& Umbraco当前节点

时间:2012-04-20 14:06:55

标签: asp.net-mvc umbraco

我正在尝试在一个表面控制器中编写一个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”

感谢您的任何建议。

尼古拉斯。

7 个答案:

答案 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包含之后,我添加了一个自定义标题标记,如下所示。

&#13;
&#13;
    <script type="text/javascript">
        $.ajaxSetup({
            headers: { 'umbraco-page-id': '@CurrentPage.Id' }
        });
    </script> 
&#13;
&#13;
&#13;

现在每个jquery帖子都会占用当前的umbraco页面。您可以从“请求标头”属性中访问此自定义标头。