DbConnection.Open()的作品,但dbConnection.OpenAsync()不
这是一个艰难的一个。使用完全相同的查询字符串,完全相同的下面的代码:DbConnection.Open()的作品,但dbConnection.OpenAsync()不
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()
替换该行,它可以工作。有什么建议么?
正如其他人所说,首先要确保你有没有Wait
或Result
调用您的层次结构。一个async
方法链终止于依赖于框架的入口点。在UI/WebForms应用程序中,这通常是一个async void
事件处理程序。在WebAPI/MVC应用程序中,这通常是一个async
操作。其他
两件事情来检查ASP.NET是:
- 确保您的目标平台是.NET 4.5。
- 确保您已将
UseTaskFriendlySynchronizationContext
设置为true
。
如果您需要支持async
在多个平台上的共享库,你会发现Microsoft.Bcl.Async
的NuGet库是有帮助的。
await
需要在ASP.NET中谨慎对待,因为同步上下文想要为单个请求序列化工作。您发布的代码本身可能很好 - await
不会阻止。不过,我预计在此呼叫链的某个地方,您拨打.Wait()
或访问.Result
,而不是await
。
有几个选择这里:
- 完全不使用
.Wait()
或.Result
(或类似)- 相反,只使用await
并使其正确异步操作 -
或,使用
.ConfigureAwait(false)
来告诉它忽略sync-context;不幸的是,这将需要添加到所有的地方,你await
,即await db.OpenAsync().ConfigureAwait(false); var results = await db.ExecuteSomethingAsync(...).ConfigureAwait(false);
,或者只使用同步码 - 在大多数情况下,SQL是要快速运行非常 - 所以推它异步是不一定帮助尽可能多的,你可能会想;显然这可能会因使用情况而异;但一个关键点要记住这里的是,ASP.NET已经固有的线程 - 这是不是因为虽然整个服务器研在这里停了下来
谢谢,我要检查这些选项。这段代码不仅仅被我的asp.net解决方案所使用,所以我不能只考虑这个特定的场景来编写它。 –
虽然有一个问题,如果我不能使用.Wait()或.Result,我怎么能捕获这些异步方法之一的调用方法,而不是异步本身的结果?换句话说,如何正确结束异步链? –
@LuisFerrao“通过异步同步” - 是的,基本上不能保证很好地播放。有2个答案:a)添加大量'ConfigureAwait'; b)不这样做 - 或者c)(是的,我知道我说过2!) - * make *调用方法async –
我注意到在ASP.Net Web Forms代码隐藏中编写async/await代码时要记住的另一个重点,那就是在页面声明中确保Async =“true”。该属性默认为false。
如果你不这样做,那么你可以看到你的网页处于永久加载状态。
<%@ Page Language="C#" Async="true" %>
此外,在.NET 4.5,根据斯蒂芬的答案,我们需要有“UseTaskFriendlySynchronizationContext”在web配置appSettings部分设置为true。另一个有用的应用程序是AllowAsyncDuringSyncStages对于Webforms代码隐藏中的异步/等待代码,它需要为false。这些设置默认都是假的。
<add key="aspnet:AllowAsyncDuringSyncStages" value="false" />
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true"/>
我有下面的示例异步/在一个ASP.Net Web窗体跑很快使用上述的设置和使用的await通过斯蒂芬的建议一路等待代码。如果没有遵循这些建议,那么您可以在浏览器中永久加载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;
}
不确定这适用于我,因为我使用asp.net mvc –
您可以Webforms中的异步事件处理程序可以使用异步控制器操作。你也可以在这个URL看到MVC中的异步控制器动作的答案:http://stackoverflow.com/questions/20227401/using-await-taskt-async-hangs-controller-in-mvc-app – Sunil
http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html – Andomar
@Andomar'await'不会阻止这样......不过是:如果有一些**调用**代码,调用'.Wait()'或'.Result',这将是一个问题 –