当一部分等待具有ConfigureAwait false时使用MessageBox

时间:2018-06-28 04:30:53

标签: c# async-await

读史蒂芬·克雷伊(Stephen Cleary)对not blocking on Async code的看法,我这样写

public static async Task<JObject> GetJsonAsync(Uri uri)
{
   using (var client = new HttpClient())
   {
      var jsonString = await client.GetStringAsync(uri).ConfigureAwait(false);  
      return JObject.Parse(jsonString);
   }
}

public async void Button1_Click(...)
{
    var json = await GetJsonAsync(...);
    textBox1.Text=json;
}

到目前为止,我了解到ConfigureAwait之后,该方法将在GetStringAsync返回之后继续在其他上下文上运行。 但是如果我想使用像MessageBox这样的东西(UI)怎么办

public static async Task<JObject> GetJsonAsync(Uri uri)
{
   if(someValue<MAXVALUE)
   {
      using (var client = new HttpClient())
      {
         //var jsonString = await client.GetStringAsync(uri);  //starts the REST request
         var jsonString = await client.GetStringAsync(uri).ConfigureAwait(false);    
         return JObject.Parse(jsonString);
      }
   }
   else
   {
      MessageBox.Show("The parameter someValue is too big!");
   }
}

我可以这样做吗?

更复杂的呢?

public static async Task<JObject> GetJsonAsync(Uri uri)
{
   if(someValue<MAXVALUE)
   {
      try{
         using (var client = new HttpClient())
         {
            //var jsonString = await client.GetStringAsync(uri);  //starts the REST request
            var jsonString = await client.GetStringAsync(uri).ConfigureAwait(false);    
            return JObject.Parse(jsonString);
         }
      }
      catch(Exception ex)
      {
         MessageBox.Show("An Exception was raised!");
      }
   }
   else
   {
      MessageBox.Show("The parameter someValue is too big!");
   }
}

我可以这样做吗?

现在,我想也许所有消息框都应该在GetJsonAync外部调用,这是一个很好的设计,但是我的问题是可以完成上述操作吗?

2 个答案:

答案 0 :(得分:2)

  

我可以这样做吗? [使用MessageBox]

是的,但是主要是因为它与异步/等待或线程无关。
MessageBox.Show()很特殊,它是一个静态方法,并记录为线程安全的。

您可以随时从任何线程显示MessageBox。

所以也许这是一个错误的示例,但是标题中确实有MessageBox。

public static async Task<JObject> GetJsonAsync(Uri uri)
{
   try{
     ...  // old context
     ... await client.GetStringAsync(uri).ConfigureAwait(false);
     ...  // new context
   }
   catch
   {
      // this might bomb
      someLabel.Text = "An Exception was raised!";
   }
}

在此示例中,可能存在代码路径,其中catch在旧的环境中运行,而其他路径则在新的上下文中运行。

最重要的是:您不知道,应该承担最坏的情况。

答案 1 :(得分:1)

我不会使用消息框,因为它非常有限且已过时。 另外,弹出窗口很烦人。 使用您自己的用户控件,该控件可按照您希望的方式进行用户交互。

在Winforms / WPF /(我猜是UWP)的上下文中,只有一个线程可以操纵UI。其他线程可以通过一系列最终被调用的动作向其发出工作。

这种体系结构可防止其他线程不断地在UI上戳戳,这可能会使UX非常不稳定(并且线程不安全)。

(在Winforms中)与UI工作队列进行通信的唯一方法是通过System.Windows.Form.Controls.BeginInvoke实例方法,该方法在每个窗体和控件上都可以找到。

在您的情况下:

public async void Button1_Click(...)
{
    var json = await GetJsonAsync(...).ConfigureAwait(false);
    BeginInvoke(UpdateTextBox, json);
}

private void UpdateTextBox(string value)
{
  textBox1.Text=json;
}