Claude
Skills
Sign in
Back

debug:dotnet

Included with Lifetime
$97 forever

Debug ASP.NET Core and .NET applications with systematic diagnostic approaches. This skill covers troubleshooting dependency injection container errors, middleware pipeline issues, Entity Framework Core query problems, configuration binding failures, authentication/authorization issues, and startup failures. Includes Visual Studio and VS Code debugging, dotnet-trace, dotnet-dump, dotnet-counters tools, Serilog configuration, Application Insights integration, and four-phase debugging methodology.

Code Review

What this skill does


# ASP.NET Core Debugging Guide

This guide provides a systematic approach to debugging ASP.NET Core applications, covering common error patterns, diagnostic tools, and resolution strategies.

## Common Error Patterns

### 1. Dependency Injection (DI) Container Errors

**Symptoms:**
- `InvalidOperationException: Unable to resolve service for type 'X'`
- `InvalidOperationException: A circular dependency was detected`
- `ObjectDisposedException: Cannot access a disposed object`

**Common Causes:**
```csharp
// Missing service registration
public class MyController
{
    public MyController(IMyService service) { } // Not registered in DI
}

// Circular dependency
public class ServiceA
{
    public ServiceA(ServiceB b) { }
}
public class ServiceB
{
    public ServiceB(ServiceA a) { } // Circular!
}

// Captive dependency (singleton holding scoped)
services.AddSingleton<ISingletonService, SingletonService>();
services.AddScoped<IScopedService, ScopedService>(); // Captured by singleton!
```

**Debugging Steps:**
1. Check `Program.cs` or `Startup.cs` for service registration
2. Verify service lifetime compatibility (Singleton > Scoped > Transient)
3. Use `IServiceProvider.GetRequiredService<T>()` for explicit resolution
4. Enable detailed DI errors in development:
```csharp
builder.Host.UseDefaultServiceProvider(options =>
{
    options.ValidateScopes = true;
    options.ValidateOnBuild = true;
});
```

**Resolution Patterns:**
```csharp
// Register missing service
builder.Services.AddScoped<IMyService, MyService>();

// Break circular dependency with Lazy<T> or factory
builder.Services.AddScoped<ServiceA>();
builder.Services.AddScoped<ServiceB>(sp =>
    new ServiceB(() => sp.GetRequiredService<ServiceA>()));

// Fix captive dependency - make both singleton or use factory
builder.Services.AddSingleton<IScopedService>(sp =>
    sp.CreateScope().ServiceProvider.GetRequiredService<ScopedService>());
```

### 2. Middleware Pipeline Issues

**Symptoms:**
- Requests returning unexpected status codes
- Authentication/authorization not working
- CORS errors
- Request body already read exceptions
- Response already started exceptions

**Common Causes:**
```csharp
// Wrong middleware order
app.UseAuthorization(); // Must come AFTER UseAuthentication!
app.UseAuthentication();

// Missing middleware
app.UseRouting();
// Missing UseAuthentication() and UseAuthorization()
app.MapControllers();

// Response already started
app.Use(async (context, next) =>
{
    await context.Response.WriteAsync("Hello"); // Response started
    await next(); // Next middleware tries to modify headers - ERROR
});
```

**Debugging Steps:**
1. Add diagnostic middleware to trace pipeline:
```csharp
app.Use(async (context, next) =>
{
    Console.WriteLine($"Request: {context.Request.Path}");
    await next();
    Console.WriteLine($"Response: {context.Response.StatusCode}");
});
```
2. Check middleware order matches recommended sequence
3. Enable developer exception page in development
4. Check for `Response.HasStarted` before modifying response

**Correct Middleware Order:**
```csharp
app.UseExceptionHandler("/error");
app.UseHsts();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors();
app.UseAuthentication();
app.UseAuthorization();
app.UseSession();
app.MapControllers();
```

### 3. Entity Framework Core Query Problems

**Symptoms:**
- `InvalidOperationException: The instance of entity type 'X' cannot be tracked`
- N+1 query problems (excessive database queries)
- `DbUpdateConcurrencyException`
- Lazy loading returning null
- Query performance issues

