title: How to prevent warning VSTHRD101 when using Control.BeginInvoke() to call an async method?
body: <p>I'm refactoring some old WinForms code to use async/await, and I've hit a code analysis warning that I'm not sure how to fix properly.</p>
  <p>The situation is that I have a method that is called from a non-UI thread which needs to update the UI. The old code uses the time-honoured technique of calling <code>Control.BeginInvoke()</code> to run the code on the UI thread.</p>
  <p>The problem is that the method I want to invoke is now <code>async</code> and attempting to use <code>Control.BeginInvoke()</code> yields the warning <code>VSTHRD101</code>: &quot;Avoid using async lambda for a void returning delegate type, because any exceptions not handled by the delegate will crash the process.&quot;</p>
  <p>The following sample WinForms application demonstrates the problem. It's a simple form containing only a <code>Button</code> called &quot;testBtn&quot; and a <code>Label</code> called &quot;label1&quot;.</p>
  <p>The call to <code>ControlBeginInvoke()</code> inside the <code>notRunningOnUiThread()</code> method causes the warning as commented:</p>
  <pre><code>using System;
  using System.Threading.Tasks;
  using System.Windows.Forms;
  
  #pragma warning disable CA2007 // Consider calling ConfigureAwait on the awaited task (disabled for brevity in this sample code)
  
  namespace Net5WinFormsApp
  {
      public partial class Form1 : Form
      {
          public Form1()
          {
              InitializeComponent();
              CheckForIllegalCrossThreadCalls = true; // For test purposes to prove that mustRunOnUiThreadAsync() runs on the UI thread.
          }
  
          // This method is only to simulate what's happening in the real code. 
          // Assume that you cannot change this.
          void testBtn_Click(object sender, EventArgs e)
          {
              _ = Task.Run(() =&gt; notRunningOnUiThread(this)); // Not my real code, but this simulates it.
          }
  
          // NOTE: In the real code this method is not a member of the Control,
          // but it does have access to the Control to update.
          void notRunningOnUiThread(Control ui) // Called from a non-UI thread and wants to call a method that updates the UI.
          {
              // The next line causes warning VSTHRD101:
              // &quot;Avoid using async lambda for a void returning delegate type,
              // because any exceptions not handled by the delegate will crash the process.&quot;
  
              ui.BeginInvoke(new Action(async () =&gt; await mustRunOnUiThreadAsync()));
          }
  
          async Task mustRunOnUiThreadAsync()
          {
              label1.Text = &quot;Before update&quot;;
              await Task.Delay(1000).ConfigureAwait(true);
              label1.Text = &quot;After update&quot;;
          }
      }
  }
  </code></pre>
  <p>If I suppress the warning, everything seems to run OK even if there are exceptions in <code>mustRunOnUiThreadAsync()</code> (if there's an exception, it's reported immediately and not from the finalizer for a Task).</p>
  <p><strong>My question is:</strong> Is it safe to suppress this warning? And if not, what's a good way to fix it?</p>
  <p><strong>The fundamental thing I want to solve</strong> is how to safely call an async UI method on the UI thread from a non-UI thread in a WinForms application, when only the ui <code>Form</code> is available and the current synchronisation context is not available.</p>
  <p>(Note that I can't simply <code>await mustRunOnUiThreadAsync()</code> in <code>notRunningOnUiThread()</code>. That would cause a &quot;Cross-thread operation not valid&quot; <code>InvalidOperationException</code> to be thrown.)</p>
  <p>I suppose one possible solution is to write a non-async method that calls the async method, using <a href="https://stackoverflow.com/a/9343733/106159">the advice from this answer</a>. But is that the best approach for this particular case?</p>
  <hr />
  <p>[EDIT]</p>
  <p>I should have mentioned: In my actual code the <code>notRunningOnUiThread()</code> is not a member of the <code>Control</code> that needs to update the UI. Because <code>notRunningOnUiThread()</code> isn't running on a UI thread, I can't use <code>System.Threading.SynchronizationContext</code> since it is the wrong context. I do have the <code>Control</code> available for calling <code>Control.BeginInvoke()</code> however.</p>
  <p>The actual situation is that I am servicing an RPC request which must update some UI using a method that happens to be async.</p>