Generic ActionResult return type for API Controller

℡╲_俬逩灬. 提交于 2020-01-15 04:45:27

问题


I have the following use case for the GetProducts() method.

Good path: Returns array of type product: Product[]

Bad path: Returns status code of 500 and descriptive string error message.

(<?Type?> below is my own markup for the purposes of this post)

[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"
        }
    }
}

Is there a way I can declare an action result of a generic type or perhaps two types so that this can work?


回答1:


You would return an IActionResult. I highly recommend making is async as well. Here's how you can return anything through a controller method:

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

Note the Ok and NotFound are methods in the Controller abstract class which allows you to return any object you want, or no object at all.

I highly recommend before continuing using .net core you take a quick look at the example project template in Visual Studio, or if you're developing in another IDE run dotnet new mvc in your terminal.

If you want to handle an exception you should handle it on the lowest level. Assuming GetProductsFromDb() is the lowest level and you have no service layer (you'll regret this design choice in production!) you would put a try/catch.

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

Speed is NOT more important than stability in most cases, and certainly not at this stage of development. the cost of catching an exception is insignificant on something so high-level.




回答2:


You can return ActionResult<Product[]> as you wish. For the error scenario, though, you can use the StatusCode() helper method to return your error message, as follows:

[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");
        }
    }
}


来源:https://stackoverflow.com/questions/53615398/generic-actionresult-return-type-for-api-controller

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!