Use this file to discover all available pages before exploring further.
By default, Problemize maps common .NET exceptions to appropriate HTTP status codes. You can customize this behavior by implementing your own status code mapper.
Problemize includes a StatusCodeMapper that handles common .NET exceptions:
// 400 Bad RequestArgumentNullExceptionArgumentOutOfRangeExceptionInvalidOperationExceptionValidationExceptionFormatExceptionOverflowExceptionNullReferenceException// 401 UnauthorizedUnauthorizedAccessException// 404 Not FoundKeyNotFoundExceptionFileNotFoundExceptionDirectoryNotFoundException// 405 Method Not AllowedNotSupportedException// 408 Request TimeoutTimeoutException// 501 Not ImplementedNotImplementedException// 500 Internal Server Error (default)All other exceptions
To create your own status code mapper, implement the IStatusCodeMapper interface:
1
Create your mapper class
Implement the IStatusCodeMapper interface with your custom logic:
MyCustomStatusCodeMapper.cs
using FloppyShelf.Problemize.Interfaces;namespace MyApi.Exceptions;public class MyCustomStatusCodeMapper : IStatusCodeMapper{ public int GetStatusCode(Exception exception) { return exception switch { // Your custom exceptions ResourceNotFoundException => StatusCodes.Status404NotFound, BusinessRuleViolationException => StatusCodes.Status422UnprocessableEntity, DuplicateResourceException => StatusCodes.Status409Conflict, RateLimitExceededException => StatusCodes.Status429TooManyRequests, // Fallback to common .NET exceptions ArgumentNullException => StatusCodes.Status400BadRequest, UnauthorizedAccessException => StatusCodes.Status401Unauthorized, KeyNotFoundException => StatusCodes.Status404NotFound, TimeoutException => StatusCodes.Status408RequestTimeout, // Default for unknown exceptions _ => StatusCodes.Status500InternalServerError }; }}
You can chain exception types or add complex logic inside the switch expression based on exception properties.
2
Register your custom mapper
Pass your custom mapper to the UseExceptionHandling method in Program.cs:
Program.cs
using MyApi.Exceptions;using FloppyShelf.Problemize;var builder = WebApplication.CreateBuilder(args);// Register services with custom status code mapperbuilder.Services.UseExceptionHandling( statusCodeMapper: new MyCustomStatusCodeMapper());var app = builder.Build();// Enable exception handling middlewareapp.UseExceptionHandling();app.MapControllers();app.Run();
3
Test your mapper
Throw your custom exceptions in your controllers and verify the correct status codes:
UserController.cs
[ApiController][Route("api/[controller]")]public class UserController : ControllerBase{ [HttpGet("{id}")] public IActionResult GetUser(int id) { if (id <= 0) throw new ArgumentOutOfRangeException(nameof(id), "User ID must be positive"); var user = _userService.FindById(id); if (user == null) throw new ResourceNotFoundException($"User with ID {id} not found"); return Ok(user); } [HttpPost] public IActionResult CreateUser(CreateUserRequest request) { if (_userService.EmailExists(request.Email)) throw new DuplicateResourceException($"User with email {request.Email} already exists"); var user = _userService.Create(request); return CreatedAtAction(nameof(GetUser), new { id = user.Id }, user); }}
You can delegate to the default mapper for common exceptions:
public class ComposedStatusCodeMapper : IStatusCodeMapper{ private readonly StatusCodeMapper _defaultMapper = new(); public int GetStatusCode(Exception exception) { // Handle custom exceptions first var statusCode = exception switch { ResourceNotFoundException => StatusCodes.Status404NotFound, BusinessRuleViolationException => StatusCodes.Status422UnprocessableEntity, DuplicateResourceException => StatusCodes.Status409Conflict, _ => 0 // Indicate no match }; // Fall back to default mapper if no custom match return statusCode != 0 ? statusCode : _defaultMapper.GetStatusCode(exception); }}
Always include a default case in your mapper to handle unexpected exception types. Returning 500 Internal Server Error is recommended for safety.