【问题标题】:Generic ActionResult return type for API ControllerAPI 控制器的通用 ActionResult 返回类型
【发布时间】:2018-12-04 14:42:01
【问题描述】:

GetProducts() 方法有以下用例。

好路径:返回产品类型数组:Product[]

错误路径:返回状态码 500 和描述性字符串错误消息。

(下面的<?Type?>是我自己的标记,用于本文的目的)

[Route("api/[controller]/[action]")]
[ApiController]
public class ProductsController : ControllerBase
{
    [HttpGet]
    public ActionResult<?Type?> GetProducts()
    {
        try
        {
            Product[] products = DataAccess.GetProductsFromDb();
            return products;
        }
        catch 
        {
            Response.StatusCode = 400;
            return "Error retrieving products list"
        }
    }
}

有没有办法我可以声明一个泛型类型或两种类型的操作结果,以便它可以工作?

【问题讨论】:

  • 使用Product[] 并在出现“错误路径”时抛出异常。内置错误处理程序将返回状态 500 和消息(您可以通过注册自己的错误处理程序进一步自定义)
  • 我读过抛出异常是一个更昂贵的过程,这就是我避免使用这种方法的原因。此外,我想避免潜在地泄露堆栈跟踪或任何服务器详细信息。这种方法是否足够安全?
  • 这不是 Web API 的工作方式。如果没有找到产品,请返回 OK(products)NotFound()
  • 如果遇到异常,正确的响应是 500 - 服务器错误。您可以使用 StatusCode() 将其返回
  • 公共 IActionResult GetProducts()

标签: c# asp.net-core .net-core asp.net-core-webapi


【解决方案1】:

您将返回一个 IActionResult。我强烈建议制作也是异步的。 以下是如何通过控制器方法返回任何内容:

[Route("api/{controller}")]
public class ProductsController : Controller
{
    [HttpGet]
    public async Task<IActionResult> GetProducts()
    {
        var products = await DataAccess.GetProductsFromDb();
        if (products is null)
        {
            return NotFound("Item not found!");
        }
        else
        {
            return Ok(products);
        }
    }
}

注意OkNotFoundController 抽象类中的方法,它们允许您返回任何您想要的对象,或者根本不返回任何对象。

我强烈建议您在继续使用 .net core 之前快速查看 Visual Studio 中的示例项目模板,或者如果您正在另一个 IDE 中进行开发,请在终端中运行 dotnet new mvc

如果你想处理一个异常,你应该在最低级别处理它。假设 GetProductsFromDb() 是最低级别并且您没有服务层(稍后您会后悔这种设计选择!)您将尝试/捕获。

[Route("api/{controller}")]
public class ProductsController : Controller
{
    [HttpGet]
    public async Task<IActionResult> GetProducts()
    {
        Products[] products;
        try
        {
            products = await DataAccess.GetProductsFromDb();
        }
        catch(Exception e)
        {
            Log.Error(e, "Unable to receive products");
            return InternalServerError("Unable to retrieve products, please try again later");
        }
        if (!products.Any())
        {
            return NotFound("No products were found");
        }
        else
        {
            return Ok(products);
        }
    }
}

在大多数情况下,速度并不比稳定性更重要,而且在这个开发阶段当然也不重要。捕获异常的成本在如此高的级别上是微不足道的,尤其是因为您的数据库调用将比捕获单个异常的开销慢几个数量级。

【讨论】:

  • 异步方法应该等待 DataAccess.GetProductsFromDb()
【解决方案2】:

您可以根据需要返回ActionResult&lt;Product[]&gt;。 但是,对于错误场景,您可以使用 StatusCode() 帮助器方法返回错误消息,如下所示:

[Route("api/[controller]/[action]")]
[ApiController]
public class ProductsController : ControllerBase
{
    [HttpGet]
    public ActionResult<Product[]> GetProducts()
    {
        try
        {
            Product[] products = DataAccess.GetProductsFromDb();
            return products;
        }
        catch 
        {
            return StatusCode(500, "Error retrieving products list");
        }
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-09-05
    • 1970-01-01
    • 2020-09-27
    • 1970-01-01
    • 1970-01-01
    • 2023-03-13
    • 1970-01-01
    • 2013-04-01
    相关资源
    最近更新 更多