谷歌网站地图从定制的SiteMapResult生成

我的上一篇文章展示了如何使用自定义actionResult和WCF中的类来生成RSS Feed。没有类似的类来帮助为ASP.NET MVC应用程序构建有效的Google站点地图。所以这就是你可以建立自己的。

有很多课程与创建源相关联 system.servicemodel.syndication. 命名空间,但我们实际上只需要从其中3人借用谷歌地点的灵感。我决定使用创建一个高级SiteMapFeed对象,其中包含SiteMapFeedItems的集合和渲染XML的格式化器。这 网站地图协议 定义有效站点地图所需的元素。

 

<?XML. 版本="1.0" 编码="UTF-8"?>

<URL.set XMLNS.="http://www.sitemaps.org/schemas/sitemap/0.9">

  <URL.>

    <座垫>http://www.lssc9d.icu/</座垫>

    <lastmod.>2009-01-01</lastmod.>

    <ChangeFreq.>每月</ChangeFreq.>

    <优先事项>0.5</优先事项>

  </URL.>

  <URL.>

    <座垫>http://www.lssc9d.icu/Contact.aspx</座垫>

    <优先事项>0.3</优先事项>

  </URL.>

</URL.set>

 

你可以希望看到每个人<url>节点包含最多4个元素:URL,介绍URL更改的内容的频率和“优先级”。这构成了SiteMapfeedItem类的基础:

using System;


namespace MikesDotnetting.Models.SiteMap
{
    public class SiteMapfeedItem.
    {
        private Double _priority = 0.5;

        public Uri Url { get; set; }
        public DateTime LastMod { get; set; }
        public Enum ChangeFreq { get; set; }
        public Double Priority
        {
            get { return _priority; }
            set
            {
                if (value < 0.0 || value > 1.0)
                {
                    throw new ArgumentOutOfRangeException("Priority","Priority must be between 0.0 and 1.0");
                }
                _priority = value;
            }
        }
    }
}


“协议”指定优先级值必须在0到1之间。我默认为0.5。该范围之外的任何值都会抛出异常。请记住,该协议还指定有一组有限的值对于ChangeFreq元素可接受,我选择使该属性成为枚举:

namespace MikesDotnetting.Models.SiteMap
{
    public enum ChangeFrequency
    {
        Always,
        Hourly,
        Daily,
        Weekly,
        Monthly,
        Yearly,
        Never
    }
}

SiteMapfeed的课程非常简单:

using System.Collections.Generic;

namespace MikesDotnetting.Models.SiteMap
{
    public class SiteMapFeed
    {
        public List<SiteMapfeedItem.> Items { get; set; }
    }
}


我本可以没有这个,刚刚通过了一个名单<SiteMapFeedItem>周围,​​但在某些阶段,我可能想要满足不同类型的网站地图。最后格式化器:

using System.Linq;
using System.Xml;
using System.Xml.Linq;

namespace MikesDotnetting.Models.SiteMap
{
    public class GoogleSiteMapFormatter
    {
        private SiteMapFeed siteMap;

        public GoogleSiteMapFormatter(SiteMapFeed feedToFormat)
        {
            siteMap = feedToFormat;
        }

        public void WriteTo(XmlWriter writer)
        {
            XNamespace ns = "http://www.sitemaps.org/schemas/sitemap/0.9";
            var sitemap = new XDocument(new XDeclaration("1.0", "utf-8", "yes"),
                    new XElement(ns + "URL.set",
                         siteMap.Items
                         .Select(item => new XElement(ns + "URL.",
                                  new XElement(ns + "座垫", item.Url),
                                  new XElement(ns + "lastmod.", item.LastMod.ToW3CDate()),
                                  new XElement(ns + "ChangeFreq.", item.ChangeFreq.ToString().ToLower()),
                                  new XElement(ns + "优先事项", item.Priority)
                                )
                              )
                            )
                        );
            sitemap.Save(writer);
        }
    }
}

这个被称为googlesitemapformatter。我可能想在将来的某个阶段添加特定于其他输出的其他格式。构造函数接受SiteMapFeed对象,该对象将传递给私人字段。调用WriteTo方法时,此馈送将迭代,并且根据协议的规范创建XDocument。

遵循A. 格雷格评论 我修改了LastMod的价值,以提供一个 有效的W3C日期 通过扩展方法:

public static string ToW3CDate(this DateTime dt)
{
    return dt.ToUniversalTime().ToString("s") + "Z";
}

在此之前,我使用ShortdateString()方法生成一个值,而在它从谷歌制作的警告时,不会停止站点地图被索引。

然后将XDocument传递给传递到WriteTo方法的XMLWriter对象,该对象在自定义ActionResult中调用:

using System;
using System.Web.Mvc;
using System.Xml;
using MikesDotnetting.Models.SiteMap;

namespace MikesDotnetting.Models
{
    public class SiteMapResult : ActionResult
    {
        public SiteMapFeed Feed { private get; set; }

        public override void ExecuteResult(ControllerContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }
            context.HttpContext.Response.ContentType = "text/xml";

            var siteMapFormatter = new GoogleSiteMapFormatter(Feed);
            using (var writer = XmlWriter.Create(context.HttpContext.Response.Output))
            {
                siteMapFormatter.WriteTo(writer);
            }
        }
    }
}


这与之相同的方式 rssresult在我上一篇文章中介绍并且就像在上一篇文章中一样,我为我的basexmlController添加了一种方法,该方法包装呼叫来实例化SiteMapResult:

protected static SiteMapResult SiteMap(SiteMapFeed feed)
{
    return new SiteMapResult
    {
        Feed = feed
    };
}

XMLController中的操作方法(从basexmlController继承)如下所示:

public SiteMapResult SiteMapFeed()
{
    const string URL. = "http://www.lssc9d.icu/Article/{0}/{1}";
    var entries = repository.GetAllArticleTitles();

    var feed = new List<SiteMapfeedItem.>();
    foreach (var entry in entries)
    {
        var item = new SiteMapfeedItem.
                       {
                           ChangeFreq = ChangeFrequency.Monthly,
                           LastMod = entry.DateAmended ?? entry.DateCreated,

                           Url = new Uri(string.Format(url, entry.ID, entry.Head.ToCleanUrl()))
                       };
        feed.Add(item);
    }
    feed.Add(new SiteMapfeedItem.
                 {
                     ChangeFreq = ChangeFrequency.Always, 
                     LastMod = DateTime.Now, 
                     Priority = 1.0, 
                     Url = new Uri("http://www.lssc9d.icu")
                 });
    feed.Add(new SiteMapfeedItem.
                 {
                     ChangeFreq = ChangeFrequency.Never, 
                     LastMod = DateTime.Now, 
                     Priority = 0.3, 
                     Url = new Uri("http://www.lssc9d.icu/Contact")
                 });
    feed.Add(new SiteMapfeedItem.
                 {
                     ChangeFreq = ChangeFrequency.Yearly, 
                     LastMod = DateTime.Now, 
                     Priority = 0.3, 
                     Url = new Uri("http://www.lssc9d.icu/About")
                 });
    var siteMap = new SiteMapFeed { Items = feed };
    return SiteMap(siteMap);
}


在此示例中,我已从数据库中检索所有文章并构建列表<SiteMapFeedItem>跟他们。然后,我也将3个静态页面添加为sitemapfeedItems。对于像这个博客这样的相对简单的网站,这将很好地工作。但是,您不想继续重新编译站点以将更多静态页面添加到网站地图,因此可以将静态页面信息保留在另一个地方,也许是数据库或其他XML文件,并且读取可能是一个好主意只要生成站点地图,就会进入SiteMapFeedItems。