ASP.NET Core 中的所有 I/O 都是异步的。服务器会实现 Stream 接口,该接口同时具有同步和异步重载。应首选异步重载以避免阻止线程池线程。阻止线程可能会导致线程池资源不足。
请勿这样做:下面的示例使用 。它会阻止当前线程等待结果。下面是异步中同步的示例。.
public class GoodStreamReaderController : Controller
{
[HttpGet("/contoso")]
public async Task<ActionResult<ContosoData>> Get()
{
var json = await new StreamReader(Request.Body).ReadToEndAsync();
return JsonSerializer.Deserialize<ContosoData>(json);
}
}
在上面的代码中,Get 将整个 HTTP 请求正文同步读取到内存中。如果客户端上传速度缓慢,则应用会进行异步中同步。应用进行异步中同步是因为 Kestrel 不支持同步读取。
请这样做:下面的示例使用 ,在读取时不会阻止线程。
public class GoodStreamReaderController : Controller
{
[HttpGet("/contoso")]
public async Task<ActionResult<ContosoData>> Get()
{
var json = await new StreamReader(Request.Body).ReadToEndAsync();
return JsonSerializer.Deserialize<ContosoData>(json);
}
}
上面的代码会将整个 HTTP 请求正文同步读取到内存中。
如果请求较大,则将整个 HTTP 请求正文读取到内存中可能会导致内存不足 (OOM) 状况。OOM 可能会导致拒绝服务。 有关详细信息,请参阅本文档中的避免将大型请求正文或响应正文读取到内存中。
请这样做:下面的示例使用非缓冲请求正文完全异步进行:
public class GoodStreamReaderController : Controller
{
[HttpGet("/contoso")]
public async Task<ActionResult<ContosoData>> Get()
{
return await JsonSerializer.DeserializeAsync<ContosoData>(Request.Body);
}
}
上面的代码将请求正文异步反序列化为 C# 对象。