ASP.NET Core is a high-performance web framework, but the default patterns leave performance on the table. These optimisation patterns are applicable to any ASP.NET Core 3.1 application.

Response compression and caching

Enable response compression (ResponseCompression middleware) for text responses: JSON, HTML, CSS, and JavaScript. Brotli compression reduces response size by 20-26% compared to gzip for typical JSON payloads. Response caching (Cache-Control headers, IMemoryCache, IDistributedCache for Redis) eliminates repeated computation for read-heavy endpoints with tolerable staleness. The combination of compression and caching can reduce server load by 50-70% for read-dominated APIs.

Span and Memory for allocation reduction

System.Span and System.Memory allow operating on contiguous memory regions without heap allocations. For hot paths that process strings, parse binary data, or work with arrays, replacing heap-allocated operations with Span-based alternatives can eliminate millions of allocations per second. ArrayPool.Shared provides pooled array rental, eliminating large array allocations in processing loops. The impact is measurable in reduced GC pressure and improved throughput.

Minimal API surface for high-throughput endpoints

ASP.NET Core's full MVC pipeline (model binding, action filters, result formatters) adds middleware overhead per request. For highest-throughput endpoints, consider: minimal API endpoints (in .NET 6) or IHttpRequestHandler (in .NET Core 3.x) that bypass MVC overhead, manual JSON parsing with System.Text.Json rather than content negotiation, and returning IActionResult vs ValueTask (the latter avoids boxing). The TechEmpower benchmark results validate that lean ASP.NET Core achieves near-raw-socket throughput.

Connection and HTTP client reuse

HttpClient should be registered as a singleton or via IHttpClientFactory, never created per request. A new HttpClient per request exhausts the ephemeral port pool under load. IHttpClientFactory manages the lifetime of HttpClientHandler instances, providing connection reuse while allowing handler rotation for DNS changes. For database connections, EF Core's connection pool (managed by the underlying database provider) should be sized appropriately for the expected concurrency.