在 ASP.NET Core 中有三种返回 数据
和 HTTP状态码
的方式,最简单的就是直接返回指定的类型实例,如下代码所示:
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
[HttpGet]
public IEnumerable 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
实例。
虽然返回指定的类型 是最简单粗暴的,但它只能返回数据,附带不了http状态码,而 IActionResult 实例可以将 数据 + Http状态码
一同带给前端,最后就是 ActionResult
它封装了前面两者,可以实现两种模式的自由切换,吧。
接下来一起讨论下如何在 ASP.NET Core Web API
中使用这三种方式。
在项目的 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 authors = new List();
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 Get()
{
return authors;
}
[HttpGet("{id}", Name = "Get")]
public Author Get(int id)
{
return authors.Find(x => x.Id == id);
}
}
}
最简单的方式就是在 Action 中直接返回一个 简单类型 或者 复杂类型,其实在上面的代码清单中,可以看到 Get 方法返回了一个 authors 集合,看清楚了,这个方法定义的是 IEnumerable
。
[HttpGet]
public IEnumerable Get()
{
return authors;
}
在 ASP.NET Core 3.0 开始,你不仅可以定义同步形式的 IEnumerable
方法,也可以定义异步形式的 IAsyncEnumerable
方法,后者的不同点在于它是一个异步模式的集合,好处就是 不阻塞
当前的调用线程,关于 IAsyncEnumerable
更多的知识,我会在后面的文章中和大家分享。
下面的代码展示了如何用 异步集合
来改造 Get 方法。
[HttpGet]
public async IAsyncEnumerable Get()
{
var authors = await GetAuthors();
await foreach (var author in authors)
{
yield return author;
}
}
如果你要返回 data + httpcode
的双重需求,那么 IActionResult 就是你要找的东西,下面的代码片段展示了如何去实现。
[HttpGet]
public IActionResult Get()
{
if (authors == null)
return NotFound("No records");
return Ok(authors);
}
上面的代码有 Ok
,NotFound
两个方法,对应着 OKResult,NotFoundResult, Http Code 对应着 200,404。当然还有其他的如:CreatedResult, NoContentResult, BadRequestResult, UnauthorizedResult, 和 UnsupportedMediaTypeResult,都是 IActionResult 的子类。
ActionResult
实例ActionResult
是在 ASP.NET Core 2.1 中被引入的,它的作用就是包装了前面这种模式,怎么理解呢? 就是即可以返回 IActionResult ,也可以返回指定类型,从 ActionResult
类下的两个构造函数中就可以看的出来。
public sealed class ActionResult : 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"));
}
Value = value;
}
public ActionResult(ActionResult result)
{
if (typeof(IActionResult).IsAssignableFrom(typeof(TValue)))
{
throw new ArgumentException(Resources.FormatInvalidTypeTForActionResultOfT(typeof(TValue), "ActionResult"));
}
Result = (result ?? throw new ArgumentNullException("result"));
}
}
有了这个基础,接下来看看如何在 Action 方法中去接这两种类型。
[HttpGet]
public ActionResult> Get()
{
if (authors == null)
return NotFound("No records");
return authors;
}
和文章之前的 Get 方法相比,这里直接返回 authors
而不需要再用 OK(authors)
包装,是不是一个非常好的简化呢? 接下来再把 Get 方法异步化,首先考虑下面返回 authors 集合的异步方法。
private async Task> GetAuthors()
{
await Task.Delay(100).ConfigureAwait(false);
return authors;
}
值得注意的是,异步方法必须要有至少一个 await 语句,如果不这样做的话,编译器会提示一个警告错误,告知你这个方法将会被 同步执行
,为了避免出现这种尴尬,我在 Task.Delay
上做了一个 await。
下面就是更新后的 Get 方法,注意一下这里我用了 await 去调用刚才创建的异步方法,代码参考如下。
[HttpGet]
public async Task>> 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
更多高质量干货:参见我的 GitHub: csharptranslate