title: Why is the default implementation of DbConnection.OpenAsync(CancellationToken) synchronous?
body: <p>I was reading the <a href="https://msdn.microsoft.com/en-us/library/hh223693%28v=vs.110%29.aspx" rel="nofollow noreferrer">documentation for <code>DbConnection.OpenAsync(CancellationToken)</code></a> and found the following snippet:</p>
  
  <blockquote>
    <p>The default implementation invokes the synchronous <a href="https://msdn.microsoft.com/en-us/library/system.data.common.dbconnection.open(v=vs.110).aspx" rel="nofollow noreferrer">Open</a> call and returns a completed task. The default implementation will return a cancelled task if passed an already cancelled cancellationToken. Exceptions thrown by Open will be communicated via the returned Task Exception property.</p>
  </blockquote>
  
  <p>Now, if I were on a spotty/slow network connection and used a database provider that hasn’t overridden <code>DbConnection.OpenAsync(CancellationToken)</code> (i.e., I’m using something other than <code>System.Data.SqlClient</code>), <em>and</em> if I plopped that into a UI Button’s event handler, like: (hypothetical code, untested)</p>
  
  <pre><code>async void button1_Clicked(object sender, EventArgs e)
  {
      using (var connection = MyProviderFactory.CreateConnection())
      {
          button1.Text = "Opening…";
          connection.ConnectionString = _SomeString;
          try
          {
              await connection.OpenAsync(default);
              button1.Text = "Opened successfully!";
          }
          catch (Exception ex)
          {
              button1.Text = ex.Message;
          }
      }
  }
  </code></pre>
  
  <p>Based on the documentation I quoted, if the connection took long enough to complete, my Form would be “ (Not Responding)” while the connection was being established if the provider hasn’t overridden the default implementation. To prevent this from happening regardless of the underlying database provider, I might as well do <code>await Task.Run(async () =&gt; await connection.OpenAsync());</code>. Why is the default implementation this way and how is one supposed to know when <code>Task.Run()</code> is needed without writing provider-aware code?</p>