Connecting SQL Source Control to Git in Team Foundation Service

Team Foundation Service is Microsoft’s hosted TFS, and supports both Git and TFS source control.  TFS(ervice) is free for teams up to five, and all repos are private.  If you need a Team Foundation Service account, go to http://tfs.visualstudio.com and log in with your Microsoft ID.  If you’re using Git, you’ll also need to create an alternate set of credentials to connect to the repo.

In SQL Source Control, Git is now a top-level provider, but full Git support hasn’t been implemented yet (Subversion and TFS have much better support in the current version, 3.4 at the time of this post).  For the current version of SQL Source Control, you’ll still need to switch to your favorite Git tool for add/commit/push.  Upcoming features in SQL Source Control for Git include better branching support and support for migrations.  Migrations allow you to alter schema objects without dropping them first—like changing the name of a table without dropping it first—as well as seeding initial data.

1. Create project in TFS

image

 

2. Navigate to Code tab, clone the repo in your favorite Git tool using the URL provided.  TFS only supports HTTPS right now, so you need a set of alternate credentials to use Git.

image

image

 

3. In SSMS, right-click the database you want to put under source control and select “Link database to source control”.

image

 

4. Then, browse to your working folder and select whether each developer will have their own copy of the database, or everyone will work from one central database.

image

 

5. Once the database has been linked, click on the “Commit Changes” tab and choose “Save Changes”.  For a Git repo, this just saves the script files—you still need to do an add, commit and push in your favorite tool.

image

 

6. Once you’ve done an add/commit/push, you can log into TFS again and use all the functionality of diffs, history tracking, etc.  Your other team members can pull from this repo and use SQL Source Control to easily keep their instances up to date.

TryParse() in one line–when to use it, when to avoid it

Note: The code samples shown below are meant to run in LinqPad as “C# Statements”. You can use the free version, but it’s well worth paying for.

Almost all types (every one I can think of, but I’m not going to commit and say “all”) have both a .Parse() and .TryParse() method, the differences between which are discussed at http://stackoverflow.com/questions/467613/parse-v-tryparse. As a general rule, we try and use .TryParse() everywhere.

The one down side to .TryParse() is that it requires a little extra code–an output variable, and a result variable, and you’ll probably need to set a default value in case the parsing fails. You can accomplish this in one line of code with the right syntax that at first doesn’t look like it should work.

Here’s an example of how to do .TryParse() in one line, showing a syntax which works and one which doesn’t (.Dump() is a method specific to LinqPad).

string _int = "8675309";

int i1 = int.TryParse(_int, out i1)
	? i1
	: 0;
i1.Dump();

Output: 8675309

//This doesn't work
//var i2 = int.TryParse(_int, out i2)
//	? i2
//	: 0;
//i2.Dump();

It’s interesting how the explicitly typed variable works, but the implicitly typed one doesn’t. The same thing happens with a GUId:

string _guid = "d09eccda-533a-4772-b589-dbc5676fb690";

//This works
Guid g1 = Guid.TryParse(_guid, out g1) 
	? g1 
	: Guid.Empty;
g1.Dump();

output: d09eccda-533a-4772-b589-dbc5676fb690

//This does not:
//var g2 = Guid.TryParse(_guid.ToString(), out g2)
// 	? g2
// 	: Guid.Empty;
//g2.Dump();

So we know implicit typing isn’t going to work. Are there any other places we’ve found you need to be careful? Yes, one more so far–Booleans. Based on the patterns above, you’d expect this to work:

string _bool = "false";
bool b1 = bool.TryParse(_bool, out b1);
b1.Dump();

output: true

Go try that in LindPad and see what happens. Spoiler alert: b1 is true, not false. The result of .TryParse() is a Boolean, and instead of assigning the output value to b1, the result is being assigned to b1. Instead, you need to use the longer syntax to make Booleans work correctly:

string _bool = "false";
bool b2;
bool b3 = bool.TryParse(_bool, out b2);
b2.Dump();
b3.Dump();

output: true
false

