ASP.NET Core

Server-Timing Headers in ASP.NET Core: Backend Metrics in Browser DevTools

Maarten Balliauw shows how to add a Server-Timing response header in ASP.NET Core so database and external API timings appear in browser DevTools next to the network timings. The post builds a small middleware, a measurement feature that endpoints can use, and ways to reuse OpenTelemetry Activity data. It also covers gating the header so internal timings are not exposed to every caller.

Maarten Balliauw Maarten Balliauw
Published
Reading time
11 min read
agent run #9
agent run #9
Go to original blog.maartenballiauw.be

Report this story

Is something wrong with the summary, or do you own this content? Your message comes straight to my inbox.

Type of message

Key points

  • The Server-Timing header uses name;dur=ms;desc="..." entries, and browsers display them without extra tooling.
  • The middleware must write the header in OnStarting, because headers cannot be added once the response has begun.
  • A per-request feature stored in HttpContext.Features lets any code add timings, with a lock protecting the list.
  • If you use OpenTelemetry, put timing tags on the request activity via IHttpActivityFeature, since child span tags are not seen by the middleware.
  • Internal timings can leak information about your system, so gate the header with a predicate such as development-only or an authorized role.
  • Trailer-based Server-Timing is only read by Firefox in DevTools, so the regular response header is the portable choice.

Browser DevTools show DNS, TLS and the 'waiting for server' bar, but not what the server was busy with during that wait. The Server-Timing response header lets an application publish its own named measurements, such as database or external API durations, and browsers such as Chrome, Edge and Firefox display them alongside their built-in timings. It is a practical way to see backend cost while debugging a request in the browser.

The author builds the feature in layers. A middleware records the total time until the response starts, a per-request feature collects metrics from anywhere in the code, and a small scope helper makes timing a block of code a one-liner. The post also shows how to reuse OpenTelemetry Activity data, either through tags on the request activity or through an ActivityListener, and then gates the header with an options predicate so only development or authorized callers receive the internal timings.

Real-world use

  • Finding whether a slow list endpoint is spending its time on a database query or on a pricing service call, straight from the browser during development.
  • Exposing timings already recorded on the request Activity in an OpenTelemetry-instrumented ASP.NET Core API, so they also appear in DevTools.
  • Enabling internal timing headers in staging only for users in a Diagnostics role.

Why it matters

You can see where a request spends its server time directly in the browser without switching to a tracing tool. Just make sure the header is not exposed publicly in production.

This summary was generated by the agent from the original post on Maarten Balliauw. The full text and all rights belong to its author and publisher. Go to original

Related stories

Feedback

Found a bug or have an idea? Your message lands straight in my inbox.

Type of message