【问题标题】:ASP.NET Webforms with async/await带有 async/await 的 ASP.NET Webforms
【发布时间】:2017-11-07 04:43:45
【问题描述】:

我基于 .Net 4.6 的 Webforms 应用程序必须非常广泛地使用 async/await 功能。因为我对这个 async/await 主题很陌生,所以我阅读了很多最佳实践,例如 thisthis。但是我还有一些问题没有找到明确的信息。

  1. 关于页面生命周期事件:我知道,例如对于 Page_Load-Event,最好的做法是避免使用异步 void 方法并注册这样的方法:

    protected void Page_Load(object sender, EventArgs e)
    {
       PageAsyncTask pageAsyncTask = new PageAsyncTask(SomeAsyncMethod);
       Page.RegisterAsyncTask(pageAsyncTask);
       //Method to invoke the registered async-methods immedietly and not after the PreRender-Event
       Page.ExecuteRegisteredAsyncTasks();
     }
    

    我的问题是我想在注册后立即调用异步方法,而不是在 OnPreRender 事件之后。这应该通过调用 ExecuteRegisteredAsyncTasks() 方法来实现。但在我的情况下,这 没有效果,并且在 PreRender 事件之后仍会调用异步方法。但是为什么呢?

  2. 关于 Control-Events:是用我在上面的代码示例中提到的相同方式注册 async-methods 更好,还是可以使用 async-void 签名,例如:

    protected async void OnClick(object sender, EventArgs e)
    {
    await SomeAsyncMethod();
    }
    

    我找到了这两个示例,但没有明确的信息哪个是更好的解决方案以及原因。

  3. 关于 Context 和 ConfigureAwait,最好的做法是使用 await SomeAsyncMethod.ConfigureAwait(false) 以获得更好的性能,并且在上下文不重要的情况下不要使用它,例如在上下文中使用它。操作 GUI 元素时。但就我而言,如果我在点击事件中调用 await SomeAsyncMethod.ConfigureAwait(false) 似乎没有什么区别。我仍然可以毫无问题地操作我的 GUI 元素。我使用的示例是这样的:

    private async void button1_Click(object sender, EventArgs e)
    {
      button1.Enabled = false;
      try
      {
        await SomeAsyncMethod().ConfigureAwait(false);
      }
      finally
      {
        //Manipulating still works even it's another context
        button1.Enabled = true;
      }
    }
    

所以我想知道为什么 GUI 元素的操作仍然有效,以及我是否真的应该在上下文不重要的每个异步方法上使用 ConfigureAwait(false),这非常乏味。我想知道这是否与 Telerik 用于我的 Web 应用程序的 Ajax-Functionality 的使用有关。但这只是一个假设。

【问题讨论】:

  • 如果您想以 Markdown 格式呈现列表中的代码块,请使用双缩进。
  • 好的,感谢编辑。
  • ASP.NET 应用程序中没有 GUI。 WebForms 为您提供了一个看起来 像 GUI 的模型,但实际上并非如此。也就是说,当该方法必须调用 ASP.NET API(例如button1.Enabled)时,我不会调用ConfigureAwait(false)。大多数 API 都可以正常工作,但也有一些会失败,所以我只是谨慎行事。

标签: asp.net asynchronous webforms async-await


【解决方案1】:

ASP.NET WebForms 有它自己的异步执行引擎。请参考the documentation

在任何情况下,您通常希望(或需要)返回到事件处理程序等方法上的当前同步上下文,因此您不应在 button1_Click 内调用 ConfigureAwait(false),而应在 @ 内调用它987654324@.

【讨论】:

  • 已经阅读了我在初始帖子中提到的内容。但我需要更详细的信息,尤其是为什么 Page.ExecuteRegisteredAsyncTasks() 无法正常工作
  • SomeAsyncMethod() 在做什么,您认为Page.ExecuteRegisteredAsyncTasks() 正常工作是什么?我还是更喜欢注册所有异步工作,让它在渲染前自动执行获取值。
  • 例如SomeAsyncMethod() 在页面加载事件中加载一些数据。这些数据是必要的,例如在按钮单击事件中。问题是异步方法是在预渲染事件之后执行的,这对于点击事件来说太晚了。因此,我认为我可以使用Page.ExecuteRegisteredAsyncTasks()。但是调用这个方法没有效果,在prerender-event之后还是会调用SomeAsyncMethod()
【解决方案2】:

我对 Asp.net 4.5 网络表单的简单方法:

1) 使用该属性声明 aspx 页面

<%@ Page ..... Async="true" ValidateRequest="false" EnableEventValidation="false" %>

2) 在代码中创建这个 void 方法:

void MyAsyncMethod( ... list parameters )
{
  //Insert this on end method code
  var objThread = Session["MyAsyncMethod"] as Thread;
  if (objThread != null) objThread.Abort();
}

3) 调用方法MyAsyncMethod:

var objThread = new Thread(
              () => MyAsyncMethod(parameters..)) {IsBackground = true};
objThread.Start();
Session["MyAsyncMethod"] = objThread;

【讨论】:

  • 线程很昂贵(它们会导致 1MB 堆栈分配) - 如果您要使用 Thread,请使用 ThreadPool(而 Task.Run 会自动使用线程池)。但是您的代码不会异步等待 (await) 线程或任务完成 - 而且,永远不会调用Thread.Abort()
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-09-12
  • 2023-03-10
  • 2016-10-09
  • 1970-01-01
  • 2021-06-29
  • 2018-03-09
  • 2012-10-12
相关资源
最近更新 更多