Skip to content

Permformance issue with StaticAssetDevelopmentRuntimeHandler.EnableSupport.Β #59673

@maliming

Description

@maliming

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.

if (StaticAssetDevelopmentRuntimeHandler.IsEnabled(result.IsBuildManifest, endpoints.ServiceProvider))
{
StaticAssetDevelopmentRuntimeHandler.EnableSupport(endpoints, result, environment, result.Descriptors);
}

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();
}
}

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);

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.");
}

Metadata

Metadata

Assignees

Labels

area-blazorIncludes: Blazor, Razor Components

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions