在将遗留应用程序移植到async \ await模式时,我们遇到了一些我们无法跟踪的奇怪行为。我们将页面async指令设置为true,并将事件处理程序添加到RowDataBound。如果EventHandler中的代码包含等待的调用,则在继续处理下一行之前不会等待它。
这是一个让人们更容易理解的复制品:
public partial class WorkingCorrectlyWebForm: System.Web.UI.Page
{
private int _index;
protected void Page_Load(object sender, EventArgs e)
{
var grid = new GridView();
grid.RowDataBound += GridOnRowDataBound;
grid.DataSource = new[]
{
new {Name = "Person1", Age = 23},
new {Name = "Person2", Age = 33},
new {Name = "Person3", Age = 15}
};
grid.DataBind();
}
private async void GridOnRowDataBound(object sender, GridViewRowEventArgs gridViewRowEventArgs)
{
if (gridViewRowEventArgs.Row.RowType != DataControlRowType.DataRow)
return;
var localIndex = ++_index;
HttpContext.Current.Response.Write($"starting #{localIndex} <br />");
await Task.Delay(1000); //HERE IS THE PROBLEMATIC LINE
//removing the remark from the following line will make code behave "synchronously" as expected.
// Task.Delay(1000).Wait();
HttpContext.Current.Response.Write($"exiting #{localIndex} <br />");
}
}
此代码将生成与此类似的输出(而不是命令“开始\退出”每个项目):
开始#1
开始#2
开始#3
退出#3
退出#1
退出#2
为什么会发生这种情况?为什么我没有看到有序的“开始”和“退出”消息。
答案 0 :(得分:1)
如果你想要串行行为,这应该有效:
private void GridOnRowDataBound(object sender, GridViewRowEventArgs gridViewRowEventArgs)
{
if (gridViewRowEventArgs.Row.RowType != DataControlRowType.DataRow)
return;
var localIndex = ++_index;
HttpContext.Current.Response.Write($"starting #{localIndex} <br />");
Thread.Sleep(1000);
// or Task.Delay(1000).Wait();
HttpContext.Current.Response.Write($"exiting #{localIndex} <br />");
}
或尝试:
private void GridOnRowDataBound(object sender, GridViewRowEventArgs gridViewRowEventArgs)
{
RegisterAsyncTask(new PageAsyncTask(() => Bob(gridViewRowEventArgs)));
HttpContext.Current.Response.Write($"b");
}
private async Task Bob(GridViewRowEventArgs gridViewRowEventArgs)
{
if (gridViewRowEventArgs.Row.RowType != DataControlRowType.DataRow)
return;
var localIndex = ++_index;
HttpContext.Current.Response.Write($"starting #{localIndex} <br />");
await Task.Delay(1000);
HttpContext.Current.Response.Write($"exiting #{localIndex} <br />");
}