【问题标题】:Embedded code in Razor _Layout.cshtmlRazor _Layout.cshtml 中的嵌入代码
【发布时间】:2012-03-27 22:56:53
【问题描述】:

我正在开发一个 MVC3 Razor Web 应用程序,该应用程序从 Java 内容管理系统获取页面装饰。由于每个页面都共享此装饰,因此我已将 CMS 内容的检索放在 _Layout.cshtml 文件中,但我对已实现的代码并不完全满意...

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    @{
        -- The first two lines are temporary and will be removed soon.
        var identity = new GenericIdentity("", "", true);
        var principal = new GenericPrincipal(identity, new string[] { });
        var cmsInterface = MvcApplication.WindsorContainer.Resolve<ICMSInterface>();
        cmsInterface.LoadContent(principal, 2);
     }
     @Html.Raw(cmsInterface.GetHeadSection())
 </head>

<body>
    @Html.Raw(cmsInterface.GetBodySection(0))
    @RenderBody()
    @Html.Raw(cmsInterface.GetBodySection(1))
</body>
</html>

由于 _layout 文件没有控制器,我看不到我可以将代码放在哪里进行检索。以下是我考虑过的几件事:

  • 以单独的部分检索 CMS 内容,因此我不需要 LoadContent 调用。不幸的是,由于我必须使用组件来检索 CMS 内容,这是不可能的,要么全有,要么全无。
  • 使用局部视图,以便我可以使用控制器。因为我需要将整个页面放入部分页面,所以该选项似乎有点荒谬。
  • 在某个帮助程序类上调用单个静态方法,该方法检索数据并将三个部分添加到 ViewBag。这将允许我将代码移出视图,感觉是最好的解决方案,但我仍然对它不是特别满意。

有没有人有其他建议/cmets?

【问题讨论】:

    标签: asp.net-mvc razor


    【解决方案1】:

    您可以使用全局操作过滤器将所需的数据添加到所有控制器中的 ViewBag:

    public class LoadCmsAttribute : ActionFilterAttribute
    {
        public override void OnResultExecuting(ResultExecutingContext filterContext)
        {
            if (!filterContext.IsChildAction &&
                !filterContext.HttpContext.Request.IsAjaxRequest() &&
                filterContext.Result is ViewResult)
            {
                var identity = new GenericIdentity("", "", true);
                var principal = new GenericPrincipal(identity, new string[] { });
                var cmsInterface = MvcApp.WindsorContainer.Resolve<ICMSInterface>();
                cmsInterface.LoadContent(principal, 2);
    
                var viewBag = filterContext.Controller.ViewBag;
                viewBag.HeadSection = cmsInterface.GetHeadSection();
                viewBag.FirstBodySection = cmsInterface.BodySection(0);
                viewBag.SecondBodySection = cmsInterface.BodySection(1);
            }
        }
    }
    

    全球.asax:

    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        ...
        filters.Add(new LoadCmsAttribute());
    }
    

    【讨论】:

    • 这看起来是一个很好的解决方案,但我是否认为这会发生在每个操作中?我不希望代码为任何部分视图或 json 操作执行。
    • 我已经更新了代码,所以它只在正常操作时执行。
    【解决方案2】:

    一种解决方案:

    1. 创建每个控制器都继承自的基本控制器。
    2. 覆盖 OnActionExecuted 或类似概述
    3. 在覆盖的代码中将数据添加到 ViewBog 或 ViewData

    每次调用操作时都会运行 OnActionExecuted 代码,因此您可能需要执行一些检查以确保操作将返回视图等。可能有更好的覆盖 OnActionExecuting、OnResultExecuting 等,但仅此而已我想到了一个。

    另一种解决方案:

    创建一个过滤器属性,你可以用它来装饰你的控制器。

    http://www.asp.net/mvc/tutorials/older-versions/controllers-and-routing/understanding-action-filters-cs

    如果您不想要基本控制器,这可能是一个更好的解决方案。

    【讨论】:

      【解决方案3】:

      *"因为 _layout 文件没有控制器".* 关键是你的假设并不完全正确!事实上,在控制器的帮助下填充 _Layout 页面是很常见的。让我们想想很多网站的登录/注销矩形......它通常放在 _Layout 中并由控制器处理。 没有控制器将 ViewModel 传递给 Layout...仅仅是因为 Layout...只是...一个 Layout 而不是传达信息的东西...howeber 它可以是其他内容的“容器” turn 可能有一个 ViewModel。 在实践中,您可以使用 Html.Action 或 Html.RenderAction 从 _Layout 调用子控制器...这是大多数 asp.net Mvc 网站中处理登录的方式...我建议您也这样做为您的内容...通过调用专门的子控制器来填充您的内容,一个用于布局页面的每个不同“区域”。

      【讨论】:

      • 这样做的唯一问题是我需要将数据传递给所有不同的控制器操作,因为我只想调用一次 LoadContent 方法。我是否误解了您建议的解决方案中的某些内容?是否可以在不同的控制器动作之间传递状态数据(不使用 viewbag)?
      • 可能你误解了我的建议。 Probaby 你只需要 1-2 个控制器。 1-2 之间的选择...仅取决于模块化问题...取决于您的选择。只需在您的 _layout 中放入一个仅调用一个控制器的 Html.Action 或 Html.RenderAction。这样,您将始终拥有相同的控制器填充您的 _layout 的一部分......这意味着相同的控制器为使用该 _layout 页面的所有视图执行工作。如果您希望多个控制器分别填充 _layout 的不同部分,您也可以选择使用多个 Html.Action。这取决于您。
      【解决方案4】:

      看来你的答案可能在这里:child action that obviates need for base controller.

      【讨论】:

        猜你喜欢
        • 2023-03-30
        • 2013-09-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-04-27
        相关资源
        最近更新 更多