A component of ASP.NET Core for creating RESTful web services that support HTTP-based communication between clients and servers.
Since you can't use Postman, here's a way to settle "is it the API, the network or the tool?" with numbers instead of guesses, using only what's already on a Windows machine.
1. Break one request into its parts with curl
curl.exe is built into Windows 10 and 11. In PowerShell, type curl.exe (plain curl is an alias for Invoke-WebRequest in Windows PowerShell 5.1):
curl.exe -s -o NUL -D - -w "dns=%{time_namelookup} connect=%{time_connect} tls=%{time_appconnect} firstbyte=%{time_starttransfer} total=%{time_total}`n" https://your-api-host/your-endpoint
Each value is the number of seconds since the request started:
| Value | What it covers | If this is where the ~4 s appears |
|---|---|---|
dns |
Looking up the host name | Name resolution (DNS, proxy auto-config) |
| -------- | -------- | -------- |
dns |
Looking up the host name | Name resolution (DNS, proxy auto-config) |
connect |
TCP connection | Network path, firewall or proxy |
tls |
HTTPS handshake | TLS or certificate checks |
firstbyte |
Until the first byte of the response | The server: your API code, or authentication before it |
total |
Whole request |
If the endpoints use Windows authentication, add --negotiate -u : so curl authenticates like a browser. That also shows whether the Kerberos/NTLM negotiation Bruce mentioned is adding the time.
Run it from the machine where the slowness happens: your PC for the Bruno comparison, and the Blazor server for calls the app itself makes.
2. Time the request inside the API
Add this as the first middleware in Program.cs. It returns the server's own processing time in a Server-Timing header:
using System.Diagnostics;
app.Use(async (context, next) =>
{
var stopwatch = Stopwatch.StartNew();
context.Response.OnStarting(() =>
{
context.Response.Headers["Server-Timing"] = $"app;dur={stopwatch.Elapsed.TotalMilliseconds:0}";
return Task.CompletedTask;
});
await next(context);
});
The -D - in the curl command prints response headers, so you'll see a line like Server-Timing: app;dur=12 (milliseconds). Browser developer tools also show it in the Timing tab of a request.
Reading the results together
-
app;duris small butfirstbyteis about 4 s: the time is spent before your code runs (authentication, IIS, a proxy or the network). The API logic isn't the problem.
app;dur is about 4 s: the time is in your endpoint code or its dependencies, such as a database call. Time those next.
curl is fast from your machine but Bruno is slow: it's the tool or its proxy settings, which matches what you saw with Postman off-site.
I tested this with a .NET 9 minimal API: an endpoint that waits 1.5 s showed Server-Timing: app;dur=1503 and firstbyte=1.50, with DNS and connect near zero, while a trivial endpoint showed app;dur=0.