【发布时间】:2022-02-02 16:37:04
【问题描述】:
(以下所有内容最初都是为 .Net 5.0 编写的,但现在针对 .Net 6.0)
考虑将此 Asp.Net 控制器用作 REST Api:
[AllowAnonymous]
[Route("[controller]")]
[ApiController]
[ApiConventionType(typeof(DefaultApiConventions))]
public class DebugController : ControllerBase {
private readonly ILoggingWrapper log;
public DebugController(ILoggingWrapper log) {
this.log = log;
log.Information("Constructor called");
}
private async Task Slow() {
await Task.Delay(15000).ConfigureAwait(false);
}
[Authorize()]
[HttpGet]
[Route("testSlow")]
public async Task<ActionResult> TestSlow() {
await Slow().ConfigureAwait(false);
return Ok();
}
[Authorize()]
[HttpGet]
[Route("testFast")]
public async Task<ActionResult> TestFast() {
return Ok();
}
}
我配置了一个 Swagger 页面,我可以在其中按需调用 TestSlow 和 TestFast。
体验#1
- 在 Swagger 页面打开的情况下打开浏览器选项卡,
- 只打电话
TestSlow
结果
DebugController构造函数立即进入,然后TestSlow立即启动,15秒后返回
经验#2
- 在 Swagger 页面打开的情况下打开浏览器选项卡,
- 在 Swagger 页面打开的情况下打开另一个浏览器选项卡,
- 在第一个 Swagger 页面上,只调用
TestSlow - 快速切换到其他Swagger页面,拨打
TestFast
结果
-
DebugController构造函数立即进入,然后 TestSlow 立即启动 - 当调用
TestFast,而Testslow仍在运行时,DebugController构造函数立即进入,TestFast 立即启动。
上述两种体验的行为符合我的预期:Asp.Net 是多线程的,调用一个端点并不会阻止另一个客户端调用另一个端点,即使第一个端点仍在为第一个客户端提供服务。
体验#3(奇怪的体验)
- 在 Swagger 页面打开的情况下打开浏览器选项卡,
- 在 Swagger 页面打开的情况下打开另一个浏览器选项卡,
- 在第一个 Swagger 页面上,仅致电
TestSlow - 快速切换到另一个 Swagger 页面,在那里也可以拨打
TestSlow
结果
-
DebugController构造函数立即进入,然后TestSlow立即启动 - 当调用 other
TestSlow时,Controller 的构造器在第一次调用 TestSlow 完全完成并返回之前不会被调用!。实际上,对 TestSlow 的两次调用是按顺序发生的。
为什么会这样?为什么当我尝试调用同一个端点两次时,多线程似乎突然“消失”了,即使我是从两个不同的客户端执行的?
【问题讨论】:
-
你在发布模式下尝试过同样的实验吗?
-
您是否尝试过不调试(并使用日志记录/时间测量来确定行为)?
-
您是否启用了会话状态?如果您看到来自同一浏览器的请求是串行而不是并行提供的,那通常是罪魁祸首。 (注意:同一浏览器中的两个选项卡不是“两个不同的客户端”;请尝试从两个不同的浏览器调用。)
-
为什么要使用 .ConfigureAwait(false)?这不需要在 ASP.NET Core 应用程序中完成。
-
这里只是挑剔...“异步”不等于“多线程”。 (不过,对您的问题没有任何改变...... async 应该是一个非阻塞调用。)
标签: c# asp.net swagger-ui .net-6.0