将数据传递给所有页面通用的布局

我有一个网站,有一个布局页面。 然而,这个布局页面有数据,所有页面模型必须提供这样的页面标题,页面名称和我们实际上为HTML帮手执行某些操作的位置。 另外每个页面都有自己的视图模型属性。

我该怎么做? 这似乎是一个不好的主意,键入一个布局,但我怎么传递这些信息?

如果您需要将相同的属性传递给每个页面,那么创build所有视图模型使用的基本视图模型将是明智的。 你的布局页面可以采用这个基础模型。

如果在这个数据后面有逻辑要求,那么这个应该被放入一个由所有控制器使用的基础控制器。

有很多事情你可以做,重要的方法是不要在多个地方重复相同的代码。

编辑:从下面的评论更新

这是一个简单的例子来展示这个概念。

创build一个所有视图模型都将从中inheritance的基础视图模型。

 public abstract class ViewModelBase { public string Name { get; set; } } public class HomeViewModel : ViewModelBase { } 

你的布局页面可以把它作为模型。

 @model ViewModelBase <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>Test</title> </head> <body> <header> Hello @Model.Name </header> <div> @this.RenderBody() </div> </body> </html> 

最后在action方法中设置数据。

 public class HomeController { public ActionResult Index() { return this.View(new HomeViewModel { Name = "Bacon" }); } } 

我在布局中使用了RenderAction html helper作为剃刀。

 @{ Html.RenderAction("Action", "Controller"); } 

我需要它为简单的string。 所以我的行动返回string,并写下来容易在视图中。 但是,如果您需要复杂的数据,您可以返回PartialViewResult和模型。

  public PartialViewResult Action() { var model = someList; return PartialView("~/Views/Shared/_maPartialView.cshtml", model); } 

你只需要把你创build的局部视图'_maPartialView.cshtml'的模型开始

 @model List<WhatEverYourObjeIs> 

然后,您可以使用HTML在该部分视图模型中使用数据。

另一种select是创build一个单独的LayoutModel类,其中包含布局中需要的所有属性,然后将此类的一个实例填充到ViewBag中。 我使用Controller.OnActionExecuting方法来填充它。 然后,在布局的开始,您可以从ViewBag中取回这个对象,并继续访问这个强types的对象。

据推测,主要用例是为所有(或大部分)控制器操作获取基本模型。

鉴于此,我已经使用了几个这些答案的组合,主要支持科林培根的答案。

这是正确的,这仍然是控制器逻辑,因为我们填充视图模型返回到视图。 因此把这个放在控制器里的正确位置。

我们希望在所有的控制器上都发生这种情况,因为我们使用这个布局页面。 我正在使用它在布局页面中呈现的部分视图。

我们还想要一个强types的ViewModel的附加好处

因此,我创build了一个BaseViewModel和BaseController。 所有ViewModel控制器将分别从BaseViewModel和BaseControllerinheritance。

代码:

BaseController

 public class BaseController : Controller { protected override void OnActionExecuted(ActionExecutedContext filterContext) { base.OnActionExecuted(filterContext); var model = filterContext.Controller.ViewData.Model as BaseViewModel; model.AwesomeModelProperty = "Awesome Property Value"; model.FooterModel = this.getFooterModel(); } protected FooterModel getFooterModel() { FooterModel model = new FooterModel(); model.FooterModelProperty = "OMG Becky!!! Another Awesome Property!"; } } 

注意从这个SOpost中使用OnActionExecuted

