Recently, I had to make a crumb-trail in the web application that I am working on (ASP.NET MVC). There are multiple ways of doing this and initially I elected to do this in my controller base class (which is inherited by all my controller classes). I created a method that do the job - but this means that this method has to be called on every single action (with GET method). If a fellow developer miss to call the method, then it would mean that the data in the crumb-trail is not built properly or accurately. If there is just an interceptor that I can hook into that will run automatically every time a controller action is being called ... *sigh
Wait - there is one, ActionFilter!!
public class CrumbTrailKeyValuePair<TKey, TValue> { public CrumbTrailKeyValuePair() { } public CrumbTrailKeyValuePair(TKey key, TValue value) { Key = key; Value = value; } public TKey Key { get; set; } public TValue Value { get; set; } } public class CrumbTrailAttribute : ActionFilterAttribute { public override void OnResultExecuting(ResultExecutingContext filterContext) { if (filterContext.HttpContext.User.Identity.IsAuthenticated) { // skip recording Account controller actions if (filterContext.RouteData.Values["controller"] != null && filterContext.RouteData.Values["controller"].ToString() != "Account") { // put in cookies Queue<CrumbTrailKeyValuePair<string, string>> crumbTrailQueue = new Queue<CrumbTrailKeyValuePair<string, string>>(); HttpCookie crumbTrailCookie = filterContext.HttpContext.Request.Cookies["CrumbTrailLinks"] ?? new HttpCookie("CrumbTrailLinks"); // initialize serializer var serializer = new JavaScriptSerializer(); // if crumbTrailCookie is not empty, retrieve value from cookie the rehydrate queue if (crumbTrailCookie != null && !string.IsNullOrEmpty(crumbTrailCookie.Value)) { // rehydrate crumbTrailQueue with cookie value crumbTrailQueue = new Queue<CrumbTrailKeyValuePair<string, string>> (serializer.Deserialize<IEnumerable<CrumbTrailKeyValuePair<string, string>>> (HttpUtility.UrlDecode(crumbTrailCookie.Value))); } if (filterContext.HttpContext.Request.HttpMethod.ToUpper() == "GET") { // get page title var pageTitle = string.IsNullOrEmpty(filterContext.Controller.ViewBag.Title) ? "PAGE" : filterContext.Controller.ViewBag.Title; // get url string url = filterContext.HttpContext.Request.RawUrl; // if current page is not in both queue, then add it if (!crumbTrailQueue.Any(x => x.Value == url && x.Key == pageTitle)) { // remove oldest menu item, keep queue length to 6 if (crumbTrailQueue.Count >= 5) crumbTrailQueue.Dequeue(); // insert new menu item into queue crumbTrailQueue.Enqueue(new CrumbTrailKeyValuePair<string, string>(pageTitle, url)); } crumbTrailCookie.Value = serializer.Serialize(crumbTrailQueue); crumbTrailCookie.Expires = DateTime.Now.AddDays(365); crumbTrailCookie.Path = "/"; filterContext.HttpContext.Response.Cookies.Add(crumbTrailCookie); } // put in viewbag if (filterContext.Result.GetType().Name == "ViewResult") { (filterContext.Result as ViewResult).ViewBag.QuickAccessQueue = crumbTrailQueue; } } } } }Inside the view, just get the queue from the ViewBag and display accordingly. The queue is stored temporarily in a cookie, so it will be remembered even when the browser is closed and reopen and relogin.
No comments:
Post a Comment