ASP.NET Core 8 Web API -

Performance Optimization

Performance optimization is crucial for ensuring your ASP.NET Core 8 Web API can handle high loads efficiently. This guide covers various strategies and best practices for optimizing the performance of your web API, along with detailed explanations and examples.


1. Introduction to Performance Optimization

Optimizing performance involves making your application faster and more efficient. This can be achieved through various techniques, including caching, compression, minimizing network latency, optimizing data access, and more.


2. Caching

Caching is a powerful technique to improve performance by storing frequently accessed data in memory. This reduces the need to repeatedly fetch data from a database or external service.

2.1 In-Memory Caching Example:
        
            var builder = WebApplication.CreateBuilder(args);

// Add services to the container
builder.Services.AddControllers();
builder.Services.AddMemoryCache();

var app = builder.Build();

app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
        
    


2.2 Distributed Caching with Redis Example:
        
            var builder = WebApplication.CreateBuilder(args);

// Add services to the container
builder.Services.AddControllers();
builder.Services.AddStackExchangeRedisCache(options =>
{
    options.Configuration = builder.Configuration.GetConnectionString("Redis");
    options.InstanceName = "SampleInstance";
});

var app = builder.Build();

app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
        
    

3. Compression

Compression reduces the size of responses sent from the server to the client, decreasing the amount of data transferred and improving load times.

3.1 Configure Response Compression Program.cs:
        
            var builder = WebApplication.CreateBuilder(args);

// Add services to the container
builder.Services.AddControllers();
builder.Services.AddResponseCompression(options =>
{
    options.Providers.Add<GzipCompressionProvider>();
    options.EnableForHttps = true;
});
builder.Services.Configure<GzipCompressionProviderOptions>(options =>
{
    options.Level = System.IO.Compression.CompressionLevel.Fastest;
});

var app = builder.Build();

app.UseResponseCompression();
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
        
    

4. Minimize Network Latency

Network latency can significantly impact performance. Minimize latency by optimizing your API endpoints and reducing the number of network calls.

4.1 Use Asynchronous Programming Example:
        
            [ApiController]
[Route("[controller]")]
public class ProductsController : ControllerBase
{
    private readonly IProductService _productService;

    public ProductsController(IProductService productService)
    {
        _productService = productService;
    }

    [HttpGet("{id}")]
    public async Task<IActionResult> GetProduct(int id)
    {
        var product = await _productService.GetProductAsync(id);
        if (product == null)
        {
            return NotFound();
        }
        return Ok(product);
    }
}

public interface IProductService
{
    Task<Product> GetProductAsync(int id);
}

public class ProductService : IProductService
{
    public Task<Product> GetProductAsync(int id)
    {
        // Simulate a database call
        return Task.FromResult(new Product { Id = id, Name = "Product " + id });
    }
}

public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
}
        
    


4.2 Optimize API Endpoints Example:
        
            [ApiController]
[Route("[controller]")]
public class ProductsController : ControllerBase
{
    private readonly IProductService _productService;

    public ProductsController(IProductService productService)
    {
        _productService = productService;
    }

    [HttpGet("{id}")]
    public async Task<IActionResult> GetProduct(int id)
    {
        var product = await _productService.GetProductAsync(id);
        if (product == null)
        {
            return NotFound();
        }
        return Ok(product);
    }

    [HttpGet]
    public async Task<IActionResult> GetProducts([FromQuery] int page = 1, [FromQuery] int pageSize = 10)
    {
        var products = await _productService.GetProductsAsync(page, pageSize);
        return Ok(products);
    }
}

public interface IProductService
{
    Task<Product> GetProductAsync(int id);
    Task<IEnumerable<Product>> GetProductsAsync(int page, int pageSize);
}

public class ProductService : IProductService
{
    public Task<Product> GetProductAsync(int id)
    {
        // Simulate a database call
        return Task.FromResult(new Product { Id = id, Name = "Product " + id });
    }

    public Task<IEnumerable<Product>> GetProductsAsync(int page, int pageSize)
    {
        // Simulate a database call
        var products = Enumerable.Range(1, 100).Select(id => new Product { Id = id, Name = "Product " + id });
        return Task.FromResult(products.Skip((page - 1) * pageSize).Take(pageSize));
    }
}

