1

I am using MvcSiteMapProvider 4.6.3, MVC 4. Using DI to config the Sitemap.

this.For<System.Runtime.Caching.ObjectCache>()
    .Use(s => System.Runtime.Caching.MemoryCache.Default);

this.For(typeof (ICacheProvider<>)).Use(typeof (RuntimeCacheProvider<>));
var rootCacheDependency = this.For<ICacheDependency>().Use<RuntimeFileCacheDependency>()
    .Ctor<string>("fileName").Is(rootFileName);

var rootCacheDetails = this.For<ICacheDetails>().Use<CacheDetails>()
    .Ctor<TimeSpan>("absoluteCacheExpiration").Is(absoluteCacheExpiration)
    .Ctor<TimeSpan>("slidingCacheExpiration").Is(TimeSpan.MinValue)
    .Ctor<ICacheDependency>().Is(rootCacheDependency);

var cacheDetails = new List<SmartInstance<CacheDetails>>();
var xmlSources = new List<SmartInstance<FileXmlSource>>(); 

How to make it automatically update the cache when the Sitemap xml is updated?

I am upgrading MvcSitemapProvider from v3 to v4. In version 3, it seems the sitemap is automatically refreshed.

I did set the cache expiration time to be 5 min, is this causing problem?

TimeSpan absoluteCacheExpiration = TimeSpan.FromMinutes(5);

var rootCacheDetails = this.For<ICacheDetails>().Use<CacheDetails>()
            .Ctor<TimeSpan>("absoluteCacheExpiration").Is(absoluteCacheExpiration)
            .Ctor<TimeSpan>("slidingCacheExpiration").Is(TimeSpan.MinValue)
            .Ctor<ICacheDependency>().Is(rootCacheDependency);

UPDATE

When I change the sitemap xml file the cache is not updated till 5 min the cache expire. I am using multiple sitemap xml files.

        var sitmapPath = HostingEnvironment.MapPath("~/Sitemaps");
        var sitemaps = new List<string>();
        if (sitmapPath != null)
        {
            sitemaps.AddRange(Directory.GetFiles(sitmapPath, "*.sitemap"));
        }

        foreach (var sitemapFileName in sitemaps)
        {
            var cacheDependencie = 
                this.For<ICacheDependency>()
                .Use<RuntimeFileCacheDependency>()
                .Ctor<string>("fileName")
                .Is(sitemapFileName);

            cacheDetails.Add(this.For<ICacheDetails>().Use<CacheDetails>()
            .Ctor<TimeSpan>("absoluteCacheExpiration").Is(absoluteCacheExpiration)
            .Ctor<TimeSpan>("slidingCacheExpiration").Is(TimeSpan.MinValue)
            .Ctor<ICacheDependency>().Is(cacheDependencie));

            xmlSources.Add(this.For<IXmlSource>().Use<FileXmlSource>()
                .Ctor<string>("fileName").Is(sitemapFileName));
        }

Will this be the reason it's not working?

4

1 回答 1

0

我认为您发布的代码没有问题。但是,当 XML 更改时,它会重新加载 RuntimeFileCacheDependency。

RuntimeFileCacheDependency 期望 fileName 参数是绝对路径。因此,在将其提供给 RuntimeFileCacheDependency 构造函数之前,您必须使用 HostingEnvironment.MapPath 对其进行转换。

var rootFileName = HostingEnvironment.MapPath("~/root.sitemap");

回复您的更新

cacheDetails 对象的目的是为单个 SiteMapBuilderSet 实例指定缓存策略。如果您进一步查看(原始)DI 模块,请注意该变量已传递给此类的构造函数。

// Configure the builder sets
this.For<ISiteMapBuilderSetStrategy>().Use<SiteMapBuilderSetStrategy>()
    .EnumerableOf<ISiteMapBuilderSet>().Contains(x =>
    {
        x.Type<SiteMapBuilderSet>()
            .Ctor<string>("instanceName").Is("default")
            .Ctor<bool>("securityTrimmingEnabled").Is(securityTrimmingEnabled)
            .Ctor<bool>("enableLocalization").Is(enableLocalization)
            .Ctor<bool>("visibilityAffectsDescendants").Is(visibilityAffectsDescendants)
            .Ctor<bool>("useTitleIfDescriptionNotProvided").Is(useTitleIfDescriptionNotProvided)
            .Ctor<ISiteMapBuilder>().Is(builder)
            .Ctor<ICacheDetails>().Is(cacheDetails); // <- caching specified here explicitly.
    });

