Clean Architecture架构异常处理方案与错误码归属咨询
方案可行性验证与实践建议
一、MediatR装饰器处理领域层异常的落地思路
你的方案完全符合Clean Architecture的依赖规则,核心实现可以通过MediatR管道行为完成:
- 实现
IPipelineBehavior<TRequest, TResult>通用管道,其中TResult约束为Fluent Results的Result类型,在Handle方法中捕获领域层的两类异常,转换为Result.Fail()格式 - 该管道属于应用层组件,不侵入领域层,完美规避了在领域层引入Fluent Results的问题
- 示例代码:
public class DomainExceptionPipeline<TRequest, TResult> : IPipelineBehavior<TRequest, TResult> where TResult : Result, new() { public async Task<TResult> Handle(TRequest request, RequestHandlerDelegate<TResult> next, CancellationToken cancellationToken) { try { return await next(); } catch (BusinessRuleValidationException ex) { return new TResult().WithError(ex.Message) as TResult; } catch (NullReferenceException ex) { // 建议把空引用异常转化为明确的业务提示,避免暴露底层细节 return new TResult().WithError("请求的资源不存在或参数无效") as TResult; } } }
- 额外建议:领域层尽量避免抛出
NullReferenceException,可以通过提前空值检查抛出BusinessRuleValidationException,统一业务异常类型,减少后续处理分支。
二、基础设施层改用Fluent Results的核心原则
- 基础设施层(仓储、外部服务集成等)所有操作直接返回
Result/Result<T>,不再抛出异常,所有错误封装为Fluent Results的Error对象 - 错误信息需包含技术细节(如数据库连接超时、第三方服务返回错误码),但不要关联HTTP状态码——基础设施层属于底层实现,可能被API、后台任务、控制台程序等多种上层组件调用,硬编码HTTP状态码会导致严重耦合,违反单一职责原则。
关于HTTP状态码的决策方案
- 禁止基础设施层返回HTTP状态码:底层组件不应该依赖上层API的协议细节,否则后续扩展其他调用场景时会面临大量代码改造
- 由API层统一决定HTTP状态码:
- 在基础设施层返回
Error时,通过WithMetadata附加错误类型标识(比如ErrorType.InfrastructureFailure、ErrorType.DataNotFound) - API层实现统一的结果处理逻辑,根据
Result中的错误类型映射对应的HTTP状态码:- 领域层业务规则校验失败 → 400 Bad Request
- 基础设施层故障(如数据库连接失败) → 500 Internal Server Error
- 资源不存在 → 404 Not Found
- 示例处理逻辑:
- 在基础设施层返回
public class BaseApiController : ControllerBase { protected IActionResult MapResultToResponse(Result result) { if (result.IsSuccess) return Ok(result.Value); var firstError = result.Errors.First(); if (firstError.Metadata.TryGetValue("ErrorType", out var errorTypeObj) && errorTypeObj is ErrorType errorType) { return errorType switch { ErrorType.BusinessRuleViolation => BadRequest(result.Errors.Select(e => e.Message)), ErrorType.InfrastructureFailure => StatusCode(500, "服务内部异常,请稍后重试"), ErrorType.NotFound => NotFound(result.Errors.Select(e => e.Message)), _ => BadRequest("请求参数无效") }; } return BadRequest("请求处理失败"); } }
额外优化点
- 强制所有MediatR Handler的返回类型统一为
Result/Result<T>,避免混合返回值与异常的情况 - 可以给Fluent Results的
Error扩展自定义方法,快速添加错误类型元数据,简化基础设施层的错误封装代码
内容的提问来源于stack exchange,提问作者PelikanFix16
相关产品推荐
相关产品推荐

