App first request performance with many Minimal APIs
- Dominant language
- C#
- Stars
- 38.4k
- Forks
- 10.9k
- Avg merge
- 2d 5h
- Merged PRs (30d)
- 276
Description
### Is there an existing issue for this?
- [X] I have searched the existing issues
### Describe the bug
Found while investigating https://github.com/dotnet/aspnetcore/issues/46154
The app below has 30,000 endpoints. The first request to `/` takes 0.5 seconds with 280 MB memory usage:
```cs
using System.Diagnostics;
using System.Globalization;
using System.Reflection;
using Microsoft.AspNetCore.Http.HttpResults;
using Microsoft.AspNetCore.Http.Metadata;
using Microsoft.AspNetCore.Mvc;
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.Use(async (HttpContext context, Func next) =>
{
Console.WriteLine("Start time");
Stopwatch stopwatch = Stopwatch.StartNew();
await next();
stopwatch.Stop();
Console.WriteLine(stopwatch.Elapsed.TotalSeconds);
});
app.UseRouting();
Task Plaintext(HttpContext context) => context.Response.WriteAsync("Hello, World!");
for (int i = 0; i < 30_000; i++)
{
var url = "/plaintext/nested" + i;
app.MapGet(url, Plaintext);
}
app.MapGet("/", (HttpContext context) =>
{
return context.Response.WriteAsync("Hello world");
});
Console.WriteLine("Running app");
app.Run();
```
If I change the `Plaintext` endpoint to be a minimal API (aka use `RequestDelegateFactory`) like so:
```diff
- Task Plaintext(HttpContext context) => context.Response.WriteAsync("Hello, World!");
+ string Plaintext() => "Hello, World!";
```
With 30,000 minimal APIs, it now takes 32 seconds to get the first request. And memory usage is 1,065 MB.
### Expected Behavior
I expect a fast startup time.
I think the problem is `RequestDelegateFactory` is building and compiling expressions for all minimal API endpoints when routing starts. Creating a minimal API's expression should be lazy and wait until an endpoint is first visited.
### Steps To Reproduce
_No response_
### Exceptions (if any)
_No response_
### .NET Version
_No response_
### Anything else?
_No response_
Contributor guide
Assessment
This issue has not been assessed yet.