diff --git a/src/Http/Http.Features/src/FeatureCollection.cs b/src/Http/Http.Features/src/FeatureCollection.cs index 36acb30ecb47..7bde54632dfb 100644 --- a/src/Http/Http.Features/src/FeatureCollection.cs +++ b/src/Http/Http.Features/src/FeatureCollection.cs @@ -15,6 +15,7 @@ public class FeatureCollection : IFeatureCollection { private static readonly KeyComparer FeatureKeyComparer = new KeyComparer(); private readonly IFeatureCollection? _defaults; + private readonly int _initialCapacity; private IDictionary? _features; private volatile int _containerRevision; @@ -25,6 +26,21 @@ public FeatureCollection() { } + /// + /// Initializes a new instance of with the specified initial capacity. + /// + /// The initial number of elements that the collection can contain. + /// is less than 0 + public FeatureCollection(int initialCapacity) + { + if (initialCapacity < 0) + { + throw new ArgumentOutOfRangeException(nameof(initialCapacity)); + } + + _initialCapacity = initialCapacity; + } + /// /// Initializes a new instance of with the specified defaults. /// @@ -73,7 +89,7 @@ public object? this[Type key] if (_features == null) { - _features = new Dictionary(); + _features = new Dictionary(_initialCapacity); } _features[key] = value; _containerRevision++; diff --git a/src/Http/Http.Features/src/PublicAPI.Unshipped.txt b/src/Http/Http.Features/src/PublicAPI.Unshipped.txt index 922524558a31..5b914c27b50f 100644 --- a/src/Http/Http.Features/src/PublicAPI.Unshipped.txt +++ b/src/Http/Http.Features/src/PublicAPI.Unshipped.txt @@ -13,4 +13,5 @@ Microsoft.AspNetCore.Http.Features.FeatureCollection.Set(TFeature? ins Microsoft.AspNetCore.Http.Features.IFeatureCollection.Get() -> TFeature? Microsoft.AspNetCore.Http.Features.IFeatureCollection.Set(TFeature? instance) -> void Microsoft.AspNetCore.Http.Features.IServerVariablesFeature.this[string! variableName].get -> string? -Microsoft.AspNetCore.Http.ISession.TryGetValue(string! key, out byte[]? value) -> bool \ No newline at end of file +Microsoft.AspNetCore.Http.ISession.TryGetValue(string! key, out byte[]? value) -> bool +Microsoft.AspNetCore.Http.Features.FeatureCollection.FeatureCollection(int initialCapacity) -> void \ No newline at end of file diff --git a/src/Http/Http/src/DefaultHttpContext.cs b/src/Http/Http/src/DefaultHttpContext.cs index 22c9566344b4..9143938a7496 100644 --- a/src/Http/Http/src/DefaultHttpContext.cs +++ b/src/Http/Http/src/DefaultHttpContext.cs @@ -19,6 +19,10 @@ namespace Microsoft.AspNetCore.Http /// public sealed class DefaultHttpContext : HttpContext { + // The initial size of the feature collection when using the default constructor; based on number of common features + // https://github.com/dotnet/aspnetcore/issues/31249 + private const int DefaultFeatureCollectionSize = 10; + // Lambdas hoisted to static readonly fields to improve inlining https://github.com/dotnet/roslyn/issues/13624 private readonly static Func _newItemsFeature = f => new ItemsFeature(); private readonly static Func _newServiceProvidersFeature = context => new RequestServicesFeature(context, context.ServiceScopeFactory); @@ -44,7 +48,7 @@ public sealed class DefaultHttpContext : HttpContext /// Initializes a new instance of the class. /// public DefaultHttpContext() - : this(new FeatureCollection()) + : this(new FeatureCollection(DefaultFeatureCollectionSize)) { Features.Set(new HttpRequestFeature()); Features.Set(new HttpResponseFeature());