如何使用 async/await 实现 asp.net webform 中的异步页面?

15

现在我们可以在ASP.NET MVC 4中使用async/await关键字了。

public async Task<ActionResult> TestAsync()
{
    WebClient client = new WebClient();
    return Content(await client.DownloadStringTaskAsync("http://www.google.com"));
}

但如何在ASP.NET WebForms中使用它?

2个回答

22

一个简单的方法是将你的事件处理程序设置为async。首先,在@Page指令中添加Async="true"参数,然后就可以编写如下的异步事件处理程序:

protected async void Page_Load(object sender, EventArgs e)
{
  var client = new WebClient();
  var content = await client.DownloadStringTaskAsync("http://www.google.com");
  Response.Write(content);
}

我说“应该能够”是因为我自己还没有尝试过。但是这应该是有效的。

更新:这对于Page_Load 并不起作用(请参见此MSDN论坛线程),但对于其他事件(如按钮点击)应该可以。

更新:在ASP.NET 4.5中,这对于Page_Load也有效。此外,他们还添加了检查来防止您错误地使用async事件处理程序。有关详细信息,请参见此视频。


1
如果您注册它们,那应该可以正常工作。但是 async void 不会自动向 Page 注册,因此会出现问题(在 .NET 4.0 上)。 - Stephen Cleary
1
根据http://www.hanselman.com/blog/TheMagicOfUsingAsynchronousMethodsInASPNET45PlusAnImportantGotcha.aspx,使用异步方法在Web表单中的唯一可靠方式是注册Page.RegisterAsyncTask。您确定将async添加到Page_Load就足够了吗? - Michael Freidgeim
1
@MichaelFreidgeim:这已经足够了。虽然我建议使用“RegisterAsyncTask”。 - Stephen Cleary
值得一提的是,我已经在.NET 4.5.2和.NET 4.7的WebForms中看到了Task.Run的使用(与ContiuneWith链接且当然不访问Result以避免死锁),已经存在多年并且没有出现问题。但需要说明的是,同时使用该Task.Run代码的会话不超过几十个。 - OfirD
@OfirD:当然,Task.RunContinueWith可能有效,但在ASP.NET上,Task.Run效率低下,而ContinueWith是一种危险的低级方法。 - Stephen Cleary
显示剩余3条评论

2
根据 http://www.hanselman.com/blog/TheMagicOfUsingAsynchronousMethodsInASPNET45PlusAnImportantGotcha.aspx 的说法,使用异步技术在 Web Forms 中唯一可靠的方法是调用 Page.RegisterAsyncTask。
支持异步 Page_Load 等简单操作的代码非常复杂,并且在基本情况以外的场景下未经充分测试。使用 voids(空返回值)的异步方式不稳定或不可靠。但是,你只需调用 Page.RegisterAyncTask - 这并不麻烦,而且你将处于更好、更灵活的状态。
public void Page_Load(object sender, EventArgs e)
{
    RegisterAsyncTask(new PageAsyncTask(LoadSomeData));
}

public async Task LoadSomeData()
{
var clientcontacts = Client.DownloadStringTaskAsync("api/contacts");
var clienttemperature = Client.DownloadStringTaskAsync("api/temperature");

var contacts = Newtonsoft.Json.JsonConvert.DeserializeObject>(await clientcontacts);
var temperature = Newtonsoft.Json.JsonConvert.DeserializeObject(await clienttemperature);

listcontacts.DataSource = contacts;
listcontacts.DataBind();
Temparature.Text = temperature; 
}

正确,但它不等待异步任务完成,而是在Page_Load内部继续执行下一行代码。 - Bimal Das

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接