异步执行存储过程而不等待它并阻塞UI

时间:2019-05-06 22:42:12

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

我有几个存储过程,可以在ASP.NET Web窗体应用程序中对数据库进行INSERT或UPDATE。我希望执行这些查询,但不希望用户的UI或页面执行等待它们完成。它们并不需要很长的时间(不到一秒钟),但这是用户必须等待页面加载的一秒钟。

我通常正在考虑将日志记录或历史记录插入表中。用户的页面视图不依赖于查询的执行或结果。

我正在尝试使用.NET的异步方法,例如ExecuteNonQueryAsync()。但是我认为我在概念上错了。 ExecuteNonQueryAsync()似乎用于并行运行两个或多个运行时间更长的数据库操作,并阻塞UI,直到两个操作都完成为止。

private async Task<string> DoTransaction()
{
    string value = "";

    using (SqlConnection objCS = DB.AdminNET())
    {
        await objCS.OpenAsync();
        using (SqlTransaction t = objCS.BeginTransaction())
        using (SqlCommand objCommand = new SqlCommand("WAITFOR DELAY '00:00:05'; EXEC logtiming @line", objCS, t))
        {
            try
            {
                objCommand.Parameters.Add("@line", SqlDbType.VarChar).Value = "log me";
                await objCommand.ExecuteNonQueryAsync();
            }
            catch
            {
                t.Rollback();
                throw;
            }

            t.Commit();

            value = "done";
        }
    }

    return value;
}

protected async void Page_Load(object sender, EventArgs e)
{
    await DoTransaction(g);
}

此代码将在引入的延迟之后插入我的测试数据。但是,它将整个页面响应保留给用户,直到延迟结束。理想情况下,我希望页面立即返回给用户,然后五秒钟后,我将在表中看到结果。 ExecuteNonQueryAsync()是错误的工具吗?还是我可以做出一些尚未找到的更改,例如。 “不等”?

1 个答案:

答案 0 :(得分:4)

  

ExecuteNonQueryAsync()似乎正在...阻塞UI,直到两个操作都完成。

是的,这就是ASP.NET的工作方式。所有其他HTTP服务器(例如ASP.NET Core和Node.js)都以相同的方式工作:仅发送一个响应,并且仅在请求处理程序完成时才发送-无论处理程序是同步还是异步,都是如此。

有关更多信息,请参见我的article on async ASP.NET;相关部分:

  

异步代码不是灵丹妙药

     

与异步请求处理一样,它不能解决您的所有问题。关于异步和等待可以在ASP.NET上执行的操作,存在一些常见的误解。

     

当一些开发人员了解异步并等待时,他们认为这是服务器代码“屈服”于客户端(例如浏览器)的一种方式。但是,在ASP.NET上进行异步和等待只能“屈服”到ASP.NET运行时。 HTTP协议保持不变,并且每个请求仍然只有一个响应。如果在异步/等待之前需要SignalR或AJAX或UpdatePanel,则在异步/等待之后仍需要SignalR或AJAX或UpdatePanel。

解决此问题的正确方法是使用reliable queue with an independent background processing application。您的Web请求处理程序仅将一个项目放入队列中,然后快速返回给客户。然后,后台应用程序处理该队列并进行实际的数据库更改。