Dynamic Menus in ASP.NET MVC 4 using EF Code First and jQuery

Posted by: Sumit Maitra , on 5/24/2012, in Category ASP.NET MVC
Views: 185757
Abstract: By default ASP.NET MVC Project Templates come with a Menu that is hardcoded for each controller. However in a real-life scenario, more often than not, we need our Menus to be dynamic and loaded and managed with certain amount of flexibility. In this article, we will see how to create a single level Dynamic Menu using EF code first and jQuery in an MVC Application.

 

Default static ASP.NET MVC Project Templates are a good starting point, however projects with even medium complexity need certain amount of flexibility. In this article, we will create a simple single level menu system that will group child menu items and give the flexibility of setting the Label, Action and Controller names at run-time.

This article uses the code from the Live Tile jQuery Plugin article that we wrote earlier on www.devcurry.com

The Backend

We will use SQL Server to store and EF to manage the Menu definitions. Our schema is as follows. The Menu class is our container or logical grouping for MenuItems.

menu-entity

MenuItems encapsulate the Item details:

  • Id - Identifier
  • Name – Label used in Menu
  • ActionName – Name of action to be invoked
  • ControllerName – Name of controller in which the action resides
  • Url – If Action Name is empty, one can provide a direct URL that the menu should point to.
  • ParentMenu – A navigation property to the container Menu

menu-item-entity

We persist them in SQL Server using EF Code First.

Building the UI for Administration of the Menus

We start off with our LiveTile project that was built from an empty MVC4 project. It has only got Index.cshtml under Home. We will build the Administration as well as the Menu on top of this.

Step 1: Copy the _Layout.cshtml and rename the new file as _LayoutAdmin.cshtml. Change the header to ‘LifeTile.js Admin’

Step 2: We create a Controller using the standard MVC Scaffolder that we can bring up by Right clicking on ‘Controllers’ folder and selecting ‘Add Controller’.

create-menu-controller

- Click on Advanced Options and select _LayoutAdmin.cshtml as the master page. This is important because we want the menu to be cached for regular pages that use the default master pages. On the other hand the Admin page will be setup to not use any caching so that changes to the Menu are reflected immediately.

setup-new-masterpage

- Finish the Controller creation by click the ‘Add’ button. This will scaffold all the methods and views required for Menu creation. Now we repeat the same for MenuItem and create a new controller MenuItemController using the same Data Context and the Admin specific master page.

create-menu-item-controller

Step 3: Next we update the connection string in the web.config by changing the Name to LiveTileDB and the connectionString to point to the correct catalog.

update-web-config

Step 4: Then we update the DBContext such that it uses the correct connection string. As seen below, we pass it to the base in the Constructor.

update-db-context

We have also overridden OnModelCreating and passed it the Initializer ‘CreateDatabaseIfNotExists’. This ensures EF simply creates the DB if it does not exist.

Step 5: MenuItems don’t really exist on their own, they HAVE to be a part of some Menu. So let’s delete the MenuItem\Index.cshtml.

Step 6: MenuItems instead will be shown in the Details page of the Menu. So we update the Menu\Details.cshtml as follows

menu-details-csthml

We are adding the rendering details for MenuItems in the Menu\Details page itself. Not only that, for each MenuItem, we are setting up the Edit and Delete action link that will enable us to Edit and Delete the MenuItems from the Details page itself. At the bottom we have also added the ‘Create’ MenuItem Action link.

Step 6: Update the MenuItem Controller. In the above step, we have seen that all the action links pass additional parameters for the HTTP GET operation. This is to let the controller know which Menu the Menu Item is associated to. To accommodate this, we update the MenuItemController as follows

Creation Action

menuitem-create-action

Edit Action

menu-item-edit-action

Delete Action

menu-item-delete-action

With the Details View and Controller setup like this, we are ready to create Menus and MenuItems. Run the Application and navigate to /Menu to get the following:

menu-admin-first

Click on Create New and add a new Menu called ‘Main’.

Click on the Details to get to the Details page.

menu-details

Click on Add Menu Item and add a MenuItem with Name = Home, Action=Index, Controller=Home.

Add another with Name = About, Action = About, Controller=Home. The Details page will now look as follows

menu-details-with-menu-items

So now our backend is all set with a Menu and a few MenuItems. Time to get the rendering work in place!

 

Rendering the Menu

Step 1: Add a Partial View called _MenuLayout.cshtml under the Views/Shared folder. Make it Strongly Typed of type Menu.

add-partial-menu-layout

Step 2: Update the View as follows

partial-view-markup

Thus the Menu is nothing but a List with each menu item being a list item.

Step 3: Update the HomeController.cs with the following action method

home-controller

This will be called to generate the PartialView of the Menu. Here we have ‘hardcoded’ the Menu name (‘Main’). The method returns just the HTML for the _MenuLayout.cshtml file with the given Model (menu).

Step 4: Update the _Layout.cs

Layout-header

Add a <nav> section with an empty div with id navcontainer. We will replace the contents of this div with the partial view.

Add the following JavaScript at the bottom of the _Layout.cs

partial-view-javascript

This script is nothing but a jQuery postback, it is fired once the document is loaded. And on a successful return ,it simply dumps the response HTML into the container.

Step 5: Update _LayoutAdmin.cs with the same except for one change in the JavaScript. We disable caching for the Admin pages.

cache-disabled

Step 6: Prettify it by updating the CSS for converting the <li> elements into a Tab layout.

That’s it, we are done. Run the Application to see the Menu getting rendered.

menu-Rendered

