Asp.Net 控制器看起来就像单线程一样。为什么?
Asp.Net controller seemingly behaves as if single-threaded. Why?
(以下所有内容最初是为 .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秒后returns
体验#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
时,控制器的构造函数 在第一次调用 TestSlow 完全完成并返回之前没有被调用!。实际上,对 TestSlow 的两次调用是顺序发生的。
这是为什么?为什么当我尝试两次调用同一个端点时,多线程似乎突然“消失”了,即使我是从两个不同的客户端调用的?
我很可能是无意中发现 会话状态 禁用 同时 为同一个端点提供多次调用的服务,如此处设计:
Disable Session state per-request in ASP.Net MVC
看来这不是多线程问题,而是网络应用程序配置(“设计使然”)问题。
@Richard deeming : Post 这是一个答案,我会把它标记为正确的。
(以下所有内容最初是为 .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秒后returns
体验#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
时,控制器的构造函数 在第一次调用 TestSlow 完全完成并返回之前没有被调用!。实际上,对 TestSlow 的两次调用是顺序发生的。
这是为什么?为什么当我尝试两次调用同一个端点时,多线程似乎突然“消失”了,即使我是从两个不同的客户端调用的?
我很可能是无意中发现 会话状态 禁用 同时 为同一个端点提供多次调用的服务,如此处设计:
Disable Session state per-request in ASP.Net MVC
看来这不是多线程问题,而是网络应用程序配置(“设计使然”)问题。
@Richard deeming : Post 这是一个答案,我会把它标记为正确的。