我们有一个需要连接到慢速数据库进程并向客户端返回值的Web服务,因此尝试异步运行它以阻止它阻塞线程。但是,如果我们进行两次调用,它们会按顺序运行,而不是异步运行。呼叫1在5秒后返回,在10后呼叫2,在15后呼叫3,依此类推。
这是(简化测试版)代码 -
public class ImportAsyncController : AsyncController
{
[HttpPost]
[Authorize(Roles = "Admin, ContentAdmin, ContentEdit")]
public async Task<string> SlowProcess()
{
await Task.Delay(5000);
return "Hello, world!";
}
}
IIS 7.5,默认设置。遗产项目所以并非完全不可能,项目文件中的其他地方有一些东西迫使它但不知道是什么,抱歉。
作为参考,从中调用的实际代码调用SQL服务器sproc。它在内部使用sp_getapplock进行并发逻辑,并在SSMS中运行时正确返回 - 调用1运行完成,调用&gt; 1如果调用1仍在运行则返回错误代码,否则返回自身完成。那个逻辑很好;问题实际上是在队列中按顺序处理Web请求,因此在调用1完成之前,调用&gt; 1甚至不会被调用。
我们做错了什么?
答案 0 :(得分:2)
如果您正在写入会话,则可能会发生这种情况。基本上,Session对象将被锁定,直到请求完成,这给出了同步调用的错觉。
示例强>
由于以下Action会写入会话,因此会锁定会话对象,直到请求完成(5秒后)。如果您要从客户端调用此操作异步,它将在5秒,10秒,15秒等后返回。
public async Task<string> SlowProcess() {
Session["Hello"] = "World";
await Task.Delay(5000);
return "Hello, world!";
}
<强>解决方案强>
如果需要使用会话对象,可以告诉控制器使用ReadOnly模式,这样可以防止会话被锁定。要执行此操作,请使用控制器上的SessionStateBehaviour属性(不是操作)。
你会看到这样的东西......
[SessionState(System.Web.SessionState.SessionStateBehavior.ReadOnly)]
public class HomeController : Controller
{
public async Task<string> SlowProcess()
{
Session["Hello"] = "World";
await Task.Delay(5000);
return "Hello, world!";
}
}
希望这有帮助。
<强>更新强>
我发现了一篇很好的文章,解释了您可能觉得有用的问题。看看吧!
http://johnculviner.com/asp-net-concurrent-ajax-requests-and-session-state-blocking/