How can dynamic breadcrumbs be achieved with ASP.net MVC?
Solution 1:
Sitemap's are definitely one way to go... alternatively, you can write one yourself! (of course as long as standard MVC rules are followed)... I just wrote one, I figured I would share here.
@Html.ActionLink("Home", "Index", "Home")
@if(ViewContext.RouteData.Values["controller"].ToString() != "Home") {
@:> @Html.ActionLink(ViewContext.RouteData.Values["controller"].ToString(), "Index", ViewContext.RouteData.Values["controller"].ToString())
}
@if(ViewContext.RouteData.Values["action"].ToString() != "Index"){
@:> @Html.ActionLink(ViewContext.RouteData.Values["action"].ToString(), ViewContext.RouteData.Values["action"].ToString(), ViewContext.RouteData.Values["controller"].ToString())
}
Hopefully someone will find this helpful, this is exactly what I was looking for when I searched SO for MVC breadcrumbs.
Solution 2:
ASP.NET 5 (aka ASP.NET Core), MVC Core Solution
In ASP.NET Core, things are further optimized as we don't need to stringify the markup in the extension method.
In ~/Extesions/HtmlExtensions.cs
:
using System.Text.RegularExpressions;
using Microsoft.AspNetCore.Html;
using Microsoft.AspNetCore.Mvc.Rendering;
namespace YourProjectNamespace.Extensions
{
public static class HtmlExtensions
{
private static readonly HtmlContentBuilder _emptyBuilder = new HtmlContentBuilder();
public static IHtmlContent BuildBreadcrumbNavigation(this IHtmlHelper helper)
{
if (helper.ViewContext.RouteData.Values["controller"].ToString() == "Home" ||
helper.ViewContext.RouteData.Values["controller"].ToString() == "Account")
{
return _emptyBuilder;
}
string controllerName = helper.ViewContext.RouteData.Values["controller"].ToString();
string actionName = helper.ViewContext.RouteData.Values["action"].ToString();
var breadcrumb = new HtmlContentBuilder()
.AppendHtml("<ol class='breadcrumb'><li>")
.AppendHtml(helper.ActionLink("Home", "Index", "Home"))
.AppendHtml("</li><li>")
.AppendHtml(helper.ActionLink(controllerName.Titleize(),
"Index", controllerName))
.AppendHtml("</li>");
if (helper.ViewContext.RouteData.Values["action"].ToString() != "Index")
{
breadcrumb.AppendHtml("<li>")
.AppendHtml(helper.ActionLink(actionName.Titleize(), actionName, controllerName))
.AppendHtml("</li>");
}
return breadcrumb.AppendHtml("</ol>");
}
}
}
~/Extensions/StringExtensions.cs
remains the same as below (scroll down to see the MVC5 version).
In razor view, we don't need Html.Raw
, as Razor takes care of escaping when dealing with IHtmlContent
:
....
....
<div class="container body-content">
<!-- #region Breadcrumb -->
@Html.BuildBreadcrumbNavigation()
<!-- #endregion -->
@RenderBody()
<hr />
...
...
ASP.NET 4, MVC 5 Solution
=== ORIGINAL / OLD ANSWER BELOW ===
(Expanding on Sean Haddy's answer above)
If you want to make it extension-driven (keeping Views clean), you can do something like:
In ~/Extesions/HtmlExtensions.cs
:
(compatible with MVC5 / bootstrap)
using System.Text;
using System.Web.Mvc;
using System.Web.Mvc.Html;
namespace YourProjectNamespace.Extensions
{
public static class HtmlExtensions
{
public static string BuildBreadcrumbNavigation(this HtmlHelper helper)
{
// optional condition: I didn't wanted it to show on home and account controller
if (helper.ViewContext.RouteData.Values["controller"].ToString() == "Home" ||
helper.ViewContext.RouteData.Values["controller"].ToString() == "Account")
{
return string.Empty;
}
StringBuilder breadcrumb = new StringBuilder("<ol class='breadcrumb'><li>").Append(helper.ActionLink("Home", "Index", "Home").ToHtmlString()).Append("</li>");
breadcrumb.Append("<li>");
breadcrumb.Append(helper.ActionLink(helper.ViewContext.RouteData.Values["controller"].ToString().Titleize(),
"Index",
helper.ViewContext.RouteData.Values["controller"].ToString()));
breadcrumb.Append("</li>");
if (helper.ViewContext.RouteData.Values["action"].ToString() != "Index")
{
breadcrumb.Append("<li>");
breadcrumb.Append(helper.ActionLink(helper.ViewContext.RouteData.Values["action"].ToString().Titleize(),
helper.ViewContext.RouteData.Values["action"].ToString(),
helper.ViewContext.RouteData.Values["controller"].ToString()));
breadcrumb.Append("</li>");
}
return breadcrumb.Append("</ol>").ToString();
}
}
}
In ~/Extensions/StringExtensions.cs
:
using System.Globalization;
using System.Text.RegularExpressions;
namespace YourProjectNamespace.Extensions
{
public static class StringExtensions
{
public static string Titleize(this string text)
{
return CultureInfo.CurrentCulture.TextInfo.ToTitleCase(text).ToSentenceCase();
}
public static string ToSentenceCase(this string str)
{
return Regex.Replace(str, "[a-z][A-Z]", m => m.Value[0] + " " + char.ToLower(m.Value[1]));
}
}
}
Then use it like (in _Layout.cshtml for example):
....
....
<div class="container body-content">
<!-- #region Breadcrumb -->
@Html.Raw(Html.BuildBreadcrumbNavigation())
<!-- #endregion -->
@RenderBody()
<hr />
...
...