如何在 ASP.NET Core Web API 中以三種方式返回數據

在 ASP.NET Core 中有三種返回 數據HTTP狀態碼 的方式,最簡單的就是直接返回指定的類型實例,如下代碼所示:


    [ApiController]
    [Route("[controller]")]
    public class WeatherForecastController : ControllerBase
    {
        [HttpGet]
        public IEnumerable<WeatherForecast> Get()
        {
            var rng = new Random();
            return Enumerable.Range(1, 5).Select(index => new WeatherForecast
            {
                Date = DateTime.Now.AddDays(index),
                TemperatureC = rng.Next(-20, 55),
                Summary = Summaries[rng.Next(Summaries.Length)]
            })
            .ToArray();
        }
    }

除了這種,也可以返回 IActionResult 實例 和  ActionResult <T> 實例。

雖然返回指定的類型 是最簡單粗暴的,但它只能返回數據,附帶不了http狀態碼,而 IActionResult 實例可以將 數據 + Http狀態碼 一同帶給前端,最後就是 ActionResult<T> 它封裝了前面兩者,可以實現兩種模式的自由切換,????吧。

接下來一起討論下如何在 ASP.NET Core Web API 中使用這三種方式。

創建 Controller 和 Model 類

在項目的 Models 文件夾下新建一個 Author 類,代碼如下:


    public class Author
    {
        public int Id { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }

有了這個 Author 類,接下來創建一個 DefaultController 類。


using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;

namespace IDGCoreWebAPI.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class DefaultController : ControllerBase
    {
        private readonly List<Author> authors = new List<Author>();
        public DefaultController()
        {
            authors.Add(new Author()
            {
                Id = 1,
                FirstName = "Joydip",
                LastName = "Kanjilal"
            });
            authors.Add(new Author()
            {
                Id = 2,
                FirstName = "Steve",
                LastName = "Smith"
            });
        }

        [HttpGet]
        public IEnumerable<Author> Get()
        {
            return authors;
        }

        [HttpGet("{id}", Name = "Get")]
        public Author Get(int id)
        {
            return authors.Find(x => x.Id == id);
        }
    }
}

在 Action 中返回 指定類型

最簡單的方式就是在 Action 中直接返回一個 簡單類型 或者 複雜類型,其實在上面的代碼清單中,可以看到 Get 方法返回了一個 authors 集合,看清楚了,這個方法定義的是 IEnumerable<Author>


[HttpGet]
public IEnumerable<Author> Get()
{
   return authors;
}

在 ASP.NET Core 3.0 開始,你不僅可以定義同步形式的 IEnumerable<Author>方法,也可以定義異步形式的 IAsyncEnumerable<T>方法,後者的不同點在於它是一個異步模式的集合,好處就是 不阻塞 當前的調用線程,關於 IAsyncEnumerable<T> 更多的知識,我會在後面的文章中和大家分享。

下面的代碼展示瞭如何用 異步集合 來改造 Get 方法。


[HttpGet]
public async IAsyncEnumerable<Author> Get()
{
   var authors = await GetAuthors();
   await foreach (var author in authors)
   {
        yield return author;
   }
}

在 Action 中返回 IActionResult 實例

如果你要返回 data + httpcode 的雙重需求,那麼 IActionResult 就是你要找的東西,下面的代碼片段展示瞭如何去實現。


[HttpGet]
public IActionResult Get()
{
  if (authors == null)
      return NotFound("No records");

  return Ok(authors);
}

上面的代碼有 OkNotFound 兩個方法,對應着 OKResult,NotFoundResult, Http Code 對應着 200,404。當然還有其他的如:CreatedResult, NoContentResult, BadRequestResult, UnauthorizedResult, 和 UnsupportedMediaTypeResult,都是 IActionResult 的子類。

在 Action 中返回 ActionResult<T> 實例

ActionResult<T> 是在 ASP.NET Core 2.1 中被引入的,它的作用就是包裝了前面這種模式,怎麼理解呢?就是即可以返回 IActionResult ,也可以返回指定類型,從 ActionResult<TValue> 類下的兩個構造函數中就可以看的出來。


public sealed class ActionResult<TValue> : IConvertToActionResult
{
 public ActionResult Result  {get;}

 public TValue Value  {get;}

 public ActionResult(TValue value)
 {
  if (typeof(IActionResult).IsAssignableFrom(typeof(TValue)))
  {
   throw new ArgumentException(Resources.FormatInvalidTypeTForActionResultOfT(typeof(TValue), "ActionResult<T>"));
  }
  Value = value;
 }

 public ActionResult(ActionResult result)
 {
  if (typeof(IActionResult).IsAssignableFrom(typeof(TValue)))
  {
   throw new ArgumentException(Resources.FormatInvalidTypeTForActionResultOfT(typeof(TValue), "ActionResult<T>"));
  }
  Result = (result ?? throw new ArgumentNullException("result"));
 }
}

有了這個基礎,接下來看看如何在 Action 方法中去接這兩種類型。


[HttpGet]
public ActionResult<IEnumerable<Author>> Get()
{
  if (authors == null)
       return NotFound("No records");
   return authors;
}

和文章之前的 Get 方法相比,這裏直接返回 authors 而不需要再用 OK(authors) 包裝,是不是一個非常好的簡化呢?接下來再把 Get 方法異步化,首先考慮下面返回 authors 集合的異步方法。


private async Task<List<Author>> GetAuthors()
{
    await Task.Delay(100).ConfigureAwait(false);
    return authors;
}

值得注意的是,異步方法必須要有至少一個 await 語句,如果不這樣做的話,編譯器會提示一個警告錯誤,告知你這個方法將會被 同步執行,爲了避免出現這種尷尬,我在 Task.Delay 上做了一個 await。

下面就是更新後的 Get 方法,注意一下這裏我用了 await 去調用剛纔創建的異步方法,代碼參考如下。


[HttpGet]
public async Task<ActionResult<IEnumerable<Author>>> Get()
{
   var data = await GetAuthors();
   if (data == null)
        return NotFound("No record");
   return data;
}

如果你有一些定製化需求,可以實現一個自定義的 ActionResult 類,做法就是實現 IActionResult 中的 ExecuteResultAsync 方法即可。

譯文鏈接:https://www.infoworld.com/article/3520770/how-to-return-data-from-aspnet-core-web-api.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章