diff --git a/src/Mvc/Mvc.Abstractions/src/Abstractions/ActionDescriptor.cs b/src/Mvc/Mvc.Abstractions/src/Abstractions/ActionDescriptor.cs index 35c43127cf88..ff5444c89ea1 100644 --- a/src/Mvc/Mvc.Abstractions/src/Abstractions/ActionDescriptor.cs +++ b/src/Mvc/Mvc.Abstractions/src/Abstractions/ActionDescriptor.cs @@ -75,5 +75,7 @@ public ActionDescriptor() /// Stores arbitrary metadata properties associated with the . /// public IDictionary Properties { get; set; } = default!; + + internal IFilterMetadata[]? CachedResuableFilters { get; set; } } } diff --git a/src/Mvc/Mvc.Core/src/Filters/FilterFactory.cs b/src/Mvc/Mvc.Core/src/Filters/FilterFactory.cs index cc7563703b1d..adfe79006b71 100644 --- a/src/Mvc/Mvc.Core/src/Filters/FilterFactory.cs +++ b/src/Mvc/Mvc.Core/src/Filters/FilterFactory.cs @@ -46,15 +46,24 @@ public static FilterFactoryResult GetAllFilters( // Cache the filter items based on the following criteria // 1. Are created statically (ex: via filter attributes, added to global filter list etc.) // 2. Are re-usable + var allFiltersAreReusable = true; for (var i = 0; i < staticFilterItems.Length; i++) { var item = staticFilterItems[i]; if (!item.IsReusable) { item.Filter = null; + allFiltersAreReusable = false; } } + if (allFiltersAreReusable && filterProviders.Length == 1 && filterProviders[0] is DefaultFilterProvider defaultFilterProvider) + { + // If we know we can safely cache all filters and only the default filter provider is registered, we can + // probably re-use filters between requests. + actionDescriptor.CachedResuableFilters = filters; + } + return new FilterFactoryResult(staticFilterItems, filters); } @@ -78,6 +87,11 @@ public static IFilterMetadata[] CreateUncachedFilters( throw new ArgumentNullException(nameof(cachedFilterItems)); } + if (actionContext.ActionDescriptor.CachedResuableFilters is { } cached) + { + return cached; + } + // Deep copy the cached filter items as filter providers could modify them var filterItems = new List(cachedFilterItems.Length); for (var i = 0; i < cachedFilterItems.Length; i++)