I wanted a simple way to manage canonical links in ASP.NET MVC.
It would have been nice to work these out automatically from the route tables, but for the project I am working on, its far too convoluted to be done easily, I’d rather maintain a fixed definition for each action.
Step up a custom `ActionFilterAttribute`:
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
public sealed class CanonicalUrl : ActionFilterAttribute
{
readonly string url;
public CanonicalUrl(string url)
{
this.url = url;
}
public override void OnResultExecuting(ResultExecutingContext filterContext)
{
var uri = filterContext.RequestContext.HttpContext.Request.Url;
var fullyQualifiedUrl = (uri.Scheme + "://" + uri.Host + this.url).ToLowerInvariant();
foreach (var key in filterContext.RouteData.Values.Keys)
fullyQualifiedUrl = fullyQualifiedUrl.Replace("{" + key.ToLowerInvariant() + "}",
filterContext.RouteData.Values[key].ToString());
filterContext.Controller.ViewData["CanonicalUrl"] = fullyQualifiedUrl;
filterContext.HttpContext.Response.Headers.Add("link", "<" + fullyQualifiedUrl + ">; rel=\"canonical\"");
base.OnResultExecuting(filterContext);
}
}
You can then decorate your actions like this:
[CanonicalUrl("/show/{name}")]
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult Show(string name)
Make sure you stick the link element in your page’s head:
<% if(ViewData["CanonicalUrl"] != null){ %>
<link rel="canonical" href="<%: ViewData["CanonicalUrl"] %>" />
<%} %>