I have a small application that needs to test SQL connection strings for a number of connections (each done one-at-a-time). To do this I set the ConnectionTimeout = 5
temporarily to avoid a long wait if the connection is not valid and ConnectionTimeout = 0
(wait forever), say.
To avoid the UI hanging whilst we attempt to Open()
a bad connection (even with ConnectionTimeout = 5
the wait for the SqlException
can be up to twenty seconds), I want to run the test on a separate thread using Task Parallel Library (TPL). So I spin-off my new thread like:
Task<bool> asyncTestConn = Task.Factory.StartNew<bool>
(() => TestConnection(conn, bShowErrMsg));
return asyncTestConn.Result;
The problem is that this is still locking the UI (clearly), as it is waiting for the result before returning to the caller. How do I allow the code to return control to the UI (freeing up the GUI) whilst getting the eventual result from the asynchronous Task
?
Also, from within a Task
can I legitimately do MessageBox.Show("Some message")
? This does not work for BackgroundWorkers
and this pooled-thread is a background thread by default; yet it does not seem to be a problem. Thanks for your time.
You are right, this is where the waiting happens:
return asyncTestConn.Result;
You could simply build the finish-up code in the tail of TestConnection() or use a Continuation:
// untested
//Task<bool> asyncTestConn = Task.Factory.Create<bool> (
Task<bool> asyncTestConn = new Task<bool> (
() => TestConnection(conn, bShowErrMsg));
asyncTestConn.ContinueWith(MyFinishCode);
asyncTestConn.Start()
can I legitimately do MessageBox.Show("Some message")
?
Actually Yes, the MessageBox is thread-safe. Should be possible from a Bgw as well.
But you are prolonging the life of the Task by a lot, it's not a good idea.
For the TPL, ContinueWith
is exactly what you want. Expanding on Henk's answer:
var asyncTestConn = Task.Factory.StartNew(() => TestConnection(conn, bShowErrMsg));
// Henk's "MyFinishCode" takes a parameter representing the completed
// or faulted connection-testing task.
// Anything that depended on your "return asyncTestConn.Result;" statement
// needs to move into the callback method.
asyncTestConn.ContinueWith(task =>
{
switch (task.Status)
{
// Handle any exceptions to prevent UnobservedTaskException.
case TaskStatus.Faulted: /* Error-handling logic */ break;
case TaskStatus.RanToCompletion: /* Use task.Result here */ break;
}
},
// Using this TaskScheduler schedules the callback to run on the UI thread.
TaskScheduler.FromCurrentSynchronizationContext());