Navigate to the Admin page at /Menu, make some changes to the Name of the MenuItems and see them getting reflected immediately. Clicking on the Home link will navigate back to Home page. Clicking on About will throw an error because we don’t have an About page yet.

Conclusion

With that, we conclude this post. We saw how to create the backend and related admin screens for a simple Menu system for an ASP.NET MVC 4 application. We also saw how MVC partial views are used, how to deal with Master-Child UI by passing the Master’s Id around and last but not least, how jQuery can be used to do partial postback.

The entire source code of this article can be downloaded over here

See a Live Demo

Give a +1 to this article if you think it was well written. Thanks!
Recommended Articles
Sumit is a .NET consultant and has been working on Microsoft Technologies since his college days. He edits, he codes and he manages content when at work. C# is his first love, but he is often seen flirting with Java and Objective C. You can follow him on twitter at @sumitkm or email him at sumitkm [at] gmail


Page copy protected against web site content infringement by Copyscape


User Feedback
Comment posted by a on Monday, June 4, 2012 8:30 AM
hello , very intersting however the"Live Demo" has a "Internal Server Error"....
Comment posted by Sumit on Wednesday, June 6, 2012 4:37 AM
Hello a,
Yup, since it's open to modifications, if you change the Menu name from the default "Menu" it goes off the rockers. Simple fix to test it out is to have atleast One top level Menu's Name set as 'Main' :). I just fixed it back.

:)
Comment posted by Sergei on Tuesday, July 3, 2012 7:36 PM
Live Demo: Internal Server Error:)
Comment posted by Prakash Kumar on Thursday, July 5, 2012 12:39 AM
Nice concept  :)
Comment posted by Sumit on Thursday, July 5, 2012 2:37 AM
Thanks Sergei,
Thinking of Blocking users from making changes to 'Main' Menu :-). Or adding a admin page to allow them to select their top level Menus :-).

Thanks Prakash.

-Sumit.
Comment posted by Sumit on Thursday, July 5, 2012 5:03 AM
We have had to disable Add/Edit/Update/Deletes on the Demo site because of XSS attacks.

We get it the current code does not use Anti-XSS best practices, if we were to include all best practices of web development in every demo we did, the essence of the article would get lost.

It's a demo, let it remain one.
Comment posted by lol indus code on Tuesday, July 10, 2012 5:41 PM
omg my eyes, this is real indus code
Comment posted by Lucas on Wednesday, August 8, 2012 3:12 AM
Code and idea is really great!
But I have a problem.
How to store extra attributes in menu item like id or name. For example www.mysupersite.com/user/edit?id=3 where controller is user, action is edit and extra attribute (parameter) is id
Comment posted by Sumit on Sunday, August 12, 2012 3:42 PM
Hello Lucas,

You can add, additional attributes in the MenuItem for saving. To get those information in the menu like, look at Step 2. We are creating the Menu links using the Html.ActionLink(...). There is an overload to specify an anonymous object with name/value pairs that will be passed as query string. Use that overload to pass the additional information.

Hope this helps,
Sumit.
Comment posted by filz on Saturday, August 18, 2012 6:26 AM
very nice
http://www.woll-filz.com
Comment posted by José Jayo on Monday, November 19, 2012 3:06 PM
I would like information about Dynamic Menus in ASP.NET MVC 4
Comment posted by Oracularman on Wednesday, November 21, 2012 12:29 PM
Nice and Thank you very much Sumit. How do I sort the menu items in either the menuitemcontroller or menulayout.cshtml?
Comment posted by Oracularman on Friday, November 23, 2012 6:44 PM
How does one pass the ParentMenu ID to the Menuitems list in a seed() method?

Comment posted by Salamander on Monday, March 4, 2013 4:26 AM
In "Rendering the Menu", Step 4, when you say "update the _Layout.cs", do you mean _Layout.cshtml? And in Step 5, is it _LayoutAdmin.cshtml, not _LayoutAdmin.cs?
Comment posted by Satish on Monday, June 3, 2013 3:50 AM
Nice ...
Comment posted by AMS on Wednesday, June 19, 2013 6:31 PM
Hi @Sumit
I am trying to use your live demo. Tried to create a menu, but its not getting displayed. Can you please help me out with a brief description of how can i see the menu created in the live demo
Comment posted by josh on Friday, July 5, 2013 7:32 AM
good example.I found another good example in this link

http://articlesforprogramming.blogspot.in/2013/07/partial-view-in-aspnet-mvc4.html
Comment posted by bmi on Sunday, September 29, 2013 4:18 AM
不错的例子
Comment posted by Marcus on Tuesday, November 5, 2013 2:51 AM
One of the best navigation examples I have seen. I often wonder why there couldn't be a starter template with this kind of system.
Comment posted by Marcus on Tuesday, November 5, 2013 4:28 AM
One of the best navigation examples I have seen. I often wonder why there couldn't be a starter template with this kind of system.
Comment posted by Marcus on Tuesday, November 5, 2013 5:00 AM
Btw. Why using jquery rather than a Html.Action or Html.Partial?
Comment posted by parw on Wednesday, January 8, 2014 4:04 AM
I wanna create a vertical menu in asp.net with c#.....
plzzz suggest me steps for create a menu.
Comment posted by asadasdsad on Saturday, June 14, 2014 5:23 AM
ssdda sadsads
Comment posted by asadasdsad on Saturday, June 14, 2014 5:23 AM
ssdda sadsads

Post your comment
Name:  
E-mail: (Will not be displayed)
Comment:
Insert Cancel