这是用于使缓存过期的内容,但它是与指定使用多个文件来构建 SiteMap 的部分完全分开的机制:

// Register the sitemap node providers
var siteMapNodeProvider = this.For<ISiteMapNodeProvider>().Use<CompositeSiteMapNodeProvider>()
    .EnumerableOf<ISiteMapNodeProvider>().Contains(x =>
    {
        x.Type<XmlSiteMapNodeProvider>()
            .Ctor<bool>("includeRootNode").Is(true)
            .Ctor<bool>("useNestedDynamicNodeRecursion").Is(false)
            .Ctor<IXmlSource>().Is(rootXmlSource);
        
        // NOTE: Each additional XmlSiteMapNodeProvider instance for the same SiteMap instance must
        // specify includeRootNode as "false"
        x.Type<XmlSiteMapNodeProvider>()
            .Ctor<bool>("includeRootNode").Is(false)
            .Ctor<bool>("useNestedDynamicNodeRecursion").Is(false)
            .Ctor<IXmlSource>().Is(childXmlSource1);
        x.Type<XmlSiteMapNodeProvider>()
            .Ctor<bool>("includeRootNode").Is(false)
            .Ctor<bool>("useNestedDynamicNodeRecursion").Is(false)
            .Ctor<IXmlSource>().Is(childXmlSource2);
        
        // Add additional XmlSiteMapNodeProviders here (with includeRootNode as "false")...
            
        // You only need this if you intend to use MvcSiteMapNodeAttribute in your application
        x.Type<ReflectionSiteMapNodeProvider>()
            .Ctor<IEnumerable<string>>("includeAssemblies").Is(includeAssembliesForScan)
            .Ctor<IEnumerable<string>>("excludeAssemblies").Is(new string[0]);
    });

// Register the sitemap builders
var builder = this.For<ISiteMapBuilder>().Use<SiteMapBuilder>()
    .Ctor<ISiteMapNodeProvider>().Is(siteMapNodeProvider);

这是为单个 SiteMap 指定多个 XML 文件的方法,但也可以通过将 XmlSiteMapNodeProvider 的每个实例传递给单独的 SiteMapBuilder 和单独的 SiteMapBuilderSet 使每个 XML 文件成为其自己的 SiteMap 实例,如在一个应用程序中的多个 SiteMaps 中所述.

重要提示:要使多个 XML 文件在单个 SiteMap 实例上工作,您必须为每个 SiteMap 的根节点指定相同的键,如本答案底部所示。但是您不能在多个 XML 文件(根节点除外)中指定代表同一控制器操作的节点。

如果您需要更多的灵活性,我建议您实现自己的 XmlSiteMapNodeProvider 或完全放弃使用 XML 的想法,因为使用 ISiteMapNodeProvider 或 IDynamicNodeProvider 更加灵活。

现在,回到缓存。如果您确实在同一个 SiteMap 实例中使用多个 XML 文件,则需要使用 RuntimeCompositeCacheDependency 以便每个文件都将被视为同一个缓存的依赖项,但您必须使用 CacheDetails 的单个实例。

var rootCacheDependency =
    this.For<ICacheDependency>().Use<RuntimeFileCacheDependency>()
        .Ctor<string>("fileName").Is(rootAbsoluteFileName);

var childCacheDependency1 =
    this.For<ICacheDependency>().Use<RuntimeFileCacheDependency>()
        .Ctor<string>("fileName").Is(childAbsoluteFileName1);
        
var childCacheDependency2 =
    this.For<ICacheDependency>().Use<RuntimeFileCacheDependency>()
        .Ctor<string>("fileName").Is(childAbsoluteFileName2);


var cacheDependency =
    this.For<ICacheDependency>().Use<RuntimeCompositeCacheDependency>()
        .Ctor<ICacheDependency[]>().Is(new ICacheDependency[] 
        { 
            (ICacheDependency)rootCacheDependency, 
            (ICacheDependency)childCacheDependency1,
            (ICacheDependency)childCacheDependency2             
        });


var cacheDetails =
    this.For<ICacheDetails>().Use<CacheDetails>()
        .Ctor<TimeSpan>("absoluteCacheExpiration").Is(absoluteCacheExpiration)
        .Ctor<TimeSpan>("slidingCacheExpiration").Is(TimeSpan.MinValue)
        .Ctor<ICacheDependency>().Is(cacheDependency);
于 2014-05-23T08:04:30.430 回答