【问题标题】:Passing Data to a Layout Page将数据传递到布局页面
【发布时间】:2012-05-20 02:49:28
【问题描述】:

我有一个layout 页面,其中包含需要填充的变量。示例:

@ModelType KarateAqua.schoolModel

<html>
    <body>

        @RenderBody()

        <div id="footer">
            <div class="content">
                <div class="bottom_logo">
                    <a href="/"><span class="inv">@Model.schoolName</span></a>
                </div>
            </div>
        </div>
    </body>
</html>

我不想在每个ActionResult 中填充它。有没有办法一次将数据传递到layout 页面并为所有实例执行此操作?

【问题讨论】:

标签: asp.net .net asp.net-mvc-3 razor


【解决方案1】:

创建一个动作过滤器并装饰您的控制器类。在 action 过滤器中,您可以将值放入 viewbag 中,这些值可用于您的布局。

这将在每个请求上运行,您不必在每个操作中设置值。您可以查找并忽略诸如子请求和 ajax 请求之类的东西,它们通常不使用布局,也不为它们设置 viewbag 值。

下面是我创建的一个属性示例,用于从会话中复制一个对象并通过 ViewBag 使其可用于布局

public class CurrentUserAttribute : ActionFilterAttribute
{
    public override void OnResultExecuting(ResultExecutingContext filterContext)
    {
        // Don't bother running this for child action or ajax requests
        if (!filterContext.IsChildAction && !filterContext.RequestContext.HttpContext.Request.IsAjaxRequest())
        {

            if (filterContext.HttpContext.Session != null)
            {
                var currentUser = filterContext.HttpContext.Session["CurrentUser"] as CurrentUser;
                if (currentUser != null)
                {
                    filterContext.Controller.ViewBag.CurrentUser = currentUser;
                }
            }
        }
    }


}

【讨论】:

  • 这不是很干净(不是强类型等),但它是我发现的最干净的。谢谢。
【解决方案2】:

好的,因为您希望在可以使用局部视图后对其进行设置。但是,根据您的需要,您将需要有几个部分视图(如果部分将分散在 _layout 页面中,可能并不理想)

你的局部视图看起来像

@model KarateAqua.schoolModel

<div class="bottom_logo">
<a href="/"><span class="inv">@Model.schoolName</span>
</div>

控制器

public class SchoolController : Controller
{
     public ActionResult Index()
     {
          //get schoolModel  
          return PartialView(schoolModel);
     }
}

在您的 _layout.cshtml 中将此行放置在您想要插入局部视图的位置

@Html.Action("Index","School")

【讨论】:

    【解决方案3】:

    您可以在布局页面上打开一个代码块并在那里填充对象。这将在每次使用布局页面时执行。好处是您不必更改控制器上的任何内容:

    @{
        KarateAqua.schoolModel data = YourBusinessLayer.Method();
    }
    
    <html>
    <body>
    
        @RenderBody()
    
        <div id="footer">
            <div class="content">
                <div class="bottom_logo">
                    <a href="/"><span class="inv">@data.schoolName</span></a>
                </div>
            </div>
        </div>
    </body>
    </html>
    

    【讨论】:

    • 只有当 imo 没有其他选项可用时,才应使用视图中的代码块。你会让视图太聪明。它是一个视图,它应该基于一个足以在没有代码块的情况下工作的模式呈现数据。
    【解决方案4】:

    您可以使用ViewBagViewData 将数据传递到您的布局页面。

    布局

    <html>
    <body>
    @RenderBody()
    
    <div id="footer">
    <div class="content">
    <div class="bottom_logo">
    <a href="/"><span class="inv">@ViewBag.schoolName</span>
    </div></div></div>
    </body>
    </html>
    

    控制器

    public ActionResult Index(){
       ViewBag.schoolName = "Bayside Tigers";
       return View();
    }
    

    【讨论】:

    • 但是我必须为每个控制器操作都这样做吗?
    • 是的,就像您必须为每个操作返回一个模型一样。
    • 糟糕的软件设计。
    • @CMate - 差评
    • @Gabe,请稍微了解一下可重用性,这是创建具有可持续可维护性的软件时的一个关键方面。它显示了一个非常糟糕的软件设计,当一个代码段必须在每个操作方法的末尾重复,这使得它变得多余且难以维护。当 ASP.NET MVC 框架提供基类来避免这种糟糕的编程方案时,情况尤其糟糕。有关该主题的详细信息,请参阅 MSDN 上的 ActionFilterAttribute 类。 JBeckton 的回答中也提出了这一点。
    【解决方案5】:

    您的布局页面:

    @ViewBag.LayoutVar
    

    您的 HomeController:

    public class HomeController : BaseController
    {
       //Here some logic...
    }
    

    你的 BaseController

    namespace ProjectName.Controllers
    {
        public class BaseController : Controller
        {
    
            public YetkiController()
            {
                //This parameter is accessible from layout
                ViewBag.LayoutVar = "Suat";
            }
        }
    }
    

    逻辑很简单:您创建 BaseController,其中包含您将在布局中使用的每个全局参数。 (如用户名或其他基于数据的参数)

    您继承(调用)BaseController 以将所有参数放入当前控制器。

    【讨论】:

      【解决方案6】:

      您始终可以创建返回部分标题视图的操作。

      只需将此添加到您的layout 页面:

      <html>
          <head> 
          </head>
              <body>
                  @{ Html.RenderAction("header", "MyController", new { area = "" }); }
      
                  @RenderBody()
      //...
      

      【讨论】:

        【解决方案7】:

        我使用HTTP Session在不同页面之间持久化数据 -

        //Opening page controller
        public ActionResult Index()
        {    
            Session["something"]="xxxx";
            return View();
        }
        

        在共享的_layout页面中;

        //persistent data   
        <p>Hello, @Session["something"]!</p>
        

        希望这会有所帮助,但如果您从与已设置的默认页面不同的页面开始,它将不起作用。

        【讨论】:

          猜你喜欢
          • 2020-10-15
          • 2020-07-16
          • 1970-01-01
          • 2021-10-21
          • 1970-01-01
          • 1970-01-01
          • 2018-10-18
          • 2021-08-30
          • 1970-01-01
          相关资源
          最近更新 更多