Why is DbContext Scoped?

DbContext is typically registered as Scoped because it is designed to handle a single unit of work, usually one HTTP request.

C#
builder.Services.AddDbContext<AppDbContext>();

By default, AddDbContext() registers it as Scoped.

Why Scoped?

For each request:

Problems with Singleton DbContext

C#
services.AddSingleton<AppDbContext>();

Bad because:

Problems with Transient DbContext

C#
services.AddTransient<AppDbContext>();

Each injection gets a new instance.

Code
RepositoryA -> DbContext A
RepositoryB -> DbContext B

A single business transaction may use multiple contexts, making transactions and tracking difficult.

InShort

DbContext is registered as Scoped because one database context should generally serve one request or unit of work. This ensures proper change tracking, transaction management, and thread safety while avoiding the problems associated with Singleton or excessive context creation from Transient lifetimes.

Why shouldn't Scoped be injected into Singleton?

Example

C#
services.AddScoped<IUserService, UserService>();
services.AddSingleton<ReportGenerator>();
C#
public class ReportGenerator
{
    public ReportGenerator(IUserService userService)
    {
    }
}

This causes a lifetime mismatch.

Why?

A Singleton is created once:

Code
Application Start
    |
    +-- Singleton Created

A Scoped service exists per request:

Code
Request 1 → UserService Instance A
Request 2 → UserService Instance B

The Singleton would hold a reference to the first scoped instance forever.

Problems

ASP.NET Core often throws:

Code
Cannot consume scoped service from singleton

Correct Approach

Inject:

or

and create a scope when needed.

InShort

A Scoped service has a shorter lifetime than a Singleton. Injecting a Scoped dependency into a Singleton can cause stale references, thread-safety issues, and runtime errors because the Singleton may outlive the Scoped object.

Why can caching improve performance AND create bugs?

Caching stores frequently accessed data in memory so it can be reused instead of repeatedly fetching it from a database or external service.

Performance Improvement

Without cache:

Code
Request
  ↓
Database
  ↓
Response

Every request hits the database.

With cache:

Code
Request
  ↓
Cache
  ↓
Response

Benefits:

Example:

C#
_memoryCache.GetOrCreate(
    "Products",
    entry =>
    {
        return repository.GetProducts();
    });

How Bugs Happen

Stale Data

Database:

Code
Product Price = 100

Cache:

Code
Product Price = 100

Database updated:

Code
Product Price = 120

Cache still returns:

Code
100

Users see incorrect data.

Cache Invalidation Problems

One of the hardest problems in software:

When should cache be refreshed?

Too long:

Too short:

Distributed Cache Issues

In multiple servers:

Code
Server A Cache = Updated
Server B Cache = Old

Users may receive inconsistent responses.

InShort

Caching improves performance by reducing expensive operations such as database queries and API calls. However, it can introduce bugs through stale data, invalidation issues, synchronization problems, and inconsistent state across multiple servers.

Why does an API become slow in production?

An API that is fast locally may become slow under real-world load.

1. Database Bottlenecks

Most common reason.

C#
var orders = _context.Orders.ToList();

Poor indexing or inefficient queries can dramatically increase response times.

2. N+1 Query Problem

C#
foreach(var order in orders)
{
    var customer = order.Customer;
}

One query becomes hundreds of queries.

3. External Service Calls

Even if your API is fast, waiting on external systems slows everything down.

4. Excessive Logging

C#
_logger.LogInformation(...);

Huge amounts of logging can impact performance.

5. Thread Pool Starvation

Blocking calls:

consume worker threads and reduce throughput.

6. Memory Pressure

Large objects:

C#
List<Customer> customers = GetMillions();

cause:

7. Network Latency

Production systems involve:

Code
Client
 ↓
Load Balancer
 ↓
API
 ↓
Database

Each hop adds latency.

InShort

APIs usually become slow in production due to database bottlenecks, N+1 queries, external service dependencies, excessive logging, memory pressure, thread pool starvation, high traffic, or network latency. Profiling and monitoring are essential to identify the real bottleneck.

Why does async improve scalability?

Many people think async makes code faster.

Important

Async doesn't necessarily make an operation faster.

It makes better use of server resources.

Synchronous Request

C#
public string GetData()
{
    var data = apiClient.GetData();
    return data;
}

Thread waits:

Code
Thread 1
   |
   | Waiting...
   | Waiting...
   | Waiting...

During waiting, the thread cannot serve other requests.

Asynchronous Request

C#
public async Task<string> GetData()
{
    return await apiClient.GetDataAsync();
}
Code
Thread starts work
      ↓
I/O operation starts
      ↓
Thread returned to pool
      ↓
I/O completes
      ↓
Thread resumes execution

The thread is free to handle other requests while waiting.

Example

Suppose:

Synchronous

Many threads remain blocked.

Code
100 Threads Busy

Asynchronous

Threads are released during I/O waits.

Code
10-20 Threads handling
100 Requests

Much better scalability.

InShort

Async improves scalability because it releases threads while waiting for I/O operations such as database calls, file access, or HTTP requests. This allows the server to handle more concurrent requests with the same hardware resources. Async improves throughput and resource utilization, though it does not necessarily make individual operations execute faster.

Summary

Understanding why DbContext is registered as Scoped, avoiding lifetime mismatches in dependency injection, using caching carefully, identifying production performance bottlenecks, and leveraging asynchronous programming appropriately are fundamental concepts for building scalable and reliable ASP.NET Core applications. These practices help improve performance, maintain thread safety, optimize resource utilization, and reduce common issues in production environments.