From 57b61bd2ad6e1818605471fd47561561c4ba807f Mon Sep 17 00:00:00 2001 From: Vladimir Zagray Date: Wed, 25 Sep 2024 22:24:53 +0300 Subject: [PATCH 1/2] retrieve all virtual paths only once during request --- src/WebOptimizer.Core/Asset.cs | 30 ++++++++++++++++--- .../Taghelpers/LinkTagHelper.cs | 2 +- .../Taghelpers/ScriptTagHelper.cs | 2 +- 3 files changed, 28 insertions(+), 6 deletions(-) diff --git a/src/WebOptimizer.Core/Asset.cs b/src/WebOptimizer.Core/Asset.cs index 328ce2d..f99b518 100644 --- a/src/WebOptimizer.Core/Asset.cs +++ b/src/WebOptimizer.Core/Asset.cs @@ -21,6 +21,8 @@ namespace WebOptimizer internal class Asset : IAsset { internal const string PhysicalFilesKey = "PhysicalFiles"; + internal const string AllFilesCacheKey = nameof(WebOptimizer) + "_AllFilesCache"; + private static readonly object _allFilesCacheKeySync = new object(); private readonly object _sync = new object(); public Asset(string route, string contentType, IAssetPipeline pipeline, IEnumerable sourceFiles) @@ -53,7 +55,7 @@ public async Task ExecuteAsync(HttpContext context, IWebOptimizerOptions var env = (IWebHostEnvironment)context.RequestServices.GetService(typeof(IWebHostEnvironment)); var config = new AssetContext(context, this, options); - IEnumerable files = ExpandGlobs(this, env); + IEnumerable files = ExpandGlobs(this, env, context); DateTime lastModified = DateTime.MinValue; @@ -85,8 +87,24 @@ public async Task ExecuteAsync(HttpContext context, IWebOptimizerOptions return config.Content.FirstOrDefault().Value; } - public static IEnumerable ExpandGlobs(IAsset asset, IWebHostEnvironment env) + public static IEnumerable ExpandGlobs(IAsset asset, IWebHostEnvironment env, HttpContext context) { + ConcurrentDictionary> virtualFilePathsCache; + + lock (_allFilesCacheKeySync) + { + if (context.Items.TryGetValue(AllFilesCacheKey, out var item) + && item is ConcurrentDictionary> dict) + { + virtualFilePathsCache = dict; + } + else + { + virtualFilePathsCache = new ConcurrentDictionary>(); + context.Items[AllFilesCacheKey] = virtualFilePathsCache; + } + } + var files = new List(); if (asset.SourceFiles.Any()) @@ -104,7 +122,11 @@ public static IEnumerable ExpandGlobs(IAsset asset, IWebHostEnvironment } else { - var virtualFilePaths = provider.GetAllFiles("/"); + IReadOnlyList virtualFilePaths = + virtualFilePathsCache + .GetOrAdd( + provider, + provider => provider.GetAllFiles("/")); var matcher = new Matcher(); matcher.AddInclude(outSourceFile); @@ -180,7 +202,7 @@ public string GenerateCacheKey(HttpContext context, IWebOptimizerOptions options if (!Items.ContainsKey(PhysicalFilesKey)) { - physicalFiles = ExpandGlobs(this, env); + physicalFiles = ExpandGlobs(this, env, context); } else { diff --git a/src/WebOptimizer.Core/Taghelpers/LinkTagHelper.cs b/src/WebOptimizer.Core/Taghelpers/LinkTagHelper.cs index 3b8e21f..c257432 100644 --- a/src/WebOptimizer.Core/Taghelpers/LinkTagHelper.cs +++ b/src/WebOptimizer.Core/Taghelpers/LinkTagHelper.cs @@ -99,7 +99,7 @@ private void WriteIndividualTags(TagHelperOutput output, IAsset asset) attrs.Add(attr); } - IEnumerable sourceFiles = Asset.ExpandGlobs(asset, HostingEnvironment); + IEnumerable sourceFiles = Asset.ExpandGlobs(asset, HostingEnvironment, CurrentViewContext.HttpContext); foreach (string file in sourceFiles) { diff --git a/src/WebOptimizer.Core/Taghelpers/ScriptTagHelper.cs b/src/WebOptimizer.Core/Taghelpers/ScriptTagHelper.cs index 9f4b441..5e9b880 100644 --- a/src/WebOptimizer.Core/Taghelpers/ScriptTagHelper.cs +++ b/src/WebOptimizer.Core/Taghelpers/ScriptTagHelper.cs @@ -100,7 +100,7 @@ private void WriteIndividualTags(TagHelperOutput output, IAsset asset) attrs.Add(attr); } - IEnumerable sourceFiles = Asset.ExpandGlobs(asset, HostingEnvironment); + IEnumerable sourceFiles = Asset.ExpandGlobs(asset, HostingEnvironment, CurrentViewContext.HttpContext); foreach (string file in sourceFiles) { From 6b805dd904e9041629c1549bcf1e4bcf1e8e0f56 Mon Sep 17 00:00:00 2001 From: Vladimir Zagray Date: Thu, 26 Sep 2024 15:13:54 +0300 Subject: [PATCH 2/2] fix tests --- test/WebOptimizer.Core.Test/TagHelpers/LinkTagHelperTest.cs | 1 + test/WebOptimizer.Core.Test/TagHelpers/ScriptTagHelperTest.cs | 1 + 2 files changed, 2 insertions(+) diff --git a/test/WebOptimizer.Core.Test/TagHelpers/LinkTagHelperTest.cs b/test/WebOptimizer.Core.Test/TagHelpers/LinkTagHelperTest.cs index 8b81b76..6fad690 100644 --- a/test/WebOptimizer.Core.Test/TagHelpers/LinkTagHelperTest.cs +++ b/test/WebOptimizer.Core.Test/TagHelpers/LinkTagHelperTest.cs @@ -191,6 +191,7 @@ public void CdnUrl_RouteIsAsset_TagHelperBundlingDisabled_Success(string cdnUrl, context.Setup(c => c.RequestServices.GetService(typeof(IMemoryCache))) .Returns(cache.Object); context.SetupGet(c => c.Request.PathBase).Returns(pathBase); + context.SetupGet(c => c.Items).Returns(new Dictionary()); var options = new WebOptimizerOptions { diff --git a/test/WebOptimizer.Core.Test/TagHelpers/ScriptTagHelperTest.cs b/test/WebOptimizer.Core.Test/TagHelpers/ScriptTagHelperTest.cs index 79785de..aaa2dfb 100644 --- a/test/WebOptimizer.Core.Test/TagHelpers/ScriptTagHelperTest.cs +++ b/test/WebOptimizer.Core.Test/TagHelpers/ScriptTagHelperTest.cs @@ -194,6 +194,7 @@ public void CdnUrl_RouteIsAsset_TagHelperBundlingDisabled_Success(string cdnUrl, context.Setup(c => c.RequestServices.GetService(typeof(IMemoryCache))) .Returns(cache.Object); context.SetupGet(c => c.Request.PathBase).Returns(pathBase); + context.SetupGet(c => c.Items).Returns(new Dictionary()); var options = new WebOptimizerOptions {