如何在MVC 3 Razor中将动态数据写入页面布局?

时间:2011-05-03 17:00:53

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

我有Razor引擎的MVC 3 C#项目。有什么方法,我想,将动态数据写入_Layout.cshtml的最佳做法是什么?

例如,也许我想在我网站的右上角显示用户名,并且该名称来自会话,数据库或其他基于用户登录的内容。

更新:我也在寻找将某些数据渲染到布局元素的良好做法。例如,如果我需要根据登录用户的凭据呈现特定的CSS文件。

(对于上面的例子,我想过使用Url Helpers。)

2 个答案:

答案 0 :(得分:19)

visual studio创建的默认互联网应用程序使用_LogOnPartial.cshtml来完成此操作。

用户名值在HomeController的LogOn操作中设置

_LogOnPartial.cshtml的代码

@if(Request.IsAuthenticated) {
    <text>Welcome <strong>@User.Identity.Name</strong>!
    [ @Html.ActionLink("Log Off", "LogOff", "Account") ]</text>
}
else {
    @:[ @Html.ActionLink("Log On", "LogOn", "Account") ]
}

User.Identity是aspnet成员资格提供者的一部分。

_Layout.cshtml的代码

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>@ViewBag.Title</title>
    <link href="@Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" />
    <script src="@Url.Content("~/Scripts/jquery-1.5.1.min.js")" type="text/javascript"></script>
    <script src="@Url.Content("~/Scripts/modernizr-1.7.min.js")" type="text/javascript"></script>
</head>
<body>
    <div class="page">
        <header>
            <div id="title">
                <h1>Test</h1>
            </div>
            <div id="logindisplay">
                @Html.Partial("_LogOnPartial")
            </div>
            <nav>
                <ul id="menu">
                </ul>
            </nav>
        </header>
        <section id="main">
            @RenderBody()
        </section>
        <footer>
        </footer>
    </div>
</body>
</html>

AccountController登录操作的代码

[HttpPost]
        public ActionResult LogOn(LogOnModel model, string returnUrl)
        {
            if (ModelState.IsValid)
            {
                if (Membership.ValidateUser(model.UserName, model.Password))
                {
                    FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);
                    if (Url.IsLocalUrl(returnUrl) && returnUrl.Length > 1 && returnUrl.StartsWith("/")
                        && !returnUrl.StartsWith("//") && !returnUrl.StartsWith("/\\"))
                    {
                        return Redirect(returnUrl);
                    }
                    else
                    {
                        return RedirectToAction("Index", "Home");
                    }
                }
                else
                {
                    ModelState.AddModelError("", "The user name or password provided is incorrect.");
                }
            }

            // If we got this far, something failed, redisplay form
            return View(model);
        }

ApplicationViewPage类的代码

public abstract class ApplicationViewPage<T> : WebViewPage<T>
    {
        protected override void InitializePage()
        {
            SetViewBagDefaultProperties();
            base.InitializePage();
        }

        private void SetViewBagDefaultProperties()
        {
            ViewBag.LayoutModel = new LayoutModel(Request.ServerVariables["SERVER_NAME"]);
        }

    }

上面的代码允许我有一个ViewBag.LayoutModel,它在每个页面中都包含我的LayoutModel类的实例。

这是我的LayoutModel类的代码

public class LayoutModel
    {
        public string LayoutFile { get; set; }
        public string IpsTop { get; set; }
        public string IpsBottom { get; set; }
        public string ProfileTop { get; set; }
        public string ProfileBottom { get; set; }

        public LayoutModel(string hostname)
        {
            switch (hostname.ToLower())
            {
                default:

                    LayoutFile = "~/Views/Shared/_BnlLayout.cshtml";
                    IpsBottom = "~/Template/_BnlIpsBottom.cshtml";
                    IpsTop = "~/Template/_BnlTop.cshtml";
                    ProfileTop = "~/Template/_BnlProfileTop.cshtml";
                    break;

                case "something.com":
                    LayoutFile = "~/Views/Shared/_Layout.cshtml";
                    IpsBottom = "~/Template/_somethingBottom.cshtml";
                    IpsTop = "~/Template/_somethingTop.cshtml";
                    ProfileTop = "~/Template/_somethingProfileTop.cshtml";
                    break;
            }
        }
    }

以下是View的代码

@{
    ViewBag.Title = "PageTitle";
    Layout = @ViewBag.LayoutModel.LayoutFile; 
}
@using (Html.BeginForm())
{
    <span class="error">@ViewBag.ErrorMessage</span>
    <input type="hidden" name="Referrer" id="Referrer" value="@ViewBag.Referrer" />
    html stuff here       
}

有关详细信息,请参阅以下问题。确保按照以下所述修改web.config:How to set ViewBag properties for all Views without using a base class for Controllers?

答案 1 :(得分:1)

除了atbebtg的答案,要想把东西放到头脑中,你想要利用Razor的部分支持。节被命名为模板化HTML的片段,可以在视图中定义并在布局中呈现,其中布局适合。在布局中,您调用@RenderSection("wellKnownSectionName"),在使用布局的视图中,您声明@section wellKnownSectionName { <link rel="stylesheet" href="@UserStylesheetUrl" /><script type="text/javascript" src="@UserScriptUrl"> }。通常,您希望在其名称中描述该部分的用意,例如“documentHead”。

更新: 如果您在每个视图上呈现相同的模板化HTML,则会转到布局中。 (由于您的布局包含HEAD和BODY标记,您只需将相应的代码添加到HEAD标记中即可。)您只需确保通过ViewBag / View.Model从控制器传递布局所需的信息。 / ViewData的。所以你的布局包括:

<head>
    <link rel="stylesheet" href="/css/@ViewBag.UserName/.css"/>
</head>

并且您的控制器将包含填充ViewBag.UserName的逻辑:

ViewBag.UserName = Session["UserName"];

(理想情况下,你会使用一个强类型的视图模型,我建议你不要使用Session做任何事情,因为它与其他选择相比它的好处很小,并且建筑成本很高......相反,我只是建议在浏览器上存储一些加密的cookie,其中包含用户名或内容,您可以在每个页面加载时使用这些cookie来从cache / db / service检索用户对象。)