Better way to get active page link in MVC 3 Razor

Solution 1:

A better approach is to use a HTML helper:

using System.Web.Mvc; 
using System.Web.Mvc.Html;

public static class MenuExtensions
{
    public static MvcHtmlString MenuItem(
        this HtmlHelper htmlHelper, 
        string text,
        string action, 
        string controller
    )
    {
        var li = new TagBuilder("li");
        var routeData = htmlHelper.ViewContext.RouteData;
        var currentAction = routeData.GetRequiredString("action");
        var currentController = routeData.GetRequiredString("controller");
        if (string.Equals(currentAction, action, StringComparison.OrdinalIgnoreCase) &&
            string.Equals(currentController, controller, StringComparison.OrdinalIgnoreCase))
        {
            li.AddCssClass("active");
        }
        li.InnerHtml = htmlHelper.ActionLink(text, action, controller).ToHtmlString();
        return MvcHtmlString.Create(li.ToString());
    }
}

and then:

<ul>
    @Html.MenuItem("Home", "Home", "Home")
    @Html.MenuItem("Products", "Index", "Products")
</ul>

To make the above work you need your views to recognize your extension: In Web.config in the Views folder, add <add namespace="yourNamespacehere.Helpers" /> inside the namespaces tag. Then build your project and close and re-open the view you are adding this to.

then based on the current action and controller the helper will add or not the active class when generating the anchor.

Solution 2:

Expanding on Darin's example, here's the full class which adds additional optional parameters for RouteValues and HtmlAttributes on the helper. In effect, it behaves just like the base ActionLink.

using System;
using System.Web.Mvc;
using System.Web.Mvc.Html;

namespace MYNAMESPACE.Helpers {
    public static class MenuExtensions {
        public static MvcHtmlString MenuItem(this HtmlHelper htmlHelper,
                                             string text, string action,
                                             string controller,
                                             object routeValues = null,
                                             object htmlAttributes = null) {
            var li = new TagBuilder("li");
            var routeData = htmlHelper.ViewContext.RouteData;
            var currentAction = routeData.GetRequiredString("action");
            var currentController = routeData.GetRequiredString("controller");
            if (string.Equals(currentAction,
                              action,
                              StringComparison.OrdinalIgnoreCase) &&
                string.Equals(currentController,
                              controller,
                              StringComparison.OrdinalIgnoreCase)) {
                li.AddCssClass("active");
            }
            if (routeValues != null) {
                li.InnerHtml = (htmlAttributes != null)
                    ? htmlHelper.ActionLink(text,
                                            action,
                                            controller,
                                            routeValues,
                                            htmlAttributes).ToHtmlString()
                    : htmlHelper.ActionLink(text, 
                                            action, 
                                            controller, 
                                            routeValues).ToHtmlString();
            }
            else {
                li.InnerHtml = htmlHelper.ActionLink(text, 
                                                     action, 
                                                     controller).ToHtmlString();
            }
            return MvcHtmlString.Create(li.ToString());
        }
    }
}

And in the View folder's web.config:

<system.web.webPages.razor>
  <host ... />
  <pages ... >
    <namespaces>
      ...

      ...
      <add namespace="MYNAMESPACE.Helpers" />
    </namespaces>
  </pages>
</system.web.webPages.razor>

Solution 3:

Use this InnerHtml if you'd like to include HTML formatting in your text;

li.InnerHtml = "<a href=\"" + new UrlHelper(htmlHelper.ViewContext.RequestContext).Action(action, controller).ToString() + "\">" + text + "</a>";

text could be "<b>Bold</b>Normal";