.NET Core API服务层验证数据后如何向控制器返回状态码与信息
问题描述
我开发了一个小型汽车API,采用控制器、服务层、仓储层的分层架构。希望将数据验证逻辑从控制器迁移至服务层,由服务层返回200、404或400状态码,并附带对应的错误说明信息。具体应如何实现从服务层向控制器返回状态码及错误原因?
原有代码
API控制器方法
[HttpGet("GetById/{Id:int}", Name = "GetCar")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] [ProducesResponseType(StatusCodes.Status400BadRequest)] public IActionResult GetById(int Id) { if (Id < 1) { ModelState.AddModelError("CarIdIsZero", "Car Id Must Not Be Less Than One !"); return BadRequest(ModelState); } var car = _db.Car.FirstOrDefault(u => u.Id == Id); if (car == null) { ModelState.AddModelError("CarNotFound", "Car was not found !"); return NotFound(ModelState); } return Ok(car); }
服务层方法
public IActionResult GetById(int carId) { return; }
仓储层方法
public Car? GetById(int carId) { return _db.Car.FirstOrDefault(c => c.Id == carId); }
解决方案
服务层直接返回IActionResult会和ASP.NET Core的Web层耦合,违背分层架构的设计原则。正确的做法是定义通用返回模型,让服务层传递结果数据、状态码和错误信息,再由控制器转换为HTTP响应。
步骤1:定义通用服务返回模型
创建一个独立的结果类,用于服务层向控制器传递完整结果信息:
public class ServiceResult<T> { public int StatusCode { get; set; } public T? Data { get; set; } public Dictionary<string, string>? Errors { get; set; } // 快捷创建成功结果 public static ServiceResult<T> Success(T data) { return new ServiceResult<T> { StatusCode = StatusCodes.Status200OK, Data = data, Errors = null }; } // 快捷创建错误结果 public static ServiceResult<T> Error(int statusCode, Dictionary<string, string> errors) { return new ServiceResult<T> { StatusCode = statusCode, Data = default, Errors = errors }; } }
步骤2:改造服务层方法
在服务层实现验证逻辑,调用仓储并返回自定义结果模型:
private readonly ICarRepository _carRepository; // 构造函数注入仓储依赖 public CarService(ICarRepository carRepository) { _carRepository = carRepository; } public ServiceResult<Car> GetById(int carId) { // 验证ID合法性 if (carId < 1) { var errors = new Dictionary<string, string> { {"CarIdIsZero", "车辆ID不能小于1!"} }; return ServiceResult<Car>.Error(StatusCodes.Status400BadRequest, errors); } var car = _carRepository.GetById(carId); // 验证车辆是否存在 if (car == null) { var errors = new Dictionary<string, string> { {"CarNotFound", "未找到指定车辆!"} }; return ServiceResult<Car>.Error(StatusCodes.Status404NotFound, errors); } // 返回成功结果 return ServiceResult<Car>.Success(car); }
步骤3:改造控制器方法
控制器调用服务层,根据返回的结果模型生成对应的HTTP响应:
private readonly ICarService _carService; // 构造函数注入服务依赖 public CarController(ICarService carService) { _carService = carService; } [HttpGet("GetById/{Id:int}", Name = "GetCar")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] [ProducesResponseType(StatusCodes.Status400BadRequest)] public IActionResult GetById(int Id) { var result = _carService.GetById(Id); switch (result.StatusCode) { case StatusCodes.Status200OK: return Ok(result.Data); case StatusCodes.Status400BadRequest: foreach (var error in result.Errors!) { ModelState.AddModelError(error.Key, error.Value); } return BadRequest(ModelState); case StatusCodes.Status404NotFound: foreach (var error in result.Errors!) { ModelState.AddModelError(error.Key, error.Value); } return NotFound(ModelState); default: return StatusCode(result.StatusCode); } }
核心说明
- 服务层通过自定义模型传递结果,完全解耦Web层依赖,符合分层架构的职责分离原则。
- 通用
ServiceResult可复用在所有服务方法中,避免重复代码。 - 控制器仅负责将服务层结果转换为HTTP响应,专注于Web层的职责。
内容的提问来源于stack exchange,提问作者MrIzzat
相关产品推荐
相关产品推荐

