3

I'm trying to open a connection to an SQL server asynchronously, so as not to tie up the UI thread. But I've found that the call to connection.OpenAsync() does not return until the connection has been opened, exactly as with connection.Open().

This code reproduces the issue:

public static void Main(string[] args)
{
    System.Data.SqlClient.SqlConnectionStringBuilder builder = new System.Data.SqlClient.SqlConnectionStringBuilder();
    builder.UserID = "sa";
    builder.Password = "1234";
    builder.DataSource = "192.168.1.254\\SQLEXPRESS";
    builder.InitialCatalog = "MyDatabase";
    builder.PersistSecurityInfo = true;

    DbConnection connection = new System.Data.SqlClient.SqlConnection(builder.ConnectionString);

    Console.WriteLine("about to connect");

    Task connection_task = connection.OpenAsync();

    Console.WriteLine("started");

    while (!connection_task.IsCompleted && !connection_task.IsFaulted && !connection_task.IsCanceled)
    {
        Console.WriteLine("busy");
    }

    Console.WriteLine("done");
}

In this case, 192.168.1.254 is non-existent. The message about to connect appears immediately, but then while waiting for the connection to time out nothing happens, then after the connection times out the messages started and done appear at the same time. I would expect that the message started would appear immediately after the message about to connect, then the message done would appear later once the connection has timed out.

I'm guessing that I'm doing something wrong with the returned Task, but the Microsoft page on Task-based Asynchronous Pattern certainly implies that I should simply be able to call the OpenAsync() method and the returned Task will be running asynchronously, instead of the operation taking place synchronously and tying up the calling thread until the Task completes.

26
  • I tried exactly this code and it behaves as expected, I get a load of "busy" before "done". This is a new console app in VS 2017 targetting .NET 4.6.1. Commented Nov 23, 2017 at 13:43
  • I'm targeting .NET 4.5 in MonoDevelop. I experience the same behaviour on Windows 10 and on Linux. Commented Nov 23, 2017 at 13:48
  • Also I get the same result as Adam, it prints "busy" a bunch of times, and then "done".
    – user310988
    Commented Nov 23, 2017 at 13:51
  • @Michael Ok so there we have a difference already. To me that seems like a bug in Mono, it doesn't yield the task when it hits a bit where it can register some sort of wait. async isn't concurrent, it'll run synchronously until something gives control back after registering with something like an IO completion port. Commented Nov 23, 2017 at 13:51
  • @AndyJ Not a syntax error, ADO.NET connections derived from DbConnection. Commented Nov 23, 2017 at 13:51

2 Answers 2

3

It turns out that this is a bug in the Mono runtime and that the code works fine on Microsoft .NET. A similar bug also seems to be present with the MySQL .NET library (MySql.Data), which runs the task synchronously regardless of whether the Mono or the Microsoft .NET runtime is used.

EDIT: I've found a bug report for the issue with MySQL.

2
  • That bug isn't looking too likely to be fixed mate, it's been around for a while :-( Another SO question: stackoverflow.com/questions/21978629/… Commented Nov 24, 2017 at 14:44
  • @AdamHouldsworth Yeah, doesn't look like it's going to be fixed soon. But it's OK, I think I've found a workaround for my particular situation. Commented Nov 24, 2017 at 15:11
0

Try add Asynchronous Processing=True or Async=True property to your connection string,

and add await to function call, like this : await connection.OpenAsync();

I hope this help you.

3
  • Setting builder.AsynchronousProcessing = true does not help. await makes the current thread wait for the task to finish; I would expect that without using await that I would get the expected behaviour, where the current thread continues without waiting for the task to finish. Commented Nov 23, 2017 at 14:20
  • This setting is a no-op in .NET 4.5 and above (which is being used, per the comments). Even if it wasn't, it enables only the use of the .BeginXXX methods (i.e. the "old" asynchronous model), which otherwise throw an exception, and should have no effect on the use of async/await. Commented Nov 23, 2017 at 14:21
  • await does not make the current thread wait for the task to finish, it makes the current thread go off and do something else (unless the task was already finished to begin with).
    – Jon Hanna
    Commented Nov 23, 2017 at 16:15

Not the answer you're looking for? Browse other questions tagged or ask your own question.