我正在寻找一种方法来处理ASP.NET MVC中不违反MVC原则的数据库驱动菜单。我想用我的数据库中的东西替换硬编码的默认“Home,About”菜单。我该如何连线?我会在Site.Master中设置一个ContentPlaceHolder并在我的视图中重新生成吗?这对我来说似乎不对。
答案 0 :(得分:2)
我的主菜单是一个ViewUserControl,它在我的MasterPage中呈现为部分视图。尽管我的是硬编码的,但您可以从ViewData轻松生成它。从视图数据生成它可能涉及实现自定义FilterAttribute,该自定义FilterAttribute指定用于生成将应用于每个控制器/操作的菜单的参数,或者,如果每个页面上的菜单相同,则实现填充的基本控制器在视图数据中,通过重写OnActionExecuted并添加到其中的ViewData。
示例(注意,您可能会使用缓存来获取结果,而不是每次都从数据库中获取它们。)
模型类
public class MenuItem
{
public string Text { get; set; }
public string Action { get; set; }
public string Controller { get; set; }
}
public class Menu
{
public string Heading { get; set; }
public IEnumerable<MenuItem> Items { get; set; }
}
MenuControl.ascx:类型System.Web.Mvc.ViewPage<List<Menu>>
<div id="mainMenu">
<% foreach (var menu in Model) { %>
<div class="menu">
<h2 class="menu-heading"><%= menu.Heading %></h2>
<% foreach (var item in Model.Items) { %>
<%= Html.ActionLink( item.Text,
item.Action,
item.Controller,
null,
{ @class = "menu-item" } ) %>
<% } %>
</div>
<% } %>
</div>
母版
<html>
<head>
...
<asp:ContentPlaceHolder runat="server" id="HeaderContent">
</head>
<body>
... other HTML...
<% Html.RenderPartial( "MenuControl", ViewData["mainMenu"], ViewData ); %>
<asp:ContentPlaceHolder runat="server" id="BodyContent" />
... more HTML ...
</body>
</html>
BaseController
public override void OnActionExecuted( ActionExecutedContext filterContext )
{
if (filterContext != null)
{
var context = filterContext.Result as ViewResult;
if (context != null) {
context.ViewData["mainMenu"] =
db.MenuData.Where( m => m.Type == "mainMenu" )
.Select( m => new Menu {
Heading = m.Heading,
Items = db.ItemData.Where( i => i.MenuID == m.MenuID )
.OrderBy( i => i.Name )
.Select( i => new MenuItem {
Text = i.Text,
Action = i.Operation,
Controller = i.Table
})
});
}
}
}