public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
}
        
    

5. Optimize Data Access

Efficient data access is critical for performance. Optimize data queries and use efficient data structures.

5.1 Use Efficient Queries Example:
        
            [ApiController]
[Route("[controller]")]
public class ProductsController : ControllerBase
{
    private readonly IProductService _productService;

    public ProductsController(IProductService productService)
    {
        _productService = productService;
    }

    [HttpGet("{id}")]
    public async Task<IActionResult> GetProduct(int id)
    {
        var product = await _productService.GetProductAsync(id);
        if (product == null)
        {
            return NotFound();
        }
        return Ok(product);
    }
}

public interface IProductService
{
    Task<Product> GetProductAsync(int id);
}

public class ProductService : IProductService
{
    private readonly ApplicationDbContext _context;

    public ProductService(ApplicationDbContext context)
    {
        _context = context;
    }

    public async Task<Product> GetProductAsync(int id)
    {
        return await _context.Products.AsNoTracking().FirstOrDefaultAsync(p => p.Id == id);
    }
}

public class ApplicationDbContext : DbContext
{
    public DbSet<Product> Products { get; set; }
}

public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
}
        
    


5.2 Implement Paging Example:
        
            [ApiController]
[Route("[controller]")]
public class ProductsController : ControllerBase
{
    private readonly IProductService _productService;

    public ProductsController(IProductService productService)
    {
        _productService = productService;
    }

    [HttpGet]
    public async Task<IActionResult> GetProducts([FromQuery] int page = 1, [FromQuery] int pageSize = 10)
    {
        var products = await _productService.GetProductsAsync(page, pageSize);
        return Ok(products);
    }
}

public interface IProductService
{
    Task<IEnumerable<Product>> GetProductsAsync(int page, int pageSize);
}

public class ProductService : IProductService
{
    private readonly ApplicationDbContext _context;

    public ProductService(ApplicationDbContext context)
    {
        _context = context;
    }

    public async Task<IEnumerable<Product>> GetProductsAsync(int page, int pageSize)
    {
        return await _context.Products.AsNoTracking()
            .Skip((page - 1) * pageSize)
            .Take(pageSize)
            .ToListAsync();
    }
}

public class ApplicationDbContext : DbContext
{
    public DbSet<Product> Products { get; set; }
}

public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
}
        
    

6. Use Dependency Injection Efficiently

Efficient use of dependency injection (DI) can improve performance by reducing the overhead of object creation and lifetime management.

6.1 Scoped vs Singleton Services Example:
        
            var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();
builder.Services.AddScoped<IScopedService, ScopedService>();
builder.Services.AddSingleton<ISingletonService, SingletonService>();

var app = builder.Build();

app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();

public interface IScopedService { }
public class ScopedService : IScopedService { }

public interface ISingletonService { }
public class SingletonService : ISingletonService { }
        
    

7. Monitor and Profile Your Application

Monitoring and profiling your application helps identify performance bottlenecks and areas for improvement.

7.1 Use Application Insights Example:
        
            var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();
builder.Services.AddApplicationInsightsTelemetry(builder.Configuration["ApplicationInsights:InstrumentationKey"]);

var app = builder.Build();

app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
        
    


7.2 Profiling with DotTrace Example:
        
            // To profile your application with JetBrains DotTrace, follow these steps:
// 1. Install JetBrains DotTrace.
// 2. Open DotTrace and select 'Profile Local App'.
// 3. Choose 'Standalone .NET Core App' and specify the path to your application's executable.
// 4. Start profiling and analyze the results to identify performance bottlenecks.

// Example code to simulate a performance issue:
[ApiController]
[Route("[controller]")]
public class ProductsController : ControllerBase
{
    [HttpGet("{id}")]
    public IActionResult GetProduct(int id)
    {
        // Simulate a performance issue
        System.Threading.Thread.Sleep(2000);
        return Ok(new Product { Id = id, Name = "Product " + id });
    }
}

public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
}
        
    

8. Best Practices for Performance Optimization


9. Conclusion

Performance optimization is essential for ensuring that your ASP.NET Core 8 Web API can handle high loads efficiently. By following the strategies and best practices outlined in this guide, you can improve the performance and scalability of your web API, providing a better experience for your users.