• Controller action return types in ASP.NET Core web API


    原文:https://docs.microsoft.com/en-us/aspnet/core/web-api/action-return-types?view=aspnetcore-6.0

    ASP.NET Core offers the following options for web API controller action return types:

    This document explains when it's most appropriate to use each return type.

    Specific type

    The simplest action returns a primitive or complex data type (for example, string or a custom object type). Consider the following action, which returns a collection of custom Product objects:

    [HttpGet]
    public List<Product> Get() =>
        _repository.GetProducts();
    

    Without known conditions to safeguard against during action execution, returning a specific type could suffice. The preceding action accepts no parameters, so parameter constraints validation isn't needed.

    When multiple return types are possible, it's common to mix an ActionResult return type with the primitive or complex return type. Either IActionResult or ActionResult<T> are necessary to accommodate this type of action. Several samples of multiple return types are provided in this document.

    Return IEnumerable<T> or IAsyncEnumerable<T>

    In ASP.NET Core 2.2 and earlier, returning IEnumerable<T> from an action results in synchronous collection iteration by the serializer. The result is the blocking of calls and a potential for thread pool starvation. To illustrate, imagine that Entity Framework (EF) Core is being used for the web API's data access needs. The following action's return type is synchronously enumerated during serialization:

    public IEnumerable<Product> GetOnSaleProducts() =>
        _context.Products.Where(p => p.IsOnSale);
    

    To avoid synchronous enumeration and blocking waits on the database in ASP.NET Core 2.2 and earlier, invoke ToListAsync:

    public async Task<IEnumerable<Product>> GetOnSaleProducts() =>
        await _context.Products.Where(p => p.IsOnSale).ToListAsync();
    

    In ASP.NET Core 3.0 and later, returning IAsyncEnumerable<T> from an action:

    • No longer results in synchronous iteration.
    • Becomes as efficient as returning IEnumerable<T>.

    ASP.NET Core 3.0 and later buffers the result of the following action before providing it to the serializer:

    public IEnumerable<Product> GetOnSaleProducts() =>
        _context.Products.Where(p => p.IsOnSale);
    

    Consider declaring the action signature's return type as IAsyncEnumerable<T> to guarantee the asynchronous iteration. Ultimately, the iteration mode is based on the underlying concrete type being returned. MVC automatically buffers any concrete type that implements IAsyncEnumerable<T>.

    Consider the following action, which returns sale-priced product records as IEnumerable<Product>:

    [HttpGet("syncsale")]
    public IEnumerable<Product> GetOnSaleProducts()
    {
        var products = _repository.GetProducts();
    
        foreach (var product in products)
        {
            if (product.IsOnSale)
            {
                yield return product;
            }
        }
    }
    

    The IAsyncEnumerable<Product> equivalent of the preceding action is:

    [HttpGet("asyncsale")]
    public async IAsyncEnumerable<Product> GetOnSaleProductsAsync()
    {
        var products = _repository.GetProductsAsync();
    
        await foreach (var product in products)
        {
            if (product.IsOnSale)
            {
                yield return product;
            }
        }
    }
    

    Both of the preceding actions are non-blocking as of ASP.NET Core 3.0.

    IActionResult type

    The IActionResult return type is appropriate when multiple ActionResult return types are possible in an action. The ActionResult types represent various HTTP status codes. Any non-abstract class deriving from ActionResult qualifies as a valid return type. Some common return types in this category are BadRequestResult (400), NotFoundResult (404), and OkObjectResult (200). Alternatively, convenience methods in the ControllerBase class can be used to return ActionResult types from an action. For example, return BadRequest(); is a shorthand form of return new BadRequestResult();.

    Because there are multiple return types and paths in this type of action, liberal use of the [ProducesResponseType] attribute is necessary. This attribute produces more descriptive response details for web API help pages generated by tools like Swagger[ProducesResponseType] indicates the known types and HTTP status codes to be returned by the action.

    Synchronous action

    Consider the following synchronous action in which there are two possible return types:

    [HttpGet("{id}")]
    [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(Product))]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    public IActionResult GetById(int id)
    {
        if (!_repository.TryGetProduct(id, out var product))
        {
            return NotFound();
        }
    
        return Ok(product);
    }
    

    In the preceding action:

    • A 404 status code is returned when the product represented by id doesn't exist in the underlying data store. The NotFound convenience method is invoked as shorthand for return new NotFoundResult();.
    • A 200 status code is returned with the Product object when the product does exist. The Ok convenience method is invoked as shorthand for return new OkObjectResult(product);.

    Asynchronous action

    Consider the following asynchronous action in which there are two possible return types:

    C#
    [HttpPost]
    [Consumes(MediaTypeNames.Application.Json)]
    [ProducesResponseType(StatusCodes.Status201Created)]
    [ProducesResponseType(StatusCodes.Status400BadRequest)]
    public async Task<IActionResult> CreateAsync(Product product)
    {
        if (product.Description.Contains("XYZ Widget"))
        {
            return BadRequest();
        }
    
        await _repository.AddProductAsync(product);
    
        return CreatedAtAction(nameof(GetById), new { id = product.Id }, product);
    }
    

    In the preceding action:

    • A 400 status code is returned when the product description contains "XYZ Widget". The BadRequest convenience method is invoked as shorthand for return new BadRequestResult();.
    • A 201 status code is generated by the CreatedAtAction convenience method when a product is created. An alternative to calling CreatedAtAction is return new CreatedAtActionResult(nameof(GetById), "Products", new { id = product.Id }, product);. In this code path, the Product object is provided in the response body. A Location response header containing the newly created product's URL is provided.

    For example, the following model indicates that requests must include the Name and Description properties. Failure to provide Name and Description in the request causes model validation to fail.

    public class Product
    {
        public int Id { get; set; }
    
        [Required]
        public string Name { get; set; }
    
        [Required]
        public string Description { get; set; }
    }
    

    If the [ApiController] attribute in ASP.NET Core 2.1 or later is applied, model validation errors result in a 400 status code. For more information, see Automatic HTTP 400 responses.

    ActionResult<T> type

    ASP.NET Core includes ActionResult<T> return type for web API controller actions. It enables you to return a type deriving from ActionResult or return a specific typeActionResult<T> offers the following benefits over the IActionResult type:

    • The [ProducesResponseType] attribute's Type property can be excluded. For example, [ProducesResponseType(200, Type = typeof(Product))] is simplified to [ProducesResponseType(200)]. The action's expected return type is instead inferred from the T in ActionResult<T>.
    • Implicit cast operators support the conversion of both T and ActionResult to ActionResult<T>T converts to ObjectResult, which means return new ObjectResult(T); is simplified to return T;.

    C# doesn't support implicit cast operators on interfaces. Consequently, conversion of the interface to a concrete type is necessary to use ActionResult<T>. For example, use of IEnumerable in the following example doesn't work:

    [HttpGet]
    public ActionResult<IEnumerable<Product>> Get() =>
        _repository.GetProducts();
    

    One option to fix the preceding code is to return _repository.GetProducts().ToList();.

    Most actions have a specific return type. Unexpected conditions can occur during action execution, in which case the specific type isn't returned. For example, an action's input parameter may fail model validation. In such a case, it's common to return the appropriate ActionResult type instead of the specific type.

    Synchronous action

    Consider a synchronous action in which there are two possible return types:

    C#
    [HttpGet("{id}")]
    [ProducesResponseType(StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    public ActionResult<Product> GetById(int id)
    {
        if (!_repository.TryGetProduct(id, out var product))
        {
            return NotFound();
        }
    
        return product;
    }
    

    In the preceding action:

    • A 404 status code is returned when the product doesn't exist in the database.
    • A 200 status code is returned with the corresponding Product object when the product does exist. Before ASP.NET Core 2.1, the return product; line had to be return Ok(product);.

    Asynchronous action

    Consider an asynchronous action in which there are two possible return types:

    C#
    [HttpPost]
    [Consumes(MediaTypeNames.Application.Json)]
    [ProducesResponseType(StatusCodes.Status201Created)]
    [ProducesResponseType(StatusCodes.Status400BadRequest)]
    public async Task<ActionResult<Product>> CreateAsync(Product product)
    {
        if (product.Description.Contains("XYZ Widget"))
        {
            return BadRequest();
        }
    
        await _repository.AddProductAsync(product);
    
        return CreatedAtAction(nameof(GetById), new { id = product.Id }, product);
    }
    

    In the preceding action:

    • A 400 status code (BadRequest) is returned by the ASP.NET Core runtime when:
      • The [ApiController] attribute has been applied and model validation fails.
      • The product description contains "XYZ Widget".
    • A 201 status code is generated by the CreatedAtAction method when a product is created. In this code path, the Product object is provided in the response body. A Location response header containing the newly created product's URL is provided.

    Additional resources

  • 相关阅读:
    Atmel Studio 烧录 Atmega328P(Arduiono)
    JSP内置对象详解及示例
    Hash Map 详细解释及示例
    19年双非学长逆袭985考研经验贴
    camelCase命名规范
    开始我的编程之旅!
    【转】堆和栈的区别
    现场编写类似strstr/strcpy函数
    【转】C++多态篇1一静态联编,动态联编、虚函数与虚函数表vtable
    【转】TCP协议中的三次握手和四次挥手(图解)
  • 原文地址:https://www.cnblogs.com/panpanwelcome/p/15825752.html
Copyright © 2020-2023  润新知