That will end up with the correct values assigned.

So there you have it–how to handle a .TryParse() in one line, and a couple of pitfalls in doing so. Hope that helps!

Slides from “An Agile Retrospective” at codepaLOUsa 2013

One of the major take-home stories not me toned in the slides is to not define your identity by your process. Don’t trap yourself in a less than optimal process by proclaiming it’s the right way, or the one true way. From the start, accept the idea (and let others know) that your overall process is a slowly changing dimension in your enterprise. Leave yourself room to adapt and grow as you and your team becomes more practiced and new tools/techniques emerge.

If you attended my talk, I deeply apologize for the technical issues. Karma’s a bitch, for sure. Run-through in my room before the talk went great, with the most up-to-date slides. Being too smart to leave Powerpoint open while I came downstairs, I closed everything down. Joking with Steve from Geeks and Gurus about his projector and my new laptop was all in fun (Steve and I have known each other for several years now, poking fun at one another is nothing new). Perhaps also making sarcastic remarks about demo gremlins, Windows 8 and the conference wifi was tempting fate a little too much. I’m still perplexed as to whether “Your changes cannot be discarded” would have been a good thing or a bad thing. In addition to the out of date slide deck I had to use, this website was down, and my laptop blue screened right as I walked out of the room. So it was exciting. From what I can gather, between the time I logged onto the conference wifi and opening my slides I must have been knocked off the network, so a local cache of an older version was found, and why I could never get the latest slides loaded. My laptop wasn’t displaying that I was disconnected, the cause of which may have been part of the BSOD.

Anyhow, my site seems to be working again, I got the laptop happy and was able to recover the correct slides from SkyDrive. Without further ado, here are the annotated slides for An Agile Retrospective. Note: file is hosted on SkyDrive, but it should be a public link.

Where are all the pretty apps? I think they’re coming.

Mobile has been on my mind a lot lately.  A good friend hooked me up with an HTC 8x recently for some side projects, and recently dangled a Win 8 Pro tablet in front of me.  I use an iPad nearly constantly, and the third birthday of the iPad was just a few days ago.  I just replaced my trusty Droid 4 with an iPhone 5, and I’ve just replaced my 6 year old “built for Windows XP” laptop with a new Windows 8 ultrabook.  I’ve also recently started on Pinterest.  So much change at once!  More on all of these below—there is a point.

I adore my iPad.  No understatement that I would anoint it “greatest invention ever (recently)”.  I am very productive, and I can be entertained in one compact yet powerful device.  The iPad itself is a larger extension of the iPhone, which is about ready to celebrate its sixth birthday.  Apple’s strategy with the first iPad release was great—make sure it can run nearly all iPhone apps, as well as provide great new capabilities for better enjoyment and productivity.  I think the results speak for themselves.  When you look in the App Store, you find so many beautiful applications for both iPhone and iPad you are amazed and thrilled.  It’s exciting.  iPhone and iPad have been so successful that they’re driving sales of Macs at a record pace.  All of this has built a vibrant culture of third party add-ons and apps.  It’s the envy of the industry.

On the other hand, Microsoft and Beauty have never gone hand-in-hand, and Microsoft’s “protect Windows at all costs” culture has led to a high cost of talent shrink an lost opportunities.  My first smartphone was the Palm Treo 700w (at that time, Palm ruled the industry).  Based on Windows CE, it had some nice functionality at the time, but left a lot to be desired (so did the rest of the Palm offerings).  It was cool back then, barely “meh” by today’s standards.  Windows Phone (CE) 6 is barely a footnote, Windows 7 felt rushed and incomplete, while Windows Phone 8 is just great.  Except for one thing—where are the apps?  Don’t get me wrong, the quantity is there, but not necessarily the quality.  Apple’s App Store is filled with thousands and thousands of high quality apps built by people actually making a fine living doing so.  The Windows Phone Store is filled with thousands and thousands of apps built by first-time phone devs mainly to participate in one of the numerous contests or hackathons being held. 

