WebForms gridview上的异步行为

时间:2017-06-04 12:01:41

标签: c# gridview webforms

在将遗留应用程序移植到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

为什么会发生这种情况?为什么我没有看到有序的“开始”和“退出”消息。

1 个答案:

答案 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 />");
    }