You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET Core 5.0文件变更未触发内存缓存自动过期问题咨询

问题原因
  • 路径适配错误:IFileProvider.Watch() 方法仅支持接收相对于自身根目录的相对路径,且要求路径分隔符为正斜杠。如果传入的strFileName是绝对路径、使用反斜杠作为分隔符,或者和IFileProvider实例的根目录映射范围不匹配(比如用WebRootFileProvider监听内容根目录下的文件),就会导致监听不到文件变更,变更令牌不会触发,缓存自然不会自动过期。
  • 文件句柄占用:XmlDocument.Load() 默认以独占读取模式打开文件,会阻塞文件系统的变更事件通知,导致IFileProvider无法捕获到文件修改动作。
  • 未配置失效校验逻辑(非核心原因,但会提升调试难度):原有代码没有注册缓存失效的回调逻辑,无法直观判断变更令牌是否正常触发。
修复方案

1. 统一路径处理

先将传入的文件路径转换为IFileProvider兼容的格式,如果是绝对路径,先转为相对于IFileProvider根目录的相对路径,同时统一替换分隔符为正斜杠。如果需要监听任意绝对路径的文件,可以为对应目录单独构造PhysicalFileProvider实例。

2. 优化文件读取逻辑

使用带共享读写权限的文件流加载XML,避免占用文件句柄阻塞变更通知。

3. 补充缓存校验逻辑(可选)

可以根据业务需要保留滑动过期配置,同时可补充缓存失效回调用于调试或预加载。

修复后完整代码

public XmlDocument loadXML(string strFileName) 
{
    XmlDocument xml;

    // 先尝试从缓存获取
    if (_cache.TryGetValue(strFileName, out xml)) 
    {
        return xml;
    }

    xml = this.createNewDocument();

    // 用共享读写的流加载文件,避免独占锁阻塞变更通知
    using (var stream = File.Open(strFileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
    {
        xml.Load(stream);
    }

    if (xml != null) 
    {
        // 转换为IFileProvider兼容的相对路径
        string relativePath = strFileName;
        if (_fileProvider is PhysicalFileProvider physicalProvider)
        {
            relativePath = Path.GetRelativePath(physicalProvider.Root, strFileName)
                .Replace(Path.DirectorySeparatorChar, '/');
        }

        var changeToken = _fileProvider.Watch(relativePath);

        var cacheEntryOptions = new MemoryCacheEntryOptions()
                .SetSlidingExpiration(TimeSpan.FromMinutes(5))
                .AddExpirationToken(changeToken);

        // 可选:注册失效回调,方便排查问题
        cacheEntryOptions.RegisterPostEvictionCallback((key, value, reason, state) =>
        {
            if (reason == EvictionReason.TokenExpired)
            {
                // 可在这里打印日志确认是文件变更触发的缓存失效
            }
        });

        _cache.Set(strFileName, xml, cacheEntryOptions);
    }
    return xml;
}

如果你的_fileProvider没有正确注入,可在服务注册逻辑中补充配置:

// ASP.NET Core 5 Startup.cs 示例
services.AddSingleton<IFileProvider>(sp => 
{
    // 控制台等非Web环境替换为IHostEnvironment
    var env = sp.GetRequiredService<IWebHostEnvironment>();
    return env.ContentRootFileProvider;
});

内容的提问来源于stack exchange,提问作者William Walseth

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 13:30:04