Web服务意外同步运行

时间:2015-11-25 09:49:11

标签: c# asp.net-mvc asynchronous async-await

我们有一个需要连接到慢速数据库进程并向客户端返回值的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甚至不会被调用。

我们做错了什么?

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/