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

时间:2022-01-12 15:16:34

I have MVC 3 C# project with Razor engine. What are the ways and, I guess, the best practices to write dynamic data to the _Layout.cshtml?

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

For example, maybe I'd like to display user's name in the upper right corner of my website, and that name is coming from Session, DB, or whatever based on what user is logged in.

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

UPDATE: I'm also looking for a good practice on rendering certain data into the element of the Layout. For example, if I need to render a specific CSS file depending on the logged-in user's credentials.

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

(For the example above, I thought of using Url Helpers.)

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

2 个解决方案

#1


19  

The default internet application created by visual studio use _LogOnPartial.cshtml to do exactly this.

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

The user Name value is set in the LogOn action of the HomeController

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

Code for _LogOnPartial.cshtml

_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 is part of the aspnet Membership provider.

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

Code for the _Layout.cshtml

_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>

Code for the AccountController Logon Action

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);
        }

Code for ApplicationViewPage class

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"]);
        }

    }

The above code allow me to have a ViewBag.LayoutModel that hold an instance of my LayoutModel class in every page.

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

Here is a code for my LayoutModel class

这是我的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;
            }
        }
    }

Here is the code to the View

这是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       
}

Refer to the following question for more detail. Make sure you modify your web.config as described there: How to set ViewBag properties for all Views without using a base class for Controllers?

有关更多详细信息,请参阅以下问题。确保修改web.config,如下所述:如何为所有视图设置ViewBag属性而不使用控制器的基类?

#2


1  

In addition to atbebtg's answer, to render stuff into the head, you want to leverage Razor's section support. Sections are named fragments of templated HTML that can be defined in views and rendered in the layout, where the layout sees fit. In the layout, you call @RenderSection("wellKnownSectionName") and in the view that uses the layout, you declare @section wellKnownSectionName { <link rel="stylesheet" href="@UserStylesheetUrl" /><script type="text/javascript" src="@UserScriptUrl"> }. Usually you want to describe the intention of the section in its name, such as "documentHead".

除了atbebtg的答案,要想把东西放到头脑中,你想要利用Razor的部分支持。节被命名为模板化HTML的片段,可以在视图中定义并在布局中呈现,布局认为适合。在布局中,您调用@RenderSection(“wellKnownSectionName”)并在使用布局的视图中声明@section wellKnownSectionName {

Update: If you're rendering the same templated HTML on every view, it would instead go into the layout. (Since your layout includes the HEAD and the BODY tags, you can just add the appropriate code to the HEAD tag their.) You just need to make sure you pass the information necessary for the layout from the controller via the ViewBag/View.Model/ViewData. So your layout would include this:

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

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

and your controller would include the logic to populate ViewBag.UserName:

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

ViewBag.UserName = Session["UserName"];

(Ideally you would use a strongly-typed view model and I would recommend you abstain from using Session for anything, since its benefits are small compared to alternatives and comes at a big cost to architecture... instead I would simply recommend storing some encrypted cookie on the browser that contains a username or something, which you can use on each page load to retrieve the user object from cache/db/service.)

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

#1


19  

The default internet application created by visual studio use _LogOnPartial.cshtml to do exactly this.

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

The user Name value is set in the LogOn action of the HomeController

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

Code for _LogOnPartial.cshtml

_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 is part of the aspnet Membership provider.

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

Code for the _Layout.cshtml

_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>

Code for the AccountController Logon Action

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);
        }

Code for ApplicationViewPage class

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"]);
        }

    }

The above code allow me to have a ViewBag.LayoutModel that hold an instance of my LayoutModel class in every page.

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

Here is a code for my LayoutModel class

这是我的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;
            }
        }
    }

Here is the code to the View

这是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       
}

Refer to the following question for more detail. Make sure you modify your web.config as described there: How to set ViewBag properties for all Views without using a base class for Controllers?

有关更多详细信息,请参阅以下问题。确保修改web.config,如下所述:如何为所有视图设置ViewBag属性而不使用控制器的基类?

#2


1  

In addition to atbebtg's answer, to render stuff into the head, you want to leverage Razor's section support. Sections are named fragments of templated HTML that can be defined in views and rendered in the layout, where the layout sees fit. In the layout, you call @RenderSection("wellKnownSectionName") and in the view that uses the layout, you declare @section wellKnownSectionName { <link rel="stylesheet" href="@UserStylesheetUrl" /><script type="text/javascript" src="@UserScriptUrl"> }. Usually you want to describe the intention of the section in its name, such as "documentHead".

除了atbebtg的答案,要想把东西放到头脑中,你想要利用Razor的部分支持。节被命名为模板化HTML的片段,可以在视图中定义并在布局中呈现,布局认为适合。在布局中,您调用@RenderSection(“wellKnownSectionName”)并在使用布局的视图中声明@section wellKnownSectionName {

Update: If you're rendering the same templated HTML on every view, it would instead go into the layout. (Since your layout includes the HEAD and the BODY tags, you can just add the appropriate code to the HEAD tag their.) You just need to make sure you pass the information necessary for the layout from the controller via the ViewBag/View.Model/ViewData. So your layout would include this:

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

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

and your controller would include the logic to populate ViewBag.UserName:

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

ViewBag.UserName = Session["UserName"];

(Ideally you would use a strongly-typed view model and I would recommend you abstain from using Session for anything, since its benefits are small compared to alternatives and comes at a big cost to architecture... instead I would simply recommend storing some encrypted cookie on the browser that contains a username or something, which you can use on each page load to retrieve the user object from cache/db/service.)

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