【问题标题】:How to make the cache to refresh when the XML is changed?当 XML 更改时如何使缓存刷新?
【发布时间】:2026-01-25 13:25:01
【问题描述】:

我正在使用 MvcSiteMapProvider 4.6.3,MVC 4。使用 DI 配置站点地图。

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>>(); 

如何让它在Sitemap xml更新时自动更新缓存?

我正在将 MvcSitemapProvider 从 v3 升级到 v4。 在第 3 版中,站点地图似乎已自动刷新。

我确实将缓存过期时间设置为 5 分钟,这会导致问题吗?

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);

更新

当我更改站点地图 xml 文件时,缓存不会更新,直到 5 分钟缓存过期。 我正在使用多个站点地图 xml 文件。

        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));
        }

这会是它不起作用的原因吗?

【问题讨论】:

  • 我已经更新了我的答案。

标签: mvcsitemapprovider asp.net-mvc-sitemap


【解决方案1】:

我认为您发布的代码没有问题。但是,当 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.
    });

这是用来使缓存过期的,但它是一个完全独立于指定使用多个文件来构建站点地图的部分的机制:

// 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 实例,如@987654321 中所述@。

重要提示:要使多个 XML 文件在单个 SiteMap 实例上工作,您必须为每个 SiteMap 的根节点指定相同的键,如 this answer 底部所示。但是您不能在多个 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);

【讨论】:

    最近更新 更多