Best way to wire up database-driven menu in ASP.NET MVC

前端 未结 1 1493
慢半拍i
慢半拍i 2021-02-03 15:54

I\'m looking for a way to handle a database-driven menu in ASP.NET MVC that doesn\'t violate the MVC principles. I want to replace the hard-coded, default, \"Home, About\" menu

相关标签:
1条回答
  • 2021-02-03 16:28

    My main menu is a ViewUserControl that is rendered as a partial view in my MasterPage. Although mine is hard-coded, you could easily generate it from ViewData. Generating it from view data would probably involve implementing either a custom FilterAttribute that specified the parameters to use in generating the menu that would be applied to each controller/action or, if the menu is the same on each page, implementing a base controller that fills in the view data by overriding OnActionExecuted and adding to the ViewData in it.

    Example (note, you'd probably use caching for the results instead of getting them from the db each time).

    Model classes

    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 : of type 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>
    

    MasterPage

    <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
                                                   })
                                });
             }
        }
    }
    
    0 讨论(0)
提交回复
热议问题