# Debugging Guide

Advanced debugging techniques for .NET microservices development.

## Visual Studio Code Debugging

### Setup launch.json

```json
{
    "version": "0.2.0",
    "configurations": [
        {
            "name": ".NET Debug",
            "type": "coreclr",
            "request": "launch",
            "preLaunchTask": "build",
            "program": "${workspaceFolder}/src/MyService.API/bin/Debug/net10.0/MyService.API.dll",
            "args": [],
            "cwd": "${workspaceFolder}/src/MyService.API",
            "console": "internalConsole",
            "stopAtEntry": false,
            "env": {
                "ASPNETCORE_ENVIRONMENT": "Development"
            }
        },
        {
            "name": ".NET Attach",
            "type": "coreclr",
            "request": "attach"
        }
    ]
}
```

### Debug Tests

```json
{
    "name": ".NET Test Debug",
    "type": "coreclr",
    "request": "launch",
    "preLaunchTask": "build",
    "program": "dotnet",
    "args": [
        "test",
        "--filter",
        "FullyQualifiedName~MyTestMethod"
    ],
    "cwd": "${workspaceFolder}",
    "console": "internalConsole"
}
```

**Usage:**
1. Set breakpoint in test or code
2. F5 to start debugging
3. Step through with F10 (over) / F11 (into)

---

## Remote Debugging Docker Containers

### Enable remote debugging in Dockerfile

```dockerfile
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS debug
WORKDIR /src
COPY . .
RUN dotnet restore
RUN dotnet build --no-restore

# Install debugger
RUN apt-get update && apt-get install -y procps

EXPOSE 8080
EXPOSE 4024

ENTRYPOINT ["dotnet", "run", "--no-build", "--project", "src/MyService.API"]
```

### Docker Compose debug config

```yaml
services:
  my-service-debug:
    build:
      context: ../..
      dockerfile: services/my-service-net/Dockerfile
      target: debug
    environment:
      - ASPNETCORE_ENVIRONMENT=Development
      - DOTNET_USE_POLLING_FILE_WATCHER=true
    ports:
      - "8080:8080"
      - "4024:4024"  # Debugger port
    volumes:
      - ./src:/src:ro
```

### Attach to running container

```bash
# 1. Start container with debug enabled
docker-compose up my-service-debug

# 2. Find process ID
docker exec my-service-debug ps aux | grep dotnet

# 3. In VS Code, use "Attach to Process" configuration
# Select the dotnet process from Docker container
```

---

## Logging Strategies

### Structured Logging with Serilog

```csharp
// Program.cs
builder.Host.UseSerilog((context, config) =>
{
    config
        .ReadFrom.Configuration(context.Configuration)
        .Enrich.FromLogContext()
        .Enrich.WithProperty("Service", "MyService")
        .WriteTo.Console(new JsonFormatter())
        .WriteTo.File("logs/log-.txt", rollingInterval: RollingInterval.Day);
});

// Usage in code
_logger.LogInformation(
    "Creating order for {UserId} with {ItemCount} items and total {Total:C}",
    command.UserId, 
    command.Items.Count,
    order.Total
);
```

**Benefits:**
- Searchable structured data
- Context preservation
- Easy filtering

---

### Log Scopes

```csharp
using (_logger.BeginScope("OrderId: {OrderId}", orderId))
{
    _logger.LogInformation("Processing order");
    _logger.LogInformation("Validating items");
    _logger.LogInformation("Calculating total");
}

// All logs include OrderId automatically
```

---

## Debugging Tools

### dotnet-dump (Memory dumps)

```bash
# Install tool
dotnet tool install -g dotnet-dump

# Create dump of running process
dotnet-dump collect -p <pid>

# Analyze dump
dotnet-dump analyze <dump-file>

# Inside analyzer
> clrstack          # View call stack
> dumpheap -stat    # Heap statistics
> eeheap -gc        # GC heap info
```

---

### dotnet-trace (Performance tracing)

```bash
# Install tool
dotnet tool install -g dotnet-trace

# Collect trace
dotnet-trace collect -p <pid> --duration 00:00:30

# Convert to speedscope format
dotnet-trace convert trace.nettrace --format speedscope

# View in browser
open https://www.speedscope.app/
```

---

### dotnet-counters (Live metrics)

```bash
# Install tool
dotnet tool install -g dotnet-counters

# Monitor live
dotnet-counters monitor -p <pid>

# Custom metrics
dotnet-counters monitor \
    -p <pid> \
    --counters System.Runtime,Microsoft.AspNetCore.Hosting
```

---

## Database Debugging

### EF Core Query Logging

