BitzOrcas 使用双错误处理策略:Result<T> 用于领域级失败,GlobalExceptionHandler 用于 HTTP 边界的 RFC 9457 ProblemDetails 转换。
Result<T> 模式
领域服务返回 Result<T> 而非抛出异常:
public Result<Note> CreateNote(string title, string content){ if (string.IsNullOrWhiteSpace(title)) return Result<Note>.Failure(Error.Validation("Note.Title", "标题不能为空"));
if (content.Length > 10000) return Result<Note>.Failure(Error.Validation("Note.Content", "内容过长"));
var note = new Note(title, content); return Result<Note>.Success(note);}错误类型
public enum ErrorType{ Validation, // 400 — 输入验证失败 NotFound, // 404 — 资源未找到 Conflict, // 409 — 重复/乐观并发冲突 Unauthorized, // 401 — 需要认证 Forbidden, // 403 — 权限不足 Failure, // 500 — 领域/业务规则失败 Infrastructure // 503 — 外部依赖失败}错误结构
public readonly record struct Error{ public ErrorType Type { get; } public string Code { get; } // 例如 "Note.NotFound" public string Description { get; }}GlobalExceptionHandler
在 HTTP 边界捕获未处理异常并转换为 ProblemDetails:
public class GlobalExceptionHandler : IExceptionHandler{ public async ValueTask<bool> TryHandleAsync( HttpContext httpContext, Exception exception, CancellationToken cancellationToken) { // 将异常类型映射到 ProblemDetails }}ProblemDetails 响应格式
所有错误响应遵循带 BitzOrcas 扩展的 RFC 9457:
{ "type": "https://docs.bitzsoft.com/problems/not-found", "title": "Not Found", "status": 404, "detail": "Note with ID 'abc123' was not found.", "instance": "/api/notes/abc123", "traceId": "00-abc123def456-...", "correlationId": "corr-789", "requestId": "req-012", "errorCode": "Note.NotFound"}标准扩展
| 扩展 | 来源 | 描述 |
|---|---|---|
traceId | Activity.Current | 分布式跟踪标识符 |
correlationId | CorrelationIdMiddleware | 请求关联 ID |
requestId | HttpContext | 每请求标识符 |
errorCode | Error.Code | 机器可读错误码 |
retryAfter | 限流器 | 允许重试前的秒数(仅 429) |
Result 到 HTTP 的转换
在 Minimal API 端点中:
app.MapPost("/api/notes", async ( CreateNoteCommand cmd, IMediator mediator) =>{ var result = await mediator.Send(cmd); return result.Match( onSuccess: value => Results.Created($"/api/notes/{value.Id}", value), onFailure: error => error.ToProblemDetails() );});验证错误
ValidationPipelineBehavior 捕获 IRequestRule 失败并返回结构化验证错误:
{ "type": "https://docs.bitzsoft.com/problems/validation", "title": "Validation Failed", "status": 400, "errors": { "Title": ["Title is required"], "Content": ["Content must not exceed 10000 characters"] }}限流错误(429)
{ "type": "https://docs.bitzsoft.com/problems/rate-limit-exceeded", "title": "Too Many Requests", "status": 429, "detail": "Rate limit exceeded.", "retryAfter": 60, "traceId": "...", "correlationId": "...", "errorCode": "RateLimit.Exceeded"}