C# 为mvc3 webapplication自动生成规范

C# 为mvc3 webapplication自动生成规范,c#,asp.net,asp.net-mvc-3,seo,C#,Asp.net,Asp.net Mvc 3,Seo,我想在我的网站中使用规范url。我在互联网上读到了一些关于它的内容,但我正在寻找一种解决方案,它将自动生成canonical for me运行时,并将其添加到返回到浏览器的html代码中 我已经在互联网上找到了一个使用属性的例子,但这不是我想要的。使用一个属性,我仍然在决定哪个页面应该得到一个规范,我希望每个页面都自动生成一个规范。我认为应该有(现有的)解决方案吗?我正在努力寻找一个好的例子,所以非常感谢您的帮助。问题已经解决。修复了编写我自己的html帮助程序的问题,该帮助程序通过从请求中获取

我想在我的网站中使用规范url。我在互联网上读到了一些关于它的内容,但我正在寻找一种解决方案,它将自动生成canonical for me运行时,并将其添加到返回到浏览器的html代码中


我已经在互联网上找到了一个使用属性的例子,但这不是我想要的。使用一个属性,我仍然在决定哪个页面应该得到一个规范,我希望每个页面都自动生成一个规范。我认为应该有(现有的)解决方案吗?我正在努力寻找一个好的例子,所以非常感谢您的帮助。

问题已经解决。修复了编写我自己的html帮助程序的问题,该帮助程序通过从请求中获取url来生成规范url。使用主题中的信息执行此操作。

对于Razor:

我为
HtmlHelper
做了一个扩展方法:

public static MvcHtmlString CanonicalUrl(this HtmlHelper html, string path)
{
    if (String.IsNullOrWhiteSpace(path))
    {
        var rawUrl = html.ViewContext.RequestContext.HttpContext.Request.Url;
        path = String.Format("{0}://{1}{2}", rawUrl.Scheme, rawUrl.Host, rawUrl.AbsolutePath);
    }

    path = path.ToLower();

    if (path.Count(c => c == '/') > 3)
    {
        path = path.TrimEnd('/');
    }

    if (path.EndsWith("/index"))
    {
        path = path.Substring(0, path.Length - 6);
    }

    var canonical = new TagBuilder("link");
    canonical.MergeAttribute("rel", "canonical");
    canonical.MergeAttribute("href", path);
    return new MvcHtmlString(canonical.ToString(TagRenderMode.SelfClosing));
}
获取当前URL的步骤

public static MvcHtmlString CanonicalUrl(this HtmlHelper html)
{
    var rawUrl = html.ViewContext.RequestContext.HttpContext.Request.Url;

    return CanonicalUrl(html, String.Format("{0}://{1}{2}", rawUrl.Scheme, rawUrl.Host, rawUrl.AbsolutePath));
}
访问Razor View:

@Html.CanonicalUrl()

MVC5有一个新选项,可以为您的路由生成小写URL。我的路线配置如下所示:

public static class RouteConfig
{
    public static void RegisterRoutes(RouteCollection routes)
    {
        // Imprive SEO by stopping duplicate URL's due to case or trailing slashes.
        routes.AppendTrailingSlash = true;
        routes.LowercaseUrls = true;

        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

        routes.MapRoute(
            name: "Default",
            url: "{controller}/{action}/{id}",
            defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional });
    }
}

有了这段代码,您应该不再需要规范化URL,因为这是为您完成的。如果您使用的是HTTP和HTTPS URL,并且希望为此使用规范URL,则可能会出现唯一的问题。在这种情况下,使用上述方法并用HTTPS替换HTTP非常容易,反之亦然。

这是公认的答案,尽管它提供了一种生成规范url的好方法

这是一条射中自己脚的捷径 它完全破坏了使用规范标记的意义

为什么规范标签存在

当谷歌抓取你的网站,发现重复内容惩罚你

可以通过各种路径访问网站中的同一页面

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..
谷歌将在不同的路径中找到相同的内容,从而复制内容,从而受到惩罚

虽然最佳实践是使用301重定向,并且只有一个指向同一网页的链接点,但这是一种痛苦

这就是为什么创建了rel=“canonical”。这是告诉爬虫的一种方式

“嘿,这不是另一个页面,这是www.mydomain.index页面 您以前搜索过……canonical标记中的链接是正确的!”

这样,同一个网页就不会像另一个网页那样被多次爬网

通过从url动态生成规范链接,您只是说

是的…这是一个不同的网页抓取这一个也。。。。
这是另一个。。。。而这个

因此,为了有一个有效的规范标签,您必须为每个具有不同内容的页面生成相同的精确链接。确定您的主域(www.etc.com)、协议(Https/Http)和字母大小写(/Index、/Index),并生成链接,其中只有标识了一个页面。 这是您的控制器/操作(可能还有语言)组合。 因此,您可以从路由数据中提取这些值

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;
}
为了让你的HtmlHelper与你的约定产生一致的链接,@Muhammad Rehan Saeed回答了这个问题

然后,为了为所有页面生成规范标记,您必须进行HtmlHelper扩展

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");
或者为控制器实现操作过滤器属性。(我使用这种方法是为了处理在同一个应用程序上有多个域的更复杂场景等。)

控制器内的使用

[CanonicalUrl("www.yourdomain.com","https")]
public class MyController : Controller
然后我在我的_Layout.chtml上使用了它,完成了

@Html.Raw(ViewBag.CanonicalUrl)

这是一个伟大的解决方案!很好用!用您的第一个解决方案替换了我自己的扩展。我意识到我是在对一个一年前的问题进行评论,但这只是将地址栏中的当前URL复制到一个rel=canonical标记。这无助于搜索引擎确定该页面的正确URL,因为无论当前URL是什么,都将显示为该页面的规范URL。这有点弄巧成拙。属性方法有什么问题?这似乎是合乎逻辑的做法。为控制器中的每个操作定义一次URL,不管当前的URL是什么,它都应该是什么。@Scott我想你没有抓住要点。规范化URL的目的是告诉索引引擎(即:google)几个URI实际上是同一件事,并且您有一个优先索引URI。上面的代码将删除任何查询字符串数据,消除重复索引URI,并在URI中不强制执行超过根域的后续斜杠(更多重复数据消除)。在你告诉每个人你认为它做什么/不做什么之前,你自己去试试吧!此外,您还可以扩展上述功能,以保留某些查询字符串或强制执行类似www的子域。确实非常有用!实际上我自己也尝试过,这个解决方案是在我写的一个实时站点上实现的经过一些实验后,它完全没有达到预期的效果。使用不同的主机头启动同一站点会导致新URL显示为规范URL(换句话说,规范URL是地址栏中的任何内容,而不是不变的静态值)。@Scott您可以在扩展方法中更改主机吗?
@Html.Raw(ViewBag.CanonicalUrl)