A middleware that does I/O (a database lookup, an external API call) sits directly in the critical path of every single request that passes through it — the cost of a slow or poorly-written middleware isn't confined to one route, it's multiplied across the entire application.
# BAD — a blocking network call on every single request, even ones that don't need it
class GeoLookupMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
request.country = geoip_lookup_over_network(request.META["REMOTE_ADDR"]) # slow!
return self.get_response(request)
# BETTER — a local, in-memory database file instead of a network round-trip,
# and only doing the lookup for routes that actually use request.country
class GeoLookupMiddleware:
def __init__(self, get_response):
self.get_response = get_response
self.reader = geoip2.database.Reader("GeoLite2-Country.mmdb") # loaded once, at startup
def __call__(self, request):
if request.path.startswith("/api/localized/"):
request.country = self.reader.country(request.META["REMOTE_ADDR"]).country.iso_code
return self.get_response(request)
The general principle, true across all three frameworks: expensive work in a globally-registered middleware should either be genuinely necessary for every request, or gated behind a check for the specific requests that need it — and one-time setup (opening a file, a connection pool) belongs in the constructor/startup phase, not repeated on every request.
app.Use(async (context, next) =>
{
await next(); // awaiting here means this middleware doesn't block a thread while waiting
});
await next() (rather than a blocking .Wait() or .Result) matters specifically because ASP.NET Core runs on a limited thread pool — blocking a thread synchronously while waiting for an inner layer to finish wastes that thread for the entire duration, whereas await frees it to serve other requests during any I/O wait inside the pipeline. Blocking on async code in ASP.NET Core is a well-known way to cause thread-pool starvation under load.