ASP.NET Core Performance Optimization Tips
By FoxLearn 1/2/2025 4:44:40 AM 30
In this article, I provide 12 tips to help you improve the performance of ASP.NET Core applications.
1. Avoid synchronous and use asynchronous
Avoid synchronous calls in ASP.NET Core applications, as they block further execution until the current task completes. For tasks like fetching data from an API or performing I/O operations, use asynchronous calls to improve performance and prevent delays.
For example, instead of using Task.Wait
or Task.Result
, you can use await
to handle asynchronous tasks more efficiently.
public class FileProcessor { public async Task ProcessFileAsync(string filePath) { // Asynchronously read the file var content = await File.ReadAllTextAsync(filePath); // Process the file content var result = await ProcessContentAsync(content); // Save the result asynchronously await SaveResultAsync(result); } private async Task<string> ProcessContentAsync(string content) { // Simulate asynchronous content processing await Task.Delay(1000); return content.ToUpper(); } private async Task SaveResultAsync(string result) { // Asynchronously save the result to a file await File.WriteAllTextAsync("output.txt", result); } }
In this example, file reading, content processing, and saving are all performed asynchronously, ensuring that each task runs concurrently without blocking the execution thread.
2. Asynchronous querying
Asynchronous queries prevent blocking a thread while executing database operations, which is crucial for maintaining responsive client applications. These queries allow other tasks to run concurrently while waiting for the database response.
Example methods include:
ToListAsync()
ToArrayAsync()
SingleAsync()
For example:
public async Task<List<Customer>> GetCustomersAsync() { using (var context = new CustomerContext()) { return await context.Customers.ToListAsync(); } }
In this example, the GetCustomersAsync
method fetches data from the database asynchronously, ensuring the application remains responsive.
3. Asynchronous saving
Asynchronous saving prevents thread blocking while changes are being saved to the database. The DbContext.SaveChangesAsync()
method provides an asynchronous alternative to the synchronous DbContext.SaveChanges()
.
For example:
public static async Task AddProductAsync(string productName) { using (var context = new ProductContext()) { var product = new Product { Name = productName }; context.Products.Add(product); await context.SaveChangesAsync(); } }
In this example, the AddProductAsync
method adds a new product to the database asynchronously, ensuring that the application remains responsive while saving data.
4. Optimize data access
Improving data access logic can significantly enhance application performance, as most applications depend on fetching, processing, and displaying data from a database. If data retrieval is slow, it can delay the entire application's load time.
Key recommendations for optimization include:
- Use asynchronous data access APIs.
- Avoid fetching unnecessary data in advance.
- Use no-tracking queries in Entity Framework Core for read-only data.
- Leverage LINQ filters and aggregates (
.Where
,.Select
,.Sum
) to offload filtering to the database.
Additionally, new features in EF Core provide advanced techniques to improve performance, especially for high-scale applications.
5. Use caching technology
To boost application performance, reduce the number of server requests by caching data. Store server responses for future use, eliminating the need to request the same data repeatedly.
These are some caching techniques:
- In-memory caching
- Distributed cache
- Cache tag helper
- Distributed cache tag helper
6. Use response caching middleware
Middleware controls response caching by storing and serving cached responses. It is part of the Microsoft.AspNetCore.ResponseCaching
package, automatically included in ASP.NET Core.
To enable response caching, add the Response Caching Middleware in Startup.ConfigureServices
:
public void ConfigureServices(IServiceCollection services) { services.AddResponseCaching(); services.AddRazorPages(); }
This sets up the caching service for the application.
7. Use JSON serialization
ASP.NET Core uses the System.Text.Json
namespace for JSON serialization by default, offering improved performance compared to Newtonsoft.Json
.
Key features of System.Text.Json
include:
- High performance
- Low memory allocation
- Standards-compliant capabilities
- Serialization of objects to JSON and deserialization of JSON to objects
8. Reduce HTTP requests
Reducing HTTP requests is a key optimization for improving performance. Caching web pages and avoiding client-side redirects can minimize server connections.
You can use the following techniques to reduce the HTTP requests:
- Minification
- Bundling
- Sprite images
These methods help speed up page load times by reducing the number of requests made to the server.
9. Use exceptions only when necessary
Exceptions should be used sparingly, as they are more time-consuming compared to other control flow patterns. Avoid throwing and catching exceptions during normal program execution, and reserve them for exceptional cases when necessary.
10. Use response compression
Response compression reduces file size and improves performance in ASP.NET Core applications. It is available as middleware and typically compresses assets like CSS, JavaScript, HTML, XML, and JSON. However, avoid compressing already compressed files (e.g., PNG images) and files smaller than 150-1000 bytes.
The Microsoft.AspNetCore.ResponseCompression
package is included by default. To enable response compression, configure it in Startup
as follows:
public class Startup { public void ConfigureServices(IServiceCollection services) { services.AddResponseCompression(); } public void Configure(IApplicationBuilder app, IHostingEnvironment env) { app.UseResponseCompression(); } }
You can also specify compression providers such as Brotli, Gzip, or custom providers:
public void ConfigureServices(IServiceCollection services) { services.AddResponseCompression(options => { options.Providers.Add<BrotliCompressionProvider>(); options.Providers.Add<GzipCompressionProvider>(); options.Providers.Add<CustomCompressionProvider>(); options.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat( new[] { "image/svg+xml" }); }); }
This helps reduce file sizes, improving load times and overall performance.
11. HttpContext accessibility improvements
In ASP.NET Core, HttpContext
is only valid during an active HTTP request. To ensure proper usage, follow these guidelines:
- Avoid storing
IHttpContextAccessor.HttpContext
in a field. - Do not access
HttpContext
from multiple threads. - Refrain from using
HttpContext
after the request has completed. - Do not capture
HttpContext
in background threads.
These practices help maintain thread safety and ensure proper lifecycle management of HttpContext
.
12. Client-side improvements
Client-side optimization is crucial for improving performance in ASP.NET Core websites.
Key strategies include:
- Bundling: Combine multiple files into one to reduce server requests. Multiple bundles can be used on a webpage.
- Minification: Remove unnecessary characters (like whitespace and comments) from code to reduce file size without affecting functionality.
- Loading JavaScript last: Load JavaScript files at the end to ensure faster display of static content.
- Content Delivery Network (CDN): Use a CDN to serve static files (e.g., images, JS, CSS) from the nearest server to reduce latency and improve load times.
- How to use Brotli for response compression in ASP.NET Core
- How to use SignalR in ASP.NET Core
- How to use the Dapper ORM in ASP.NET Core
- How to enable CORS in ASP.NET Core
- How to implement HTTP.sys web server in ASP.NET Core
- How to use File Providers in ASP.NET Core
- How to use policy-based authorization in ASP.NET Core
- How to enforce SSL in ASP.NET Core