Skip to content

Commit 0aae147

Browse files
authored
Cache filters between requests in the ordinary case (#31513)
In the normal case, * only the DefaultFilterFactoryProvider is registered * all filters registered by the framework are reusable We could so something targeted and cache filter instances between requests.
1 parent fb38da9 commit 0aae147

File tree

2 files changed

+16
-0
lines changed

2 files changed

+16
-0
lines changed

src/Mvc/Mvc.Abstractions/src/Abstractions/ActionDescriptor.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,5 +75,7 @@ public ActionDescriptor()
7575
/// Stores arbitrary metadata properties associated with the <see cref="ActionDescriptor"/>.
7676
/// </summary>
7777
public IDictionary<object, object> Properties { get; set; } = default!;
78+
79+
internal IFilterMetadata[]? CachedResuableFilters { get; set; }
7880
}
7981
}

src/Mvc/Mvc.Core/src/Filters/FilterFactory.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,15 +46,24 @@ public static FilterFactoryResult GetAllFilters(
4646
// Cache the filter items based on the following criteria
4747
// 1. Are created statically (ex: via filter attributes, added to global filter list etc.)
4848
// 2. Are re-usable
49+
var allFiltersAreReusable = true;
4950
for (var i = 0; i < staticFilterItems.Length; i++)
5051
{
5152
var item = staticFilterItems[i];
5253
if (!item.IsReusable)
5354
{
5455
item.Filter = null;
56+
allFiltersAreReusable = false;
5557
}
5658
}
5759

60+
if (allFiltersAreReusable && filterProviders.Length == 1 && filterProviders[0] is DefaultFilterProvider defaultFilterProvider)
61+
{
62+
// If we know we can safely cache all filters and only the default filter provider is registered, we can
63+
// probably re-use filters between requests.
64+
actionDescriptor.CachedResuableFilters = filters;
65+
}
66+
5867
return new FilterFactoryResult(staticFilterItems, filters);
5968
}
6069

@@ -78,6 +87,11 @@ public static IFilterMetadata[] CreateUncachedFilters(
7887
throw new ArgumentNullException(nameof(cachedFilterItems));
7988
}
8089

90+
if (actionContext.ActionDescriptor.CachedResuableFilters is { } cached)
91+
{
92+
return cached;
93+
}
94+
8195
// Deep copy the cached filter items as filter providers could modify them
8296
var filterItems = new List<FilterItem>(cachedFilterItems.Length);
8397
for (var i = 0; i < cachedFilterItems.Length; i++)

0 commit comments

Comments
 (0)