-
Notifications
You must be signed in to change notification settings - Fork 10.5k
Description
When StaticAssetDevelopmentRuntimeHandler.EnableSupport
is enabled in the development environment, websites with many static resources may experience significant delays.
The delay occurs primarily during the first request due to an O(n^2)
loop in the UpdateEndpoints
process.
Each static resource endpoint builder invokes the AttachRuntimePatching
method and then the FindOriginalAsset
method to iterate through all descriptors.
If there are 10,000
static files(js/css/images
) under the wwwroot
folder, this leads to 10,000 x 10,000
iterations on the first request.
Thanks.
aspnetcore/src/StaticAssets/src/StaticAssetsEndpointRouteBuilderExtensions.cs
Lines 39 to 42 in af22eff
if (StaticAssetDevelopmentRuntimeHandler.IsEnabled(result.IsBuildManifest, endpoints.ServiceProvider)) | |
{ | |
StaticAssetDevelopmentRuntimeHandler.EnableSupport(endpoints, result, environment, result.Descriptors); | |
} |
aspnetcore/src/StaticAssets/src/StaticAssetEndpointDataSource.cs
Lines 99 to 119 in af22eff
private void UpdateEndpoints() | |
{ | |
lock (_lock) | |
{ | |
var endpoints = new List<Endpoint>(); | |
foreach (var asset in _descriptors) | |
{ | |
// At this point the descriptor becomes immutable. | |
asset.Freeze(); | |
endpoints.Add(_endpointFactory.Create(asset, _conventions, _finallyConventions)); | |
} | |
var oldCancellationTokenSource = _cancellationTokenSource; | |
_endpoints = endpoints; | |
_cancellationTokenSource = new CancellationTokenSource(); | |
_changeToken = new CancellationChangeToken(_cancellationTokenSource.Token); | |
oldCancellationTokenSource?.Cancel(); | |
oldCancellationTokenSource?.Dispose(); | |
} | |
} |
aspnetcore/src/StaticAssets/src/Development/StaticAssetDevelopmentRuntimeHandler.cs
Lines 29 to 38 in af22eff
public void AttachRuntimePatching(EndpointBuilder builder) | |
{ | |
var original = builder.RequestDelegate!; | |
var asset = builder.Metadata.OfType<StaticAssetDescriptor>().Single(); | |
if (asset.HasContentEncoding()) | |
{ | |
// This is a compressed asset, which might get out of "sync" with the original uncompressed version. | |
// We are going to find the original by using the weak etag from this compressed asset and locating an asset with the same etag. | |
var eTag = asset.GetWeakETag(); | |
asset = FindOriginalAsset(eTag.Tag.Value!, descriptors); |
aspnetcore/src/StaticAssets/src/Development/StaticAssetDevelopmentRuntimeHandler.cs
Lines 145 to 156 in af22eff
private static StaticAssetDescriptor FindOriginalAsset(string tag, List<StaticAssetDescriptor> descriptors) | |
{ | |
for (var i = 0; i < descriptors.Count; i++) | |
{ | |
if (descriptors[i].HasETag(tag)) | |
{ | |
return descriptors[i]; | |
} | |
} | |
throw new InvalidOperationException("The original asset was not found."); | |
} |