**Common Causes:**
```csharp
// N+1 problem
var orders = context.Orders.ToList();
foreach (var order in orders)
{
    Console.WriteLine(order.Customer.Name); // Each access = new query
}

// Tracking conflict
var entity = context.Products.Find(1);
context.Products.Update(new Product { Id = 1 }); // Already tracked!

// Missing Include for related data
var order = context.Orders.First(); // Customer is null!
```

**Debugging Steps:**
1. Enable sensitive data logging:
```csharp
optionsBuilder
    .EnableSensitiveDataLogging()
    .EnableDetailedErrors()
    .LogTo(Console.WriteLine, LogLevel.Information);
```
2. Use SQL Server Profiler or EF Core logging to inspect queries
3. Check for `AsNoTracking()` usage on read-only queries
4. Verify `Include()` statements for related entities

**Resolution Patterns:**
```csharp
// Eager loading to prevent N+1
var orders = context.Orders
    .Include(o => o.Customer)
    .Include(o => o.OrderItems)
    .ToList();

// Use AsNoTracking for read-only queries
var products = context.Products
    .AsNoTracking()
    .Where(p => p.Price > 100)
    .ToList();

// Handle concurrency with retry
try
{
    await context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException ex)
{
    var entry = ex.Entries.Single();
    await entry.ReloadAsync();
    // Retry or merge changes
}

// Split queries for complex includes
var orders = context.Orders
    .Include(o => o.OrderItems)
    .AsSplitQuery()
    .ToList();
```

### 4. Configuration Binding Failures

**Symptoms:**
- Configuration values are null or default
- `InvalidOperationException` when binding to options
- Environment-specific settings not loading
- Secrets not being read

**Common Causes:**
```csharp
// Mismatched property names
public class MyOptions
{
    public string ConnectionString { get; set; } // But appsettings has "connectionString"
}

// Missing section
services.Configure<MyOptions>(config.GetSection("NonExistent"));

// Wrong environment file
// appsettings.Development.json not loading in Development
```

**Debugging Steps:**
1. Log all configuration sources:
```csharp
foreach (var source in builder.Configuration.Sources)
{
    Console.WriteLine(source.GetType().Name);
}
```
2. Dump effective configuration:
```csharp
Console.WriteLine(builder.Configuration.GetDebugView());
```
3. Verify `ASPNETCORE_ENVIRONMENT` is set correctly
4. Check file names match exactly (case-sensitive on Linux)

**Resolution Patterns:**
```csharp
// Validate options on startup
services.AddOptions<MyOptions>()
    .Bind(config.GetSection("MyOptions"))
    .ValidateDataAnnotations()
    .ValidateOnStart();

// Use strongly-typed configuration
public class MyOptions
{
    public const string SectionName = "MySettings";

    [Required]
    public string ApiKey { get; set; } = string.Empty;

    [Range(1, 100)]
    public int MaxRetries { get; set; } = 3;
}

// Load with validation
builder.Services.AddOptions<MyOptions>()
    .BindConfiguration(MyOptions.SectionName)
    .ValidateDataAnnotations()
    .ValidateOnStart();
```

### 5. Authentication/Authorization Issues

**Symptoms:**
- 401 Unauthorized when credentials are correct
- 403 Forbidden with correct roles
- JWT token validation failures
- Cookie authentication not persisting
- Claims not available in controllers

**Common Causes:**
```csharp
// Missing authentication scheme
[Authorize] // No scheme specified, uses default
public class MyController { }

// Wrong claim type for roles
options.TokenValidationParameters = new TokenValidationParameters
{
    RoleClaimType = "role", // But token has "roles"
};

// Cookie not being sent (SameSite issues)
options.Cookie.SameSite = SameSiteMode.Strict; // Blocks cross-site
```

**Debugging Steps:**
1. Log authentication events:
```csharp
services.AddAuthentication()
    .AddJwtBearer(options =>
    {
        options.Events = new JwtBearerEvents
        {
            OnAuthenticationFailed = context =>
            {
                Console.WriteLine($"Auth failed: {context.Exception}");
                return Task.CompletedTask;
            },
            OnTokenValidated = context =>
            {
                Console.WriteLine($"Token validated for: {context.Principal?.Identity?.Name}");
                return Task.CompletedTask;
            }
        };
    });
```
2. Inspect JWT tokens at jwt.io
3. Check claims in controller: `User.Claims

Related in Code Review