I have a wcf client that before doing some complicated interactions with the wcf service does a simple check for the service to be alive. As the time-out for a failed connection is one minute, I want to implement this check asynchronously.
This is what I have:
//Method on the main UI thread
public void DoSomeComplicatedInteraction()
{
If(ConnectionIsActive()) DoTheComplicatedInteraction();
}
private bool ConnectionIsActive()
{
//Status is a Textblock on the wpf form
Status.Text = "Checking Connection";
var ar = BeginConnectionIsActive();
while (!ar.IsCompleted)
{
Status.Text += ".";
Thread.Sleep(100);
}
EndConnectionIsActive(ar);
//IsConnected is a boolean property
return IsConnected;
}
private IAsyncResult BeginConnectionIsActive()
{
//checkConnection is Func<bool> with value CheckConnection
return checkConnection.BeginInvoke(null,checkConnection);
}
private void EndConnectionIsActive(IAsyncResult ar)
{
var result=((Func<bool>)ar.AsyncState).EndInvoke(ar);
IsConnected = result;
}
private bool CheckConnection()
{
bool succes;
try
{
//synchronous operation
succes=client.Send(RequestToServer.GetPing()).Succes;
}
catch
{
succes = false;
}
return succes;
}
This works. Only, when I try to simulate a slow server response by adding a Thread.Sleep in the server's Send method,the UI becomes unresponsive. Moreover, the Status Textblock's Text does not get visibly updated. It seems I need some kind of Application.DoEvents method. Or do I need a different approach?
EDIT: Indeed,a different approach is necessary. Using Thread.Sleep will block the UI when it us called on the Main UI thread. Here is how I solved it:
//Method on the main UI thread
public void DoSomeComplicatedInteraction()
{
IfConnectionIsActiveDo(TheComplicatedInteraction);
}
private void TheComplicatedInteraction()
{...}
private void IfConnectionIsActiveDo(Action action)
{
Status.Text = "Checking Connection";
checkConnection.BeginInvoke(EndConnectionIsActive,
new object[] { checkConnection, action });
}
private void EndConnectionIsActive(IAsyncResult ar)
{
var delegates = (object[]) ar.AsyncState;
var is_active_delegate = (Func<bool>) delegates[0];
var action = (Action) delegates[1];
bool is_active=is_active_delegate.EndInvoke(ar);
IsConnected = is_active;
Dispatcher.Invoke(DispatcherPriority.Normal,
new Action<bool>(UpdateStatusBarToReflectConnectionAttempt),is_active);
if (is_active) action();
}
I am not very happy with it: it spreads (synchronous) code that used to be in two methods into five! This makes the code very messy...