I'm trying to write a class that encapsulates WCF calls (the client is Silverlight, if it matters). It all works swimmingly, but I'm not sure how to trap a connection failure, as if the server won't respond. It would appear that bit of work happens somewhere in the resulting code from ChannelFactory, but I'm not sure. General code review is welcome also. :)
Bottom line, surrounding the creation of the channel, or the begin or async result delegate in try/catch doesn't trap a failed connection. I'd like to have that catch run the ServiceCallError event.
public class ServiceCaller : IDisposable
{
private IFeedService _channel;
public ServiceCaller()
{
var elements = new List<BindingElement>();
elements.Add(new BinaryMessageEncodingBindingElement());
elements.Add(new HttpTransportBindingElement());
var binding = new CustomBinding(elements);
var endpointAddress = new EndpointAddress(App.GetRootUrl() + "Feed.svc");
_channel = new ChannelFactory<IFeedService>(binding, endpointAddress).CreateChannel();
}
public void MakeCall(DateTime lastTime, Dictionary<string, string> context)
{
AsyncCallback asyncCallBack = delegate(IAsyncResult result)
{
var items = ((IFeedService)result.AsyncState).EndGet(result);
if (ItemsRetrieved != null)
ItemsRetrieved(this, new ServiceCallerEventArgs(items));
};
_channel.BeginGet(lastTime, context, asyncCallBack, _channel);
}
public event ItemsRetrievedEventHandler ItemsRetrieved;
public event ServiceCallErrorHandler ServiceCallError;
public delegate void ItemsRetrievedEventHandler(object sender, ServiceCallerEventArgs e);
public delegate void ServiceCallErrorHandler(object sender, ServiceCallErrorEventArgs e);
public void Dispose()
{
_channel.Close();
_channel.Dispose();
}
}
Here's the stack trace, for those who are curious:
An AsyncCallback threw an exception.
at System.ServiceModel.AsyncResult.Complete(Boolean completedSynchronously)
at System.ServiceModel.AsyncResult.Complete(Boolean completedSynchronously, Exception exception)
at System.ServiceModel.Channels.HttpChannelFactory.HttpRequestChannel.HttpChannelAsyncRequest.OnGetResponse(IAsyncResult result)
at System.Net.Browser.BrowserHttpWebRequest.<>c__DisplayClassd.<InvokeGetResponseCallback>b__b(Object state2)
at System.Threading._ThreadPoolWaitCallback.WaitCallback_Context(Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading._ThreadPoolWaitCallback.PerformWaitCallbackInternal(_ThreadPoolWaitCallback tpWaitCallBack)
at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback(Object state)
To make this happen, I fire up the app in the browser, then I kill the Web server process from Visual Studio. In a test environment, I get the same thing by killing the network connection for the client system.
Here's the FULL exception's ToString():
System.Exception: An AsyncCallback threw an exception. ---> System.Exception: An AsyncCallback threw an exception. ---> System.ServiceModel.CommunicationException: The remote server returned an error: NotFound. ---> System.Net.WebException: The remote server returned an error: NotFound. ---> System.Net.WebException: The remote server returned an error: NotFound.
at System.Net.Browser.BrowserHttpWebRequest.InternalEndGetResponse(IAsyncResult asyncResult)
at System.Net.Browser.BrowserHttpWebRequest.<>c__DisplayClass5.<EndGetResponse>b__4(Object sendState)
at System.Net.Browser.AsyncHelper.<>c__DisplayClass2.<BeginOnUI>b__0(Object sendState)
--- End of inner exception stack trace ---
at System.Net.Browser.AsyncHelper.BeginOnUI(SendOrPostCallback beginMethod, Object state)
at System.Net.Browser.BrowserHttpWebRequest.EndGetResponse(IAsyncResult asyncResult)
at System.ServiceModel.Channels.HttpChannelFactory.HttpRequestChannel.HttpChannelAsyncRequest.CompleteGetResponse(IAsyncResult result)
--- End of inner exception stack trace ---
at System.ServiceModel.Channels.Remoting.RealProxy.Invoke(Object[] args)
at proxy_2.EndGet(IAsyncResult )
at CoasterBuzz.Feed.Client.ServiceCaller.<MakeCall>b__0(IAsyncResult result)
at System.ServiceModel.AsyncResult.Complete(Boolean completedSynchronously)
--- End of inner exception stack trace ---
at System.ServiceModel.AsyncResult.Complete(Boolean completedSynchronously)
at System.ServiceModel.AsyncResult.Complete(Boolean completedSynchronously, Exception exception)
at System.ServiceModel.Channels.ServiceChannel.SendAsyncResult.CallComplete(Boolean completedSynchronously, Exception exception)
at System.ServiceModel.Channels.ServiceChannel.SendAsyncResult.FinishSend(IAsyncResult result, Boolean completedSynchronously)
at System.ServiceModel.Channels.ServiceChannel.SendAsyncResult.SendCallback(IAsyncResult result)
at System.ServiceModel.AsyncResult.Complete(Boolean completedSynchronously)
--- End of inner exception stack trace ---
at System.ServiceModel.AsyncResult.Complete(Boolean completedSynchronously)
at System.ServiceModel.AsyncResult.Complete(Boolean completedSynchronously, Exception exception)
at System.ServiceModel.Channels.HttpChannelFactory.HttpRequestChannel.HttpChannelAsyncRequest.OnGetResponse(IAsyncResult result)
at System.Net.Browser.BrowserHttpWebRequest.<>c__DisplayClassd.<InvokeGetResponseCallback>b__b(Object state2)
at System.Threading._ThreadPoolWaitCallback.WaitCallback_Context(Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading._ThreadPoolWaitCallback.PerformWaitCallbackInternal(_ThreadPoolWaitCallback tpWaitCallBack)
at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback(Object state)
By the way, the only way I can catch this at all is to use app level UnhandledException event in the SL client.