ASP.NET Core performance optimization is essential for building fast, scalable, and reliable enterprise applications. Whether you're developing REST APIs, business applications, logistics platforms, or high-traffic web systems, users expect millisecond response times, responsive dashboards, and backend services that can efficiently handle thousands of concurrent requests.
Over the past 14+ years, I've designed, developed, and optimized enterprise ASP.NET Core applications for logistics companies, shipping platforms, POS systems, and business management software. One lesson has remained consistent: performance problems rarely originate from ASP.NET Core itself. Most bottlenecks are caused by inefficient database access, poor architecture, excessive memory allocations, unnecessary network calls, or missing caching strategies.
This guide shares practical optimization techniques I've applied while building and maintaining enterprise backend systems, shipping platforms, and high-traffic business applications. These techniques are suitable for both new projects and legacy systems that need better performance and scalability.
- Identify performance bottlenecks before optimizing code.
- Reduce SQL Server round trips and optimize database queries.
- Use Dapper strategically for high-performance read operations.
- Implement effective caching and asynchronous programming.
- Build scalable ASP.NET Core applications using proven enterprise techniques.
1. Measure Before You Optimize
One of the biggest mistakes developers make is optimizing code without first identifying where the actual bottleneck exists. Performance tuning should always begin with measurement rather than assumptions.
For example, developers often spend hours optimizing C# loops or LINQ queries, only to discover later that 90% of the response time was spent waiting for SQL Server or an external API.
Before making any code changes, collect performance data using tools such as:
- Visual Studio Performance Profiler
- BenchmarkDotNet
- dotnet-counters
- dotnet-trace
- Application Insights
- SQL Server Query Store
Always optimize the slowest component first. Improving a method that consumes only 2 milliseconds will never compensate for a SQL query taking 2 seconds.
2. Reduce Database Round Trips
In many enterprise ASP.NET Core applications, SQL Server is the primary contributor to request latency. Inefficient queries, unnecessary database round trips, missing indexes, and poor execution plans often have a far greater impact on performance than the application code itself. Every additional database call increases network overhead, connection usage, serialization time, and overall response time.
Consider an API that displays customer information.
Get Customer
↓
Get Orders
↓
Get Address
↓
Get Payments
↓
Get Shipment History
This approach requires five separate database calls for a single request.
A better approach is to retrieve the required information using one optimized query or a small number of carefully designed queries.
While optimizing an enterprise shipping platform handling thousands of shipment records, I consolidated multiple database calls into two carefully optimized SQL queries. This reduced average API response times by more than 60%, lowered SQL Server CPU utilization, and significantly improved application scalability during peak business hours.
3. Use Dapper for High-Performance Read Operations
Entity Framework Core is an excellent ORM for most business applications because it simplifies development and maintenance. However, for high-volume reporting systems, enterprise dashboards, analytics platforms, shipping applications, and read-heavy REST APIs, Dapper often delivers significantly better performance due to its lightweight design and minimal overhead.
Dapper performs minimal object tracking and maps database rows directly to C# objects, reducing CPU usage and memory allocations.
using (var connection = new SqlConnection(connectionString))
{
var orders = await connection.QueryAsync<Order>(
"SELECT Id, CustomerName, Status FROM Orders");
}
Many successful enterprise systems use a hybrid approach:
- Entity Framework Core for complex write operations.
- Dapper for reporting and high-performance read APIs.
In many enterprise .NET applications, the best results come from using Entity Framework Core for transactional business operations and Dapper for high-performance reporting, dashboards, and read-heavy APIs. Choosing the right tool for each workload delivers better scalability without sacrificing maintainability.
4. Select Only the Columns You Need
One of the simplest ways to improve application performance is to avoid
using SELECT *.
Retrieving unnecessary columns increases:
- Database I/O
- Network traffic
- Memory usage
- JSON serialization time
-- Avoid
SELECT *
FROM Orders
-- Better
SELECT
OrderId,
CustomerName,
Status,
CreatedDate
FROM Orders
Returning only the required data is especially important for APIs that serve thousands of requests every minute.
5. Database Indexing Matters More Than Most Code Changes
Many developers immediately begin optimizing C# code while ignoring the execution plan generated by SQL Server.
A missing index can turn a query that executes in milliseconds into one that takes several seconds.
Regularly review:
- Execution Plans
- Missing Index Recommendations
- Table Scans
- Index Fragmentation
- Query Store Reports
Never add indexes blindly. Every index improves reads but also adds overhead to INSERT, UPDATE, and DELETE operations. Always evaluate indexes using production-like workloads.
6. Use Asynchronous Programming Correctly
ASP.NET Core was designed around asynchronous I/O. Every request that waits on SQL Server, a REST API, cloud storage, or the file system should be asynchronous.
Synchronous database calls block valuable thread pool threads. Under heavy traffic, this leads to thread starvation, increased response times, and reduced throughput.
public async Task<Order> GetOrder(int id)
{
return await _repository.GetOrderAsync(id);
}
Avoid using .Result or .Wait() inside ASP.NET
Core applications. They can reduce scalability and may introduce
deadlocks in certain environments.
7. Cache Data That Rarely Changes
One of the fastest database queries is the one you never execute.
Enterprise applications frequently reload data that changes only once a day or even once a month.
Examples include:
- Countries
- States
- Shipping carriers
- Tax rates
- Configuration settings
- Product categories
var countries = await _memoryCache.GetOrCreateAsync(
"Countries",
async entry =>
{
entry.AbsoluteExpirationRelativeToNow =
TimeSpan.FromHours(12);
return await repository.GetCountriesAsync();
});
Proper caching reduces SQL Server load while dramatically improving response times.
8. Enable Response Compression
APIs often return large JSON payloads. Compressing these responses reduces bandwidth consumption and improves page load times.
ASP.NET Core supports both Gzip and Brotli compression.
In many applications, enabling response compression reduces payload sizes by 60–80%.
Smaller responses not only improve user experience but also lower bandwidth costs for cloud-hosted applications.
9. Reduce JSON Serialization Overhead
Returning an entire Entity Framework entity often sends significantly more data than the client actually requires.
Instead, create lightweight DTOs containing only the required properties.
public class OrderSummaryDto
{
public int OrderId { get; set; }
public string CustomerName { get; set; }
public string Status { get; set; }
}
Smaller JSON objects reduce:
- Serialization time
- Memory allocation
- Network traffic
- Browser parsing time
10. Let SQL Connection Pooling Work for You
Opening SQL Server connections is relatively expensive. Fortunately, ADO.NET automatically manages a connection pool for each unique connection string.
Always create connections as late as possible and dispose them as soon as you're finished.
using var connection =
new SqlConnection(connectionString);
await connection.OpenAsync();
Never keep connections open longer than necessary.
11. Move Long Running Work to Background Services
Users should never wait while your application generates PDFs, sends emails, synchronizes shipments, or processes large imports.
Instead, return a response immediately and process heavy workloads using background services.
Good candidates include:
- Email notifications
- Invoice generation
- Shipping label creation
- Import/export processing
- Scheduled maintenance jobs
Moving long-running tasks to background services improves perceived application speed while increasing the number of requests your API can process concurrently.
12. Reduce Memory Allocations
High memory allocation rates force the .NET Garbage Collector to run more frequently, which can negatively impact application throughput.
Common improvements include:
- Reuse objects where practical.
- Avoid unnecessary string concatenation.
- Use
StringBuilderfor repeated string operations. - Return lightweight DTOs instead of large entity graphs.
- Avoid loading unnecessary collections into memory.
Performance optimization isn't only about CPU speed. Efficient memory usage often has an equally significant impact on scalability.
13. Optimize LINQ Queries
LINQ is one of the most productive features of C#, but poorly written queries can become expensive when working with large collections or databases.
Keep LINQ expressions simple and allow Entity Framework Core to translate them into efficient SQL. Avoid loading unnecessary records into memory before filtering.
// Less efficient
var activeCustomers = context.Customers
.ToList()
.Where(c => c.IsActive);
// Better
var activeCustomers = await context.Customers
.Where(c => c.IsActive)
.ToListAsync();
Always filter data inside SQL Server whenever possible rather than retrieving all records and filtering them in memory.
14. Optimize SQL Queries
The fastest ASP.NET Core API cannot compensate for slow SQL queries. SQL Server should always be included in your performance optimization strategy.
Review execution plans regularly and identify expensive operations such as table scans, missing indexes, implicit conversions, and key lookups.
- Review execution plans.
- Keep statistics updated.
- Avoid unnecessary SELECT * statements.
- Index frequently filtered columns.
- Return only required data.
15. Implement Server-Side Pagination
Returning thousands of rows to a web browser wastes memory, bandwidth, and processing time.
Every large data grid should support:
- Pagination
- Sorting
- Searching
- Filtering
var orders = await context.Orders
.OrderByDescending(x => x.OrderDate)
.Skip((page - 1) * pageSize)
.Take(pageSize)
.ToListAsync();
Server-side pagination dramatically reduces response sizes and keeps applications responsive as databases grow.
16. Design Lightweight APIs
Modern APIs should return only the information the client actually needs. Avoid exposing entire entity graphs or deeply nested objects.
Smaller payloads improve:
- Serialization speed
- Network transfer
- Browser rendering
- Mobile performance
17. Log Smartly, Not Excessively
Logging is essential for diagnosing production issues, but excessive logging can reduce performance and generate unnecessary storage costs.
Follow these guidelines:
- Use Information logs for important business events.
- Use Warning logs for recoverable issues.
- Use Error logs for failures.
- Avoid logging every successful database call.
- Never log sensitive customer information.
18. Monitor Production Continuously
Performance tuning doesn't stop after deployment. Production monitoring helps identify slow endpoints, SQL bottlenecks, memory leaks, and unexpected spikes in traffic before they affect users.
Useful metrics include:
- Average response time
- 95th percentile response time
- Error rate
- SQL execution time
- CPU utilization
- Memory usage
19. Load Test Before Production
Many applications perform well with ten users but fail under one thousand concurrent requests.
Simulate realistic workloads using tools such as:
- k6
- Apache JMeter
- Azure Load Testing
Load testing reveals scalability issues long before customers discover them.
20. Optimize Static Assets
Images, JavaScript, CSS, and downloadable files should be optimized and cached effectively.
Consider:
- Browser caching
- Brotli compression
- Image optimization
- Lazy loading
- Content Delivery Networks (CDNs)
Faster static asset delivery improves overall page speed and contributes to better Core Web Vitals scores.
These 20 techniques form the foundation of high-performance ASP.NET Core applications. Start with measurement, address the biggest bottlenecks first, and iterate.