On a supposed-to-be-related-but-aren’t-yet note, Windows 8 shipped last year also, and Microsoft unleashed a strategy only a committee could dream up.  One flavor of Windows 8 runs on traditional PC/laptops and some tablets, and is both backwards-compatible with Windows 7 applications and with the new Windows Store apps.  Another flavor of Windows 8 (RT) looks exactly the same, runs primarily on tablets, but can’t run any legacy applications—just the Windows Store apps.  Neither flavor of Windows 8 will run Windows Phone 8 apps, nor will WP 8 run Windows Store apps.  It’s a very confusing strategy to say the least, and I think in the short term has hurt quick adoption of any of the three platforms.

image

That’s not so say there aren’t already great apps for WP8 or Win 8.  Some WP 8 apps are quite good—there is no official Pinterest app, but the Pinsation app is actually so much better I wish it were on the iPhone.  But they are rare.  Most apps, while providing some useful functionality, are just unattractive.  Beauty generates excitement, and that’s why Microsoft’s seeming aversion to beauty has failed to build a base as excited as Apple’s.  However, I think this is about to change.  And here’s why: http://cacoe.deviantart.com/art/Decor8-Metro-White-Start-Screen-340446302 (as found at http://pinterest.com/pin/403424079090833867/).  This is an artist’s concept of a whit start screen for Windows 8.  Then there’s http://designmodo.com/flat-free/ (found via http://pinterest.com/pin/403424079090835061/).  Flat UI is a PSD swatch of Metro-inspired icons and colors.  And there are more of the same on the Technology and Design boards.

image

