我在MVC4中使用MVCSitemapProvider by Maarten Balliauw和Ninject DI。作为一个大型Web应用程序,枚举记录以生成站点地图xml帐户占页面加载时间的70%。为此,我开始为每个n级动态节点提供程序使用新的站点地图文件。
<mvcSiteMap xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://mvcsitemap.codeplex.com/schemas/MvcSiteMap-File-4.0" xsi:schemaLocation="http://mvcsitemap.codeplex.com/schemas/MvcSiteMap-File-4.0 MvcSiteMapSchema.xsd">
<mvcSiteMapNode title="$resources:SiteMapLocalizations,HomeTitle" description="$resources:SiteMapLocalizations,HomeDescription" controller="Controller1" action="Home" changeFrequency="Always" updatePriority="Normal" metaRobotsValues="index follow noodp noydir"><mvcSiteMapNode title="$resources:SiteMapLocalizations,AboutTitle" controller="ConsumerWeb" action="Aboutus"/>
<mvcSiteMapNode title="Sitemap" controller="Consumer1" action="SiteMap"/><mvcSiteMapNode title=" " action="Action3" controller="Consumer2" dynamicNodeProvider="Comp.Controller.Utility.NinjectModules.PeopleBySpecDynamicNodeProvider, Comp.Controller.Utility" />
<mvcSiteMapNode title="" siteMapFile="~/Mvc2.sitemap"/>
</mvcSiteMapNode>
</mvcSiteMap>
但是,它似乎不起作用。对于localhost:XXXX / sitemap.xml,Mvc2.sitemap中的子节点似乎无法加载。
答案 0 :(得分:0)
siteMapFile
不是MvcSiteMapProvider中的有效XML属性(尽管您可以将其用作自定义属性),因此我不确定您要执行此操作的指南。但是,底线是没有功能加载“子站点地图文件”,即使有,它也无助于解决您的问题,因为所有节点都会立即加载到内存中。实际上,在普通服务器上存在大约10,000到15,000个节点的上限。
您描述的问题是一个已知问题。 issue #258中提供了一些可能有帮助或可能没有帮助的提示。
我们正在使用new XML sitemap implementation,它允许您将XML站点地图直接连接到数据源,这可用于解决此问题(至少就XML站点地图而言)。此实现是基于流的,具有可以直接绑定到数据源的分页,并且可以无缝地分页到多个表,因此它非常有效。然而,虽然有一个工作原型,但它仍然有一段时间没有被发布。
如果您需要早点而不是晚些时候,欢迎您从this branch获取原型。
您需要一些代码才能将其连接到您的应用程序中(这可能会在官方发布时发生变化)。我创建了一个demo project here。
<强>的Application_Start 强>
var registrar = new MvcSiteMapProvider.Web.Routing.XmlSitemapFeedRouteRegistrar();
registrar.RegisterRoutes(RouteTable.Routes, "XmlSitemap2");
<强> XmlSitemap2Controller 强>
using MvcSiteMapProvider.IO;
using MvcSiteMapProvider.Web.Mvc;
using MvcSiteMapProvider.Xml.Sitemap.Configuration;
using System.Web.Mvc;
public class XmlSitemap2Controller : Controller
{
private readonly IXmlSitemapFeedResultFactory xmlSitemapFeedResultFactory;
public XmlSitemap2Controller()
{
var builder = new XmlSitemapFeedStrategyBuilder();
var xmlSitemapFeedStrategy = builder
.SetupXmlSitemapProviderScan(scan => scan.IncludeAssembly(this.GetType().Assembly))
.AddNamedFeed("default", feed => feed.WithMaximumPageSize(5000).WithContent(content => content.Image().Video()))
.Create();
var outputCompressor = new HttpResponseStreamCompressor();
this.xmlSitemapFeedResultFactory = new XmlSitemapFeedResultFactory(xmlSitemapFeedStrategy, outputCompressor);
}
public ActionResult Index(int page = 0, string feedName = "")
{
var name = string.IsNullOrEmpty(feedName) ? "default" : feedName;
return this.xmlSitemapFeedResultFactory.Create(page, name);
}
}
<强> IXmlSiteMapProvider 强>
您需要一个或多个IXmlSitemapProvider
实施。为方便起见,有一个基类XmlSiteMapProviderBase
。这些类似于在MVC中创建控制器。
using MvcSiteMapProvider.Xml.Sitemap;
using MvcSiteMapProvider.Xml.Sitemap.Specialized;
using System;
using System.Linq;
public class CategoriesXmlSitemapProvider : XmlSitemapProviderBase, IDisposable
{
private EntityFramework.MyEntityContext db = new EntityFramework.MyEntityContext();
// This is optional. Don't override it if you don't want to use last modified date.
public override DateTime GetLastModifiedDate(string feedName, int skip, int take)
{
// Get the latest date in the specified page
return db.Category.OrderBy(x => x.Id).Skip(skip).Take(take).Max(c => c.LastUpdated);
}
public override int GetTotalRecordCount(string feedName)
{
// Get the total record count for all pages
return db.Category.Count();
}
public override void GetUrlEntries(IUrlEntryHelper helper)
{
// Do not call ToList() on the query. The idea is that we want to force
// EntityFramework to use a DataReader rather than loading all of the data
// at once into RAM.
var categories = db.Category
.OrderBy(x => x.Id)
.Skip(helper.Skip)
.Take(helper.Take);
foreach (var category in categories)
{
var entry = helper.BuildUrlEntry(string.Format("~/Category/{0}", category.Id))
.WithLastModifiedDate(category.LastUpdated)
.WithChangeFrequency(MvcSiteMapProvider.ChangeFrequency.Daily)
.AddContent(content => content.Image(string.Format("~/images/category-image-{0}.jpg", category.Id)).WithCaption(category.Name));
helper.SendUrlEntry(entry);
}
}
public void Dispose()
{
db.Dispose();
}
}
请注意,目前没有IXmlSiteMapProvider
实现从默认(或任何)SiteMap读取节点,但是创建一个类似于上面显示的那个,除了您将在SiteMap中查询节点而不是记录数据库。
或者,您可以使用第三方XML站点地图生成器。虽然,几乎所有这些都是以不可扩展的方式为大型站点设置的,并且大多数都由您来处理分页。如果他们没有流式传输节点,那么它实际上不会扩展到超过几千个URL。
您可能需要注意的其他细节是使用forcing a match技术来减少SiteMap中的节点总数。如果您使用菜单和/或SiteMap HTML帮助程序,则需要单独保留所有高级节点。但是任何没有出现的节点都是一个很好的候选者。实际上,使用这种技术几乎可以将任何数据驱动的站点减少到几十个节点,但请记住,每个被强制匹配SiteMap中多个路由的节点都意味着需要在XML站点地图中添加单个URL条目