You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 00:22:04