I want to use canonical url\'s in my website. I read a few things about it on the internet, but i\'m looking for a solution which will automatically generate the canonical for m
The accepted answer although it provides a good way to Produce Canonical url's.
It completely destroys the meaning of using the canonical tag!
Why the canonical tag exists?
When google crawls your website and finds duplicate content penalizes you.
The same page in your website can be accessed through various paths.
http://yourdomain.com/en
https://yourClientIdAt.YourHostingPacket.com/
http://195.287.xxx.xxx //Your server Ip
https://yourdomain.com/index
http://www.yourdomain.com/
http://www.yourdomain.com/index .....etc... etc..
Google will find the same content within various paths, thus duplicate content, thus penalty.
While the best practice is to use 301 redirects and have ONLY 1 link point to the same web page that's a pain......
That's why rel="canonical" has been created. Its a way to tell the crawler
"Hey this isn't a different page, this is the www.mydomain.index page you searched before.... the link in the canonical tag is the correct one!"
And then the same webpage won't be crawled multiple times as a different one.
By dynamically generating the canonical link from the url you are just saying....
Yes....this is a different page crawl this one also....
and this is a different one.... and this one...
So in order to have a working canonical tag you have to generate the same exact link for every page that has different content. Decide your primary Domain(www.etc.com), Protocol (Https/Http) and Letter Casing(/Index,/index) and produce links with the only thing that identifies a single page. And this is your Controller/Action (And maybe language) Combinations. So you can extract those values from your route data.
public static TagBuilder GetCanonicalUrl(RouteData route,String host,string protocol)
{
//These rely on the convention that all your links will be lowercase!
string actionName = route.Values["action"].ToString().ToLower();
string controllerName = route.Values["controller"].ToString().ToLower();
//If your app is multilanguage and your route contains a language parameter then lowercase it also to prevent EN/en/ etc....
//string language = route.Values["language"].ToString().ToLower();
string finalUrl = String.Format("{0}://{1}/{2}/{3}/{4}", protocol, host, language, controllerName, actionName);
var canonical = new TagBuilder("link");
canonical.MergeAttribute("href", finalUrl);
canonical.MergeAttribute("rel", "canonical");
return canonical;
}
In order your HtmlHelper to produce consistent links with your convention @Muhammad Rehan Saeed answered that.
Then in order to generate your Canonical tags for all pages you have to either make a HtmlHelper extension
public static MvcHtmlString CanonicalUrl(this HtmlHelper html,string host,string protocol)
{
var canonical = GetCanonicalUrl(HttpContext.Current.Request.RequestContext.RouteData,host,protocol);
return new MvcHtmlString(canonical.ToString(TagRenderMode.SelfClosing));
}
@Html.CanonicalUrl("www.mydomain.com", "https");
Or Implement an action filter attribute for your controllers . (I used this approach in order to handle more complex scenarios with multiple domains on the same app etc...)
public class CanonicalUrl : ActionFilterAttribute
{
private string _protocol;
private string _host;
public CanonicalUrl(string host, string protocol)
{
this._host = host;
this._protocol = protocol;
}
public override void OnResultExecuting(ResultExecutingContext filterContext)
{
var canonical = GetCanonicalUrl(filterContext.RouteData,_host,_protocol);
filterContext.Controller.ViewBag.CanonicalUrl = canonical.ToString();
}
}
}
Usage within controller
[CanonicalUrl("www.yourdomain.com","https")]
public class MyController : Controller
Then i used it on my _Layout.chtml and done!
@Html.Raw(ViewBag.CanonicalUrl)