问题
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