【问题标题】:Async behavior on WebForms gridviewWebForms gridview 上的异步行为
【发布时间】:2017-06-04 12:01:41
【问题描述】:

在将遗留应用程序移植到 async\await 模式时,我们遇到了一些我们无法跟踪的奇怪行为。我们将页面异步指令设置为 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

为什么会这样?为什么我没有看到有序的“开始”和“退出”消息。

【问题讨论】:

    标签: c# gridview webforms


    【解决方案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 />");
        }
    

    【讨论】:

    • 等待 Task.Delay(1000) 只是为了重现。这是为了表明在这种情况下不会等待任何可等待的调用。
    • 请看我的问题。我在那里写了这行得通,但我的问题是为什么“等待”在这种情况下不能像我预期的那样工作。
    • 我怀疑这是因为您已将该方法标记为异步。您希望该方法异步有什么特殊原因吗?
    • 是的,因为它需要等待一个可等待的方法。
    • 你不能只使用 awaitableMethod.Wait() 吗?
    猜你喜欢
    • 2014-07-16
    • 1970-01-01
    • 1970-01-01
    • 2014-12-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多