ASP.NET Core Performance Optimization Tips

By FoxLearn 1/2/2025 4:44:40 AM   30
ASP.NET Core offers several enhancements to reduce memory usage and boost performance.

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.