In just a few short months, Win 8 and WP 8 iconsets (like http://zainadeel.deviantart.com/art/Metro2-for-Superbar-294707841, found via http://pinterest.com/pin/403424079090833846/) and conceptual designs have started to show up more and more.  Designers are taking note of the new platforms.  It’s important that talented designers are creating designs, it’s even more important these designs are being noticed and consumed.  I think this bodes well for the “Ocho” ecosystems.  Going into this summer’s Build, I think we’ll begin to see a few of the unexpectedly beautiful, didn’t-know-you-needed-it apps from third party developers.  They’ll be exciting in a way, and I think will be at the leading edge of big change in the Ocho app stores in terms of app design and quality.  And that will be very exciting.

image

Yahoo’s Opportunities

I’m writing this as both a consumer of online services as well as the hypothetical “what I’d do if I were the CEO” scenario.  It’s nothing more than armchair quarterbacking.  Also, I started this post before news of Yahoo’s acquisition of Summly broke, and rumors of Zynga and DailyMotion began.

There was little doubt in my mind that Marissa Mayer was a great choice to lead Yahoo.  I can only imagine the morale and culture after the least few years.  And, even though I’m a remote worker myself (not for Yahoo), I agree with her decision to pull in all the remotes.  Yahoo needs to come together if it wants to survive.

It’s a sad fall for a site which was the first real start page for the Internet, the first free email on a grand scale, the first real customizable portal.  The gold standard with the six second load time, and the your-site-is-invisible-until-it’s-in-the-Yahoo-directory site.  And YUI and Douglas Crockford and JSON.  Delicious and Flickr made sense, and there is still so much to like.

We’ll know if Yahoo has it’s shit together in the next few months.  Google reader closing is a prime opportunity, even some industry pundits are saying that despite declining usage closing Reader is a bad ideaFeedly picked up 500K new users in 48 hours and Digg is adding its own RSS reader.  No migrant user is truly committed yet—people are shopping around for a replacement they like.  There is plenty of opportunity, but services have only until May 31.  A My Yahoo user could always add RSS to your My Yahoo page, but I stopped using online portals several years ago like everyone else as I began to use a tablet and touch apps more and more.

Yahoo needs a good mobile strategy.  I wouldn’t be looking to build a legion of delusional fanbois, but anyone who isn’t productive on a tablet is on shaky ground these days.  Yahoo has the content and services, it just needs to get them back in people’s hands.  There are a few Yahoo mobile apps, but so much room for more.

Yahoo has done its share of spring cleaning in the past, but there’s one service Yahoo dispensed with which they might regret.  I’m sure Ms. Mayer is just a little sick that Delicious was unloaded.  Delicious is just the kind of analytics-generating service data-centric people love.  Despite its offerings, there is a lot of room for acquisition to expand Yahoo.  Sites like Yelp, TripAdvisor or Kayak could go a long way if integrated well and could be used to enhance Bing’s results, giving users a reason to choose Yahoo over Bing itself.  Remember, while Ms. Mayer was still at Google, Google acquired Zagat, ostensibly for similar reasons.

So, tl;dr version, Yahoo needs a solid mobile strategy.  Not a bunch of apps, one good app with access to everything Yahoo.  Yahoo also needs to give people a reason to go there for search, and adding content from review sites it may acquire is a good way to start.  And take the opportunity to grab some of the users Google has turned into nomads by being a really good site again.

A handy list of online scripting resources

On one of my mailing lists, a tangential discussion began about online scripting resources, where you can live edit HTML, CSS and JavaScript in the browser. Here’s the ones discussed:

Of these, JSFiddle seems to be used the most.

An additional site mentioned is cdnjs (http://cdnjs.com/), which hosts many, many more script libraries than Google or Microsoft’s CDN, from which you can reference a library in one of the above tools.

Should you check NuGet packages into source control?

A short time ago I posted a question on Twitter about whether people who use NuGet check the actual packages into source control.  There weren’t many answers one way or the other, but a lot of people were curious about an answer.  After some trial and error and experience, I can say this conclusively:

Do not check your NuGet packages into source control.

There are several reasons for this:

  1. Doing so violates one of the concepts of NuGet, which is to easily manage the latest versions of dependencies.
  2. Checking in packages greatly increases the size of the repository.
  3. By default, TFS ignores DLLs, but will check in manifest files.  This causes problems on build servers, since NuGet looks for the manifest, and if it finds one, won’t try and pull the package.  The dependencies you need don’t get deployed.

Here’s the right way to handle this:

  1. Right-click on your solution and select Enable NuGet Package Restore.
  2. Add your NuGet packages to your solution, if you haven’t done so already.
  3. Make sure packages.config is included in your solution, and is committed to source control.
  4. Make sure your packages folder and repositories.config are included in source control, but ignore the individual package folders.
  5. Re-read Step 4.  The key thing here is you want to ignore the folders for the individual NuGet packages.  This can be tedious with a lot of packages, so sometimes a GUI is nice.image

Now, when you go to build your solution, the packages you reference will be pulled fresh by the build server.

SSL Certificate Error in Hosted TFS with Git

Today we were poking around the new Git offering in Team Foundation Service (hosted TFS), and when I tried to clone our test repo I got the following error:

error: SSL certificate problem, verify that the CA cert is OK.  Details: error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed while accessing https://<account>.visualstudio.com/DefaultCollection/_git/<repo>
fatal: HTTP request failed

Since we didn’t get this error at home, suspicion is that our corporate proxy was interfering with the SSL check somehow.  The solution was simple, just open Git bash and issue the following command:

git config –global http.sslVerify false

After doing this, I could interact with the repo normally.

Git in Hosted TFS with Bash

A few months ago, in conjunction with the release of Visual Studio 2012, Microsoft also released a hosted TFS (Note: this hosted service is called Team Foundation Service; Team Foundation Server is the thing you install onsite.  I’m going to call Team Foundation Service “hosted TFS” for brevity and clarity).  This is kind of the third version of hosted TFS, which in Microsoft-land means it’s pretty good.  True to form, VS 2012 is pretty good, and in contrast to previous versions has a good focus on agile teams.  I’ve had the opportunity to use this for well over a year now, and I’ve seen hosted TFS grow into something you need to look at before you deride it.  A wise move on Microsoft’s part is that hosted TFS is free for teams up to five, so you can explore and use at no cost.

Perhaps the greatest downside to TFS is that you were completely locked in to the TFS version control methods.  The displeasures with this were great in number.  Git, especially Github’s implementation, gained popularity in enterprises because of its distributed nature and ease of collaboration.  Microsoft’s first foray to combining the features of Git and TFS was git-tf, which presented a git-like overlay onto TFS repositories.

Just this past week Microsoft dropped the bombshell that Git was a first class choice for version control in hosted TFS (read Team Foundation Service updates – Jan 30 or watch Git Support Added to Visual Studio and TFS).  Woah.  All the planning and tracking features of TFS (including the scrumboards) and the DVCS workflow of Git, in one offering.  Right now, Git is a feature in hosted TFS only; it’s planned for TFS but no timetable has been announced.

Also released was the CTP of Visual Studio 2012 Update 2 (VS2012.2) (see also Git init VS), which adds git support directly into Visual Studio 2012.  Warning—do not install this update if you have existing TFS repos.  There are several reports of it corrupting existing TFS repos.  You might want to sit this one out, and keep your eyes peeled for a future version that won’t kill your existing repos.  Stay tuned for updates and more information.  This will be fixed soon, I’m sure.  In the case of my team at the day job, we are connecting to TFS 2008 with VS 2012, which is not a supported scenario (even though it seems to work fine for us).  This is a known issue, see the compatibility matrix at Compatibility between Team Foundation Clients and Team Foundation Server.  If you’re using TFS 2008 or earlier, skip this update.  Otherwise, you’re apparently fine.

This image was totally stolen from http://blogs.msdn.com/b/bharry/archive/2013/01/30/git-init-vs.aspx.

Using Git in Hosted TFS

For more information on using Git in TFS with VS 2012, see Getting Started with Git in Visual Studio and Team Foundation Service, or the hosted TFS docs at Visual Studio with Git.  I have not installed the update, so I’m going to use Bash for this walkthrough.

Your Windows Live Id can’t be used by VS or any of the other tools, so you have to create an alternate credential first.  Once you’ve logged in, click on your user name in the upper-right corner and choose “My Profile”:

Screenshot-2013-02-03_21.11.34

Then select the Credentials tab, and click on “Enable alternate credentials”

Screenshot-2013-02-03_21.13.09

Enter a secondary user name and a password—only one is allowed per account.

Screenshot-2013-02-03_21.14.33

You’ll enter these credentials a little later when you clone the repo.

Next, create a new Team Project with Git:

image

Give a name, a description, a Process template (project tracking style), and choose Git as your version control.  (Note: As I later found out, don’t put spaces in repo names. Not only is %20 a pain to remember and type, but VS appears to get confused with where it put the Nuget packages. I kept getting all kinds of errors when trying to build the project. Fortunately, it was a demo only.)

image

TFS will then create your project (they are certainly optimistic!):

imageimage

If this is a new project, create a folder where you want the project files to be.  If you have an existing project, you can work with that, no problem.  Either way, open Git bash and navigate to your working folder.  To clone a new project, issue the following command:

git clone https://<accountname>.visualstudio.com/defaultcollection/_git/<repo>

A couple things to note—since this is a URL, remember to HTML encode the repo name if you have spaces (e.g., repo%20name).  Also, TFS projects are arranged into collections.  If you haven’t created a collection, use defaultcollection in the path.  If you’ve created a collection, use that.  If you have an existing repo, use git init rather than git clone.  You’ll be prompted for a username and password, and this is where you enter the secondary credentials you created earlier.

image

Now let’s see how this all works.  Open up Visual Studio and create a new project in the folder you cloned into.  Once the project is created, switch back to Bash and list the files.  You can see you’re working in the master branch.  A status check shows your new files.

image

If you try to add your files, and get an error like below, there is a simple fix:

image

You probably need to change the handling of LF and CRLF; check this with git config core.autocrlf.  True means that line endings will be changed on commit/checkout.  What you do depends on the systems your team members are using; there is a good discussion at http://kernel.org/pub/software/scm/git/docs/git-config.html.  If everyone is using Windows, you can set this to false and line endings will remain unchanged.

image

Add your new files and commit them.  If you’re new to Git, this commit will save the new files in the local copy of the repository.  Now, you can push the files to your repo:

image

Looking back in TFS, this is how we see the repo:

image

Let’s take a look at something basic—branching.  Create a branch (I called mine sprint1), then make a small change to a file.  Commit the changes, and push to TFS (remember to use git push origin sprint1).

Looking back in TFS, we switch branches with a dropdown list on the far right:

Screenshot-2013-02-03_23.15.53

After switching branches, you can select the history tab and see the history of the branch.

image

Clicking on the message for one of the commits brings up the commit changes:

image

Drilling down in the Source Explorer to the file where you made the change, you can choose the compare tab and see the diff between commits.

image

This view can also be changed into an inline view:

image

Conflicts are resolved locally, before pushing to the repo.  You do this in whatever client or tool you’re using.

TFS vs. Github – a comparison

In the table below, I’ve attempted to compare the major features between Github and Git in TFS.  It’s far from complete, and I’ll happily make corrections or add more comparisons if you leave a comment.  I’m a light user of Github, I actually use Bitbucket for my side projects.

Feature Github Hosted TFS w/ Git
Forking Yes No
Pull requests Yes No, changes are published directly to the repo
Communication SSH, HTTPS HTTPS only
Gists Yes No, nothing similar
Agile planning No Yes
Work item/bug tracking Basic Advanced
Planning tools None Advanced
Wiki Yes No
Clients Git Bash (and clients based on CLI, such as TortoiseGit), github:windows, Eclipse plugin, VS 2012 (with Git updates) VS 2012 (with Git updates),  Team Explorer Everywhere (Eclipse plugin and cross-platform CLI), Git Bash (and clients based on the CLI, such as TortoiseGit)
Private Repos Pay only Unlimited, free for teams up to 5
Public Repos Unlimited None, not meant for public repos
Permissions Repo Granular

If you’d like more information about Git, check out Syncfusion’s free Git Succinctly, or O’Reilly’s Version Control with Git.

Summary

The addition of Git to TFS as a source control option is very exciting.  If you’re used to the way Github or Bitbucket implements Git, you might find this implementation lacking a couple of your favorite features, even though the TFS implementation has all of Git’s features.  This may or may not be a deal breaker for you.  That you can use either VS or Eclipse or Bash or other Git tools is great, and that users on any OS can use TFS.

Creating a simple dynamic menu in ASP.NET MVC

Menus are one of the most basic elements on any website, but there’s not a simple dynamic menu out of the box in ASP.NET MVC.  There are several third party solutions you can add as an HTML helper or in a controller, but in several projects I’ve needed a simple and quick way to generate a menu.  Here’s an updated version of something I wrote a while ago in just such an occasion.

We’ll use VS 2010 and the new jQuery Menu widget for the UI (the standard menu CSS won’t work).  You can use any CSS or JavaScript menu UI you want to–I’m using jQuery because it’s free and easy.  You can find the Git repo for this project at https://bitbucket.org/rjdudley/simple-dynamic-menu-in-mvc.

1. Start by creating a new ASP.NET MVC 4 Internet Application.

2. The default template installs jQuery 1.7.1 and jQuery 1.8.2, but the menu widget was released in jQuery 1.9 and jQuery UI 1.10.  The easiest way to update jQuery and jQuery UI is via NuGet.  Install both the latest jQuery and jQuery UI.

One glitch in this sample is the jQuery menu widget–this is a vertical menu.  A horizontal menu will be in the menubar widget, which has not yet been released.  It was supposed to be in 1.9 but didn’t make the cut.  Not a big deal, since this isn’t a post about the UI, but fair warning.

3. Let’s make the jQuery menu work first.  Open Content/Site.css, and find around line 180 where the menu styles are.  Comment out all of the menu styles, it should be about 25 lines of code total.  These styles will conflict with the jQuery menu.

4. To help prevent page flash oafter loading and to make sure all CSS elements are in place before a script is executed, we load CSS files at the top of the page.  Just below the Styles.Render directive, add links for jquery.ui.core.css, then jquery.ui.menu.css.  The code should look like this:

@Styles.Render("~/Content/css")
<link href="../../Content/themes/base/jquery.ui.core.css" rel="stylesheet" type="text/css" />
<link href="../../Content/themes/base/jquery.ui.menu.css" rel="stylesheet" type="text/css" />
@Scripts.Render("~/bundles/modernizr")

5. Next, open up layout.cshtml and scroll down to the bottom of the file. Add a Scripts.Render directive for jQuery UI underneath the one for jQuery, then a small script block to call the jQuery menu function.  The code should look like this:

@Scripts.Render("~/bundles/jquery")
@Scripts.Render("~/bundles/jqueryui")

<script>
$(document).ready(function () {
$("#menu").menu();
});
</script>

@RenderSection("scripts", required: false)

 

(If you want to see how these bundles are defined, open up App_Start/BundleConfig.cs.  Later on you may want to configure all of these scripts and CSS into a bundle)

6.  If we load and run the page now, we should now have a fully functional vertical menu.  Good enough for this demo.

7. We need a model for a MenuItem, so create MenuItem.cs with the following code:

using System;
using System.Collections.Generic;

namespace SimpleMenuSample.Models
{
public class MenuItem
{
public MenuItem()
{
this.ChildMenuItems = new List<MenuItem>();
}

public int MenuItemId { get; set; }
public string MenuItemName { get; set; }
public string MenuItemPath { get; set; }
public Nullable<int> ParentItemId { get; set; }
public virtual ICollection<MenuItem> ChildMenuItems { get; set; }

}
}

 

 

8. Now we need a model for the Menu, so create menu.cs with the following code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace SimpleMenuSample.Models
{
public class Menu
{
public Menu()
{
Items = new List<MenuItem>();
}

public List<MenuItem> Items;
}
}

 

 

9. Now that we have our models defined, it’s time to add a controller method to generate the menu.  Normally you’d do some data access, but we’re going to hard code the menu items here for the sake of simplicity.  Open HomeController.cs and add the following code:

[ChildActionOnly]
public ActionResult Menu()
{
var _menu = new Menu();

// Normally you'd do some data or cache access to build/retrieve the user's menu
// then you're loop through the results and build the menu object
// we're hard coding for the sake of simplicity

var _google = new MenuItem()
{
MenuItemName = "Google",
MenuItemPath = "http://google.com/",
};

_google.ChildMenuItems.Add(new MenuItem()
{
MenuItemName = "Google Images",
MenuItemPath = "http://google.com/images/"
});

var _bing = new MenuItem()
{
MenuItemName = "Bing",
MenuItemPath = "http://bing.com/"
};

_bing.ChildMenuItems.Add(new MenuItem()
{
MenuItemName = "Bing Images",
MenuItemPath = "http://bing.com/images/"
});

_menu.Items.Add(_google);
_menu.Items.Add(_bing);

return PartialView("_Menu", _menu);
}

 

 

10. Now that we have a model and a controller, we need a view to display our menu.  Create a shared view named _Menu.cs with the following code:

@model SimpleMenuSample.Models.Menu
<ul id="menu">
@foreach (var item in Model.Items)
{
<li><a href="@item.MenuItemPath">@item.MenuItemName</a>
@if (item.ChildMenuItems.Any())
{
<ul>
@foreach (var subitem in item.ChildMenuItems)
{
<li><a href="@subitem.MenuItemPath">@subitem.MenuItemName</a></li>
}
</ul>
}
</li>
}
</ul>

 

11. One final change is to call the menu from _Layout.cshtml.  Change the nav element to look like the code below:

<nav>
@Html.Action("Menu","Home")
</nav>

 

And that should be a bingo!  When you run the project, you should see a (rather ugly) vertical menu (seen below).  Hovering over one of the options should cause the child entry to appear.

image

Hope this helps!