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