```csharp
// Enable sensitive data logging (Development only!)
builder.Services.AddDbContext<MyContext>(options =>
{
    options.UseNpgsql(connectionString);
    
    if (builder.Environment.IsDevelopment())
    {
        options
            .EnableSensitiveDataLogging()
            .EnableDetailedErrors();
    }
});
```

**Output:**
```
Executed DbCommand (23ms) [Parameters=[@p0='123'], CommandType='Text']
SELECT * FROM orders WHERE id = @p0
```

---

### SQL Profiling

```bash
# PostgreSQL: Enable query logging
# In postgresql.conf or docker-compose
POSTGRES_EXTRA_FLAGS="-c log_statement=all"

# View logs
docker-compose logs -f postgres | grep "statement:"
```

---

## HTTP Debugging

### Fiddler / Postman for API testing

**Setup authentication:**
```bash
# Get JWT token
curl -X POST http://localhost/api/v1/auth/login \
  -H "Content-Type: application/json" \
  -d '{"username":"test","password":"test123"}'

# Use token in requests
curl http://localhost/api/v1/orders \
  -H "Authorization: Bearer <token>"
```

---

### Request/Response logging middleware

```csharp
// Custom middleware
public class RequestResponseLoggingMiddleware
{
    private readonly RequestDelegate _next;
    private readonly ILogger _logger;
    
    public async Task InvokeAsync(HttpContext context)
    {
        // Log request
        context.Request.EnableBuffering();
        var requestBody = await ReadBodyAsync(context.Request.Body);
        
        _logger.LogInformation(
            "HTTP {Method} {Path} Body: {Body}",
            context.Request.Method,
            context.Request.Path,
            requestBody
        );
        
        // Capture response
        var originalBody = context.Response.Body;
        using var responseBody = new MemoryStream();
        context.Response.Body = responseBody;
        
        await _next(context);
        
        // Log response
        responseBody.Seek(0, SeekOrigin.Begin);
        var response = await new StreamReader(responseBody).ReadToEndAsync();
        
        _logger.LogInformation(
            "HTTP {StatusCode} Response: {Response}",
            context.Response.StatusCode,
            response
        );
        
        // Copy to original stream
        responseBody.Seek(0, SeekOrigin.Begin);
        await responseBody.CopyToAsync(originalBody);
    }
}
```

---

## Common Debugging Scenarios

### Find source of exception

```bash
# Enable first-chance exceptions in VS Code
# .vscode/launch.json
"exceptionOptions": {
    "breakpoints": {
        "raised": true,
        "userUnhandled": false
    }
}
```

---

### Memory leak investigation

```bash
# 1. Take baseline dump
dotnet-dump collect -p <pid> -o baseline.dump

# 2. Exercise application
# ... use the app normally ...

# 3. Take second dump
dotnet-dump collect -p <pid> -o leaked.dump

# 4. Compare
dotnet-dump analyze leaked.dump
> dumpheap -stat
# Look for growing object counts
```

---

### Slow request diagnosis

**Add request timing:**
```csharp
app.Use(async (context, next) =>
{
    var sw = Stopwatch.StartNew();
    await next();
    sw.Stop();
    
    if (sw.ElapsedMilliseconds > 1000)
    {
        _logger.LogWarning(
            "Slow request: {Method} {Path} took {Elapsed}ms",
            context.Request.Method,
            context.Request.Path,
            sw.ElapsedMilliseconds
        );
    }
});
```

---

## Performance Profiling

### BenchmarkDotNet

```csharp
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;

[MemoryDiagnoser]
public class OrderBenchmarks
{
    private Order _order;
    
    [GlobalSetup]
    public void Setup()
    {
        _order = new Order(/* ... */);
    }
    
    [Benchmark]
    public void AddItem()
    {
        _order.AddItem(Guid.NewGuid(), 1, 10.0m);
    }
}

// Run benchmarks
BenchmarkRunner.Run<OrderBenchmarks>();
```

---

## Quick Reference

### VS Code Shortcuts

| Action | Shortcut |
|--------|----------|
| Start debugging | F5 |
| Step over | F10 |
| Step into | F11 |
| Step out | Shift+F11 |
| Continue | F5 |
| Toggle breakpoint | F9 |
| Add watch | Right-click → Add to Watch |

### Useful Commands

```bash
# View running processes
ps aux | grep dotnet

# Find process by port
lsof -i :8080

# Kill process
kill -9 <pid>

# View environment variables
docker exec my-service env

# Execute command in container
docker exec -it my-service sh

# Follow logs with filter
docker logs -f my-service | grep ERROR
```

---

## Related Resources

- [Build Errors Catalog](build-errors.md)
- [Test Failures Guide](test-failures.md)
- Main Skill: [development-lifecycle](../SKILL.md)
- [.NET Debugging Documentation](https://learn.microsoft.com/en-us/dotnet/core/diagnostics/)
