From 6437b2d89a074cf02b057c75f9480770cfab57c2 Mon Sep 17 00:00:00 2001 From: maliming Date: Mon, 20 May 2024 17:49:56 +0800 Subject: [PATCH] Add `CachedBundleDynamicFileProvider` to sync bundle files using cache. Resolve #19861 --- .../CachedBundleDynamicFileProvider.cs | 57 +++++++++++++++++++ .../UI/Bundling/InMemoryFileInfoCacheItem.cs | 22 +++++++ .../VirtualFileSystem/DynamicFileProvider.cs | 6 +- 3 files changed, 82 insertions(+), 3 deletions(-) create mode 100644 framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/CachedBundleDynamicFileProvider.cs create mode 100644 framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/InMemoryFileInfoCacheItem.cs diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/CachedBundleDynamicFileProvider.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/CachedBundleDynamicFileProvider.cs new file mode 100644 index 0000000000..2173925878 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/CachedBundleDynamicFileProvider.cs @@ -0,0 +1,57 @@ +using System; +using Microsoft.Extensions.FileProviders; +using Microsoft.Extensions.Options; +using Volo.Abp.Caching; +using Volo.Abp.DependencyInjection; +using Volo.Abp.VirtualFileSystem; + +namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling; + +[Dependency(ReplaceServices = true)] +public class CachedBundleDynamicFileProvider : DynamicFileProvider +{ + protected IDistributedCache Cache { get; } + protected IOptions BundlingOptions { get; } + + public CachedBundleDynamicFileProvider( + IDistributedCache cache, + IOptions bundlingOptions) + { + Cache = cache; + BundlingOptions = bundlingOptions; + } + + public override IFileInfo GetFileInfo(string? subpath) + { + var fileInfo = base.GetFileInfo(subpath); + + if (!subpath.IsNullOrWhiteSpace() && fileInfo is NotFoundFileInfo && + subpath.Contains(BundlingOptions.Value.BundleFolderName, StringComparison.OrdinalIgnoreCase)) + { + var filePath = NormalizePath(subpath); + var cacheItem = Cache.Get(filePath); + if (cacheItem == null) + { + return fileInfo; + } + + fileInfo = new InMemoryFileInfo(filePath, cacheItem.FileContent, cacheItem.Name); + DynamicFiles.AddOrUpdate(filePath, fileInfo, (key, value) => fileInfo); + } + + return fileInfo; + } + + public override void AddOrUpdate(IFileInfo fileInfo) + { + var filePath = fileInfo.GetVirtualOrPhysicalPathOrNull(); + Cache.GetOrAdd(filePath!, () => new InMemoryFileInfoCacheItem(filePath!, fileInfo.ReadBytes(), fileInfo.Name)); + base.AddOrUpdate(fileInfo); + } + + public override bool Delete(string filePath) + { + Cache.Remove(filePath); + return base.Delete(filePath); + } +} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/InMemoryFileInfoCacheItem.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/InMemoryFileInfoCacheItem.cs new file mode 100644 index 0000000000..74082913f1 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bundling/Volo/Abp/AspNetCore/Mvc/UI/Bundling/InMemoryFileInfoCacheItem.cs @@ -0,0 +1,22 @@ +using System; +using Volo.Abp.MultiTenancy; + +namespace Volo.Abp.AspNetCore.Mvc.UI.Bundling; + +[Serializable] +[IgnoreMultiTenancy] +public class InMemoryFileInfoCacheItem +{ + public InMemoryFileInfoCacheItem(string dynamicPath, byte[] fileContent, string name) + { + DynamicPath = dynamicPath; + Name = name; + FileContent = fileContent; + } + + public string DynamicPath { get; set; } + + public string Name { get; set; } + + public byte[] FileContent { get; set; } +} diff --git a/framework/src/Volo.Abp.VirtualFileSystem/Volo/Abp/VirtualFileSystem/DynamicFileProvider.cs b/framework/src/Volo.Abp.VirtualFileSystem/Volo/Abp/VirtualFileSystem/DynamicFileProvider.cs index 12e5184a97..50c60ab7bc 100644 --- a/framework/src/Volo.Abp.VirtualFileSystem/Volo/Abp/VirtualFileSystem/DynamicFileProvider.cs +++ b/framework/src/Volo.Abp.VirtualFileSystem/Volo/Abp/VirtualFileSystem/DynamicFileProvider.cs @@ -29,14 +29,14 @@ public class DynamicFileProvider : DictionaryBasedFileProvider, IDynamicFileProv DynamicFiles = new ConcurrentDictionary(); } - public void AddOrUpdate(IFileInfo fileInfo) + public virtual void AddOrUpdate(IFileInfo fileInfo) { var filePath = fileInfo.GetVirtualOrPhysicalPathOrNull(); DynamicFiles.AddOrUpdate(filePath!, fileInfo, (key, value) => fileInfo); ReportChange(filePath!); } - public bool Delete(string filePath) + public virtual bool Delete(string filePath) { if (!DynamicFiles.TryRemove(filePath, out _)) { @@ -65,7 +65,7 @@ public class DynamicFileProvider : DictionaryBasedFileProvider, IDynamicFileProv return tokenInfo.ChangeToken; } - private void ReportChange(string filePath) + protected virtual void ReportChange(string filePath) { if (FilePathTokenLookup.TryRemove(filePath, out var tokenInfo)) {