这是一个艰难的。使用完全相同的查询字符串,完全相同的以下代码:
using (var db = new SqlConnection(queryString))
{
await db.OpenAsync();
var results = await db.ExecuteSomethingAsync...;
db.Close();
{
从Windows应用程序运行时可以正常工作。但是,当从IIS Express或IIS 7运行时,它将永远停留在await OpenAsync()
。如果我用db.Open()
替换该行,它可以工作。有什么建议吗?
答案 0 :(得分:5)
await
,因为同步上下文想要为单个请求序列化工作。您发布的代码本身可能很好 - await
不会阻止。但是,我希望在调用链的某个位置,您可以调用.Wait()
或访问.Result
,而不是await
。
这里有几个选项:
.Wait()
或.Result
(或类似的) - 而是仅使用await
并使其成为正确的异步操作或使用.ConfigureAwait(false)
告诉它忽略同步上下文;不幸的是,这需要添加到所有你await
的地方,即
await db.OpenAsync().ConfigureAwait(false);
var results = await db.ExecuteSomethingAsync(...).ConfigureAwait(false);
或者,只使用同步代码 - 在大多数情况下,sql将快速运行非常 - 因此推送异步不一定可以帮助你可能认为;显然这可能因使用情况而异;但要记住的一个关键点是,ASP.NET已经具有固有的线程 - 这并不是说整个服务器在这里停止运行
答案 1 :(得分:5)
正如其他人所提到的,首先确保您的层次结构没有Wait
或Result
次调用。一系列async
方法在一个依赖于框架的入口点结束。在UI / WebForms应用程序中,这通常是async void
事件处理程序。在WebAPI / MVC应用程序中,这通常是async
操作。
要检查ASP.NET的另外两件事是:
UseTaskFriendlySynchronizationContext
设置为true
。如果您需要在多个平台上的共享库中支持async
,您可能会发现Microsoft.Bcl.Async
NuGet库非常有用。
答案 2 :(得分:0)
我注意到在ASP.Net Web Forms代码隐藏中编写async / await代码时要记住的另一个要点,那就是确保页面声明中的Async =“true”。默认情况下,此属性为false。
如果您不这样做,那么您可以看到您的页面处于永久加载状态。
<%@ Page Language="C#" Async="true" %>
另外,在.Net 4.5中,根据Stephen的回答,我们需要在web config appsettings部分将'UseTaskFriendlySynchronizationContext'设置为true。另一个有用的appsetting是 AllowAsyncDuringSyncStages ,对于Webforms代码隐藏中的async / await代码,它需要为false。默认情况下,这些设置均为false。
<add key="aspnet:AllowAsyncDuringSyncStages" value="false" />
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true"/>
我在ASP.Net WebForm中有以下示例async / await代码,该代码使用上述设置非常快速地运行并且使用像Stephen建议的那样一直等待。如果没有遵循这些建议,那么您可以在浏览器中看到Webforms页面永远加载。
protected async void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
string sql = @"DELETE FROM dbo.Table1
WHERE Processed = 1";
SqlConnection conn = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["MainDB"].ConnectionString);
SqlCommand cmd = new SqlCommand(sql, conn);
int numberOfRecordsUpdated = await UpdateDatabaseAsync(conn, cmd);
}
}
public async Task<int> UpdateDatabaseAsync(SqlConnection conn, SqlCommand cmd)
{
int i = 0;
try
{
await conn.OpenAsync();
i = await cmd.ExecuteNonQueryAsync();
}
catch (Exception ex)
{
//log the error
Elmah.ErrorSignal.FromCurrentContext().Raise(ex);
}
finally
{
if (conn != null)
{
conn.Close();
conn.Dispose();
}
if (cmd != null)
{
cmd.Dispose();
}
}
return i;
}