HomeController的

 public class HomeController : BaseController { public ActionResult Index(string id) { HomeIndexModel model = new HomeIndexModel(); // populate HomeIndexModel ... return View(model); } } 

BaseViewModel

 public class BaseViewModel { public string AwesomeModelProperty { get; set; } public FooterModel FooterModel { get; set; } } 

HomeViewModel

 public class HomeIndexModel : BaseViewModel { public string FirstName { get; set; } // other awesome properties } 

FooterModel

 public class FooterModel { public string FooterModelProperty { get; set; } } 

Layout.cshtml

 @model WebSite.Models.BaseViewModel <!DOCTYPE html> <html> <head> < ... meta tags and styles and whatnot ... > </head> <body> <header> @{ Html.RenderPartial("_Nav", Model.FooterModel.FooterModelProperty);} </header> <main> <div class="container"> @RenderBody() </div> @{ Html.RenderPartial("_AnotherPartial", Model); } @{ Html.RenderPartial("_Contact"); } </main> <footer> @{ Html.RenderPartial("_Footer", Model.FooterModel); } </footer> < ... render scripts ... > @RenderSection("scripts", required: false) </body> </html> 

_Nav.cshtml

 @model string <nav> <ul> <li> <a href="@Model" target="_blank">Mind Blown!</a> </li> </ul> </nav> 

希望这有助于。

如果你想在布局中传递一个完整的模型:

 @model ViewAsModelBase <!DOCTYPE html> <html> <head> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta charset="utf-8"/> <link href="/img/phytech_icon.ico" rel="shortcut icon" type="image/x-icon" /> <title>@ViewBag.Title</title> @RenderSection("styles", required: false) <script type="text/javascript" src="http://code.jquery.com/jquery-1.8.3.min.js"></script> @RenderSection("scripts", required: false) @RenderSection("head", required: false) </head> <body> @Html.Action("_Header","Controller", new {model = Model}) <section id="content"> @RenderBody() </section> @RenderSection("footer", required: false) </body> </html> 

并将其添加到控制器中:

 public ActionResult _Header(ViewAsModelBase model) 

您不必混淆操作或更改模型,只需使用基本控制器并从layout viewcontext转换现有的控制器即可。

用所需的公共数据(标题/页面/位置等)和动作初始化创build一个基础控制器…

 public abstract class _BaseController:Controller { public Int32 MyCommonValue { get; private set; } protected override void OnActionExecuting(ActionExecutingContext filterContext) { MyCommonValue = 12345; base.OnActionExecuting(filterContext); } } 

确保每个控制器都使用基本控制器…

 public class UserController:_BaseController {... 

_Layout.cshml页面的视图上下文中_Layout.cshml现有的基础控制器…

 @{ var myController = (_BaseController)ViewContext.Controller; } 

现在,您可以从布局页面中引用基本控制器中的值。

 @myController.MyCommonValue 

其他答案几乎涵盖了我们如何将模型传递给布局页面的一切。 但是我find了一种方法,使用它可以dynamic地将variables传递到布局页面,而无需在布局中使用任何模型或局部视图。 让我们说你有这个模型 –

 public class SubLocationsViewModel { public string city { get; set; } public string state { get; set; } } 

你想要dynamic获取城市和州。 例如

在你的index.cshtml中,你可以把这两个variables放在ViewBag中

 @model MyProject.Models.ViewModel.SubLocationsViewModel @{ ViewBag.City = Model.city; ViewBag.State = Model.state; } 

然后在你的layout.cshtml中,你可以访问这些viewbagvariables

 <div class="text-wrap"> <div class="heading">@ViewBag.City @ViewBag.State</div> </div> 

我不认为这些答案对于大型企业级应用程序来说足够灵活。 我不是过度使用ViewBag的粉丝,但在这种情况下,为了灵活性,我会例外。 这就是我要做的…

你应该在你所有的控制器上都有一个基础控制器。 在您的基础控制器中添加您的布局数据OnActionExecuting(或OnActionExecuted,如果你想推迟)…

 public class BaseController : Controller { protected override void OnActionExecuting(ActionExecutingContext filterContext) { ViewBag.LayoutViewModel = MyLayoutViewModel; } } public class HomeController : BaseController { public ActionResult Index() { return View(homeModel); } } 

然后在你的_Layout.cshtml从ViewBag拉ViewModel …

 @{ LayoutViewModel model = (LayoutViewModel)ViewBag.LayoutViewModel; } <h1>@model.Title</h1> 

要么…

 <h1>@ViewBag.LayoutViewModel.Title</h1> 

这样做不会影响页面控制器或视图模型的编码。

创build一个代表布局视图模型的基本视图是一个可怕的方法。 想象一下,你想有一个模型,代表在布局中定义的导航。 你会做CustomersViewModel : LayoutNavigationViewModel ? 为什么? 为什么要通过解决scheme中的每个视图模型传递导航模型数据?

布局视图模型应该是专用的,并且不应该强制视图模型的其余部分依赖于它。

相反,您可以在_Layout.cshtml文件中执行此操作:

 @{ var model = DependencyResolver.Current.GetService<MyNamespace.LayoutViewModel>(); } 

最重要的是,我们不需要new LayoutViewModel() ,我们将得到所有的LayoutViewModel已经解决的依赖关系。

例如

 public class LayoutViewModel { private readonly DataContext dataContext; private readonly ApplicationUserManager userManager; public LayoutViewModel(DataContext dataContext, ApplicationUserManager userManager) { } } 

而不是通过这个,你总是可以使用另一种方法,也是快速的

在共享目录中创build一个新的局部视图,并在您的布局中调用您的局部视图

 @Html.Partial("MyPartialView") 

在你的局部视图中,你可以调用你的数据库并执行你想做的事情

 @{ IEnumerable<HOXAT.Models.CourseCategory> categories = new HOXAT.Models.HOXATEntities().CourseCategories; } <div> //do what ever here </div> 

假设你已经添加了你的entity framework数据库

你可以这样使用:

  @{ ApplicationDbContext db = new ApplicationDbContext(); IEnumerable<YourModel> bd_recent = db.YourModel.Where(m => m.Pin == true).OrderByDescending(m=>m.ID).Select(m => m); } <div class="col-md-12"> <div class="panel panel-default"> <div class="panel-body"> <div class="baner1"> <h3 class="bb-hred">Recent Posts</h3> @foreach(var item in bd_recent) { <a href="/BaiDangs/BaiDangChiTiet/@item.ID">@item.Name</a> } </div> </div> </div> </div>