# HTTP Troubleshooting Common HTTP integration issues and solutions. ## 404 Not Found ### Issue: Endpoint not found **Symptoms:** ``` HTTP/1.1 404 Not Found ``` **Possible Causes:** #### 1. Endpoint Not Mapped **Problem:** ```csharp var app = builder.Build(); // Missing MapSvrntyCommands() or MapSvrntyQueries() app.Run(); ``` **Solution:** ```csharp var app = builder.Build(); app.MapSvrntyCommands(); // Add this app.MapSvrntyQueries(); // Add this app.Run(); ``` #### 2. Wrong URL **Problem:** ```bash # Wrong POST /api/command/CreateUser # Capital C # Correct POST /api/command/createUser # Lowercase c ``` URLs are case-sensitive in lowerCamelCase. #### 3. Command/Query Not Registered **Problem:** ```csharp // Missing registration // builder.Services.AddCommand(); ``` **Solution:** ```csharp builder.Services.AddCommand(); ``` #### 4. [IgnoreCommand] or [IgnoreQuery] **Problem:** ```csharp [IgnoreCommand] // This prevents endpoint generation public record CreateUserCommand { } ``` **Solution:** Remove the attribute if you want an HTTP endpoint. ### Debugging ```csharp // List all registered endpoints var app = builder.Build(); app.MapSvrntyCommands(); app.MapSvrntyQueries(); // Before app.Run() var endpoints = app.Services.GetRequiredService(); foreach (var endpoint in endpoints.Endpoints) { Console.WriteLine($"{endpoint.DisplayName}: {endpoint.Metadata}"); } app.Run(); ``` ## 400 Bad Request ### Issue: Validation failed **Symptoms:** ```json { "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1", "title": "One or more validation errors occurred.", "status": 400, "errors": { "Name": ["Name is required"] } } ``` **Causes:** #### 1. Missing Required Fields **Request:** ```json { "email": "john@example.com" // Missing "name" field } ``` **Solution:** Include all required fields. #### 2. Invalid Data Format **Problem:** ```json { "age": "twenty-five" // String instead of number } ``` **Solution:** ```json { "age": 25 } ``` #### 3. Validation Rules Violated **Validator:** ```csharp RuleFor(x => x.Age) .GreaterThanOrEqualTo(18); ``` **Request:** ```json { "age": 16 // Fails validation } ``` **Solution:** Send valid data that meets all validation rules. ## 401 Unauthorized ### Issue: Missing or invalid authentication **Symptoms:** ``` HTTP/1.1 401 Unauthorized ``` **Causes:** #### 1. Missing Authentication Header **Problem:** ```bash curl -X POST http://localhost:5000/api/command/createUser # No Authorization header ``` **Solution:** ```bash curl -X POST http://localhost:5000/api/command/createUser \ -H "Authorization: Bearer eyJhbGc..." ``` #### 2. Expired Token **Problem:** JWT token has expired. **Solution:** Refresh the token or obtain a new one. #### 3. Invalid Token **Problem:** Token is malformed or invalid. **Solution:** Verify token is correctly formatted and signed. ### Debugging ```csharp app.Use(async (context, next) => { var logger = context.RequestServices.GetRequiredService>(); if (context.User.Identity?.IsAuthenticated == false) { logger.LogWarning("Unauthenticated request to {Path}", context.Request.Path); } await next(); }); ``` ## 403 Forbidden ### Issue: Not authorized **Symptoms:** ``` HTTP/1.1 403 Forbidden ``` **Causes:** #### 1. Authorization Service Denied **Authorization Service:** ```csharp public Task CanExecuteAsync(...) { return Task.FromResult(false); // Always denies } ``` **Solution:** Check authorization logic. #### 2. Missing Role **Problem:** ```csharp app.MapSvrntyCommands().RequireAuthorization(policy => { policy.RequireRole("Admin"); // User doesn't have Admin role }); ``` **Solution:** Ensure user has required role. ### Debugging ```csharp public class DeleteUserCommandAuthorization : ICommandAuthorizationService { private readonly ILogger _logger; public async Task CanExecuteAsync( DeleteUserCommand command, ClaimsPrincipal user, CancellationToken cancellationToken) { var isAdmin = user.IsInRole("Admin"); _logger.LogInformation( "Authorization check for DeleteUser: UserId={UserId}, IsAdmin={IsAdmin}", command.UserId, isAdmin); if (!isAdmin) { _logger.LogWarning( "User {UserName} attempted to delete user {UserId} without Admin role", user.Identity?.Name, command.UserId); } return isAdmin; } } ``` ## 415 Unsupported Media Type ### Issue: Wrong Content-Type **Symptoms:** ``` HTTP/1.1 415 Unsupported Media Type ``` **Causes:** #### 1. Missing Content-Type Header **Problem:** ```bash curl -X POST http://localhost:5000/api/command/createUser \ -d '{"name":"John"}' # Missing -H "Content-Type: application/json" ``` **Solution:** ```bash curl -X POST http://localhost:5000/api/command/createUser \ -H "Content-Type: application/json" \ -d '{"name":"John"}' ``` #### 2. Wrong Content-Type **Problem:** ```bash -H "Content-Type: text/plain" ``` **Solution:** ```bash -H "Content-Type: application/json" ``` ## 500 Internal Server Error ### Issue: Unhandled exception **Symptoms:** ``` HTTP/1.1 500 Internal Server Error ``` **Common Causes:** #### 1. Null Reference Exception **Problem:** ```csharp public async Task HandleAsync(GetUserQuery query, CancellationToken cancellationToken) { var user = await _repository.GetByIdAsync(query.UserId, cancellationToken); return MapToDto(user); // user is null! } ``` **Solution:** ```csharp public async Task HandleAsync(GetUserQuery query, CancellationToken cancellationToken) { var user = await _repository.GetByIdAsync(query.UserId, cancellationToken); if (user == null) throw new KeyNotFoundException($"User {query.UserId} not found"); return MapToDto(user); } ``` #### 2. Database Connection Issues **Problem:** ``` Connection to database failed ``` **Solution:** - Check connection string - Verify database is running - Check firewall rules - Verify credentials #### 3. Missing Dependency **Problem:** ``` Cannot resolve service for type 'IUserRepository' ``` **Solution:** ```csharp builder.Services.AddScoped(); ``` ### Debugging ```csharp app.UseExceptionHandler(errorApp => { errorApp.Run(async context => { var exceptionHandlerFeature = context.Features.Get(); var exception = exceptionHandlerFeature?.Error; var logger = context.RequestServices.GetRequiredService>(); logger.LogError(exception, "Unhandled exception occurred"); context.Response.StatusCode = 500; context.Response.ContentType = "application/json"; await context.Response.WriteAsJsonAsync(new { error = app.Environment.IsDevelopment() ? exception?.Message : "An error occurred", stackTrace = app.Environment.IsDevelopment() ? exception?.StackTrace : null }); }); }); ``` ## CORS Errors ### Issue: CORS policy blocks request **Browser Console:** ``` Access to fetch at 'http://localhost:5000/api/command/createUser' from origin 'http://localhost:3000' has been blocked by CORS policy ``` **Causes:** #### 1. CORS Not Configured **Problem:** ```csharp // Missing CORS configuration var app = builder.Build(); app.MapSvrntyCommands(); ``` **Solution:** ```csharp builder.Services.AddCors(options => { options.AddDefaultPolicy(policy => { policy.WithOrigins("http://localhost:3000") .AllowAnyMethod() .AllowAnyHeader(); }); }); var app = builder.Build(); app.UseCors(); // Add before MapSvrntyCommands app.MapSvrntyCommands(); ``` #### 2. Wrong Order **Problem:** ```csharp app.MapSvrntyCommands(); app.UseCors(); // Too late! ``` **Solution:** ```csharp app.UseCors(); // Must be before MapSvrntyCommands app.MapSvrntyCommands(); ``` #### 3. Credentials Without Specific Origin **Problem:** ```csharp policy.AllowAnyOrigin() .AllowCredentials(); // Error: Can't use both ``` **Solution:** ```csharp policy.WithOrigins("https://example.com") .AllowCredentials(); ``` ## JSON Serialization Issues ### Issue: Properties not deserializing **Problem:** ```csharp public record CreateUserCommand { public string Name { get; init; } = string.Empty; } ``` **Request:** ```json { "name": "John Doe" // Lowercase 'name' } ``` **Result:** Name is empty string (default value) **Solution:** JSON property names are case-insensitive by default in ASP.NET Core, but ensure: ```csharp builder.Services.ConfigureHttpJsonOptions(options => { options.SerializerOptions.PropertyNameCaseInsensitive = true; // Default }); ``` ### Issue: Circular reference **Problem:** ```csharp public class User { public int Id { get; set; } public List Orders { get; set; } } public class Order { public int Id { get; set; } public User User { get; set; } // Circular reference! } ``` **Solution:** Use DTOs without circular references: ```csharp public record UserDto { public int Id { get; init; } public List Orders { get; init; } = new(); } public record OrderSummaryDto { public int Id { get; init; } public decimal TotalAmount { get; init; } // No User property - breaks the cycle } ``` ## Handler Not Found ### Issue: Handler not resolved from DI **Symptoms:** ``` Unable to resolve service for type 'ICommandHandler' ``` **Causes:** #### 1. Handler Not Registered **Problem:** ```csharp // Missing handler registration ``` **Solution:** ```csharp builder.Services.AddCommand(); ``` #### 2. Wrong Lifetime **Problem:** ```csharp // Handler depends on Scoped service but registered as Singleton builder.Services.AddSingleton(); ``` **Solution:** ```csharp builder.Services.AddCommand(); // Uses Scoped lifetime by default ``` ## Debugging Tools ### Enable Detailed Errors ```csharp if (app.Environment.IsDevelopment()) { app.UseDeveloperExceptionPage(); } ``` ### Logging ```csharp builder.Logging.AddConsole(); builder.Logging.SetMinimumLevel(LogLevel.Debug); ``` ### Request/Response Logging ```csharp app.Use(async (context, next) => { var logger = context.RequestServices.GetRequiredService>(); logger.LogInformation( "Request: {Method} {Path}", context.Request.Method, context.Request.Path); await next(); logger.LogInformation( "Response: {StatusCode}", context.Response.StatusCode); }); ``` ## Common Mistakes ### ❌ Wrong HTTP Method ```bash # Wrong - Queries support GET/POST, not PUT curl -X PUT http://localhost:5000/api/query/getUser ``` ### ❌ Missing await ```csharp public async Task HandleAsync(GetUserQuery query, CancellationToken cancellationToken) { var user = _repository.GetByIdAsync(query.UserId, cancellationToken); // Missing await! return MapToDto(user); // Error: user is Task, not User } ``` ### ❌ Blocking async calls ```csharp // Don't do this var result = handler.HandleAsync(query, cancellationToken).Result; // Blocks thread // Do this var result = await handler.HandleAsync(query, cancellationToken); ``` ## Best Practices ### ✅ DO - Enable detailed errors in development - Use proper logging - Handle exceptions gracefully - Return appropriate status codes - Test with Swagger UI - Use integration tests - Log authorization failures ### ❌ DON'T - Don't expose detailed errors in production - Don't ignore validation errors - Don't skip authentication/authorization - Don't block async calls with .Result or .Wait() - Don't swallow exceptions ## See Also - [HTTP Integration Overview](README.md) - [Endpoint Mapping](endpoint-mapping.md) - [HTTP Configuration](http-configuration.md) - [Swagger Integration](swagger-integration.md)