views:

222

answers:

2

Inside my Silverlight app, I'm calling a web service asynchronously, using the client generated for me by Visual Studio (Add Service Reference...).
My code looks like this:

ServiceClient serviceClient = new ServiceClient();
serviceClient.GetServerTimeCompleted += new EventHandler<GetServerTimeCompletedEventArgs>(serviceClient_GetServerTimeCompleted);
serviceClient.GetServerTimeAsync();

void serviceClient_GetServerTimeCompleted(object sender, GetServerTimeCompletedEventArgs e)
{
         // do nothing atm
}

Everything works fine as long as the service is up and running, but when the service isn't running, i get:

private void Application_UnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e)

"An exception occurred during the operation, making the result invalid. Check InnerException for exception details."

InnerException

"An error occurred while trying to make a request to URI 'http://'. This could be due to attempting to access a service in a cross-domain way without a proper cross-domain policy in place, or a policy that is unsuitable for SOAP services. You may need to contact the owner of the service to publish a cross-domain policy file and to ensure it allows SOAP-related HTTP headers to be sent. This error may also be caused by using internal types in the web service proxy without using the InternalsVisibleToAttribute attribute. Please see the inner exception for more details."

It makes sense that I get an exception under these circumstances, but what I can't figure out is how to catch the exception in my client code. Is there a standard way to do this? If I understand how this is working, when my code calls the generated code, it spawns another thread that actually calls the web service and waits for the response. The exception is in that thread and in the generated code. Neither my calling code (see above) or my callback method have the opportunity to see the exception.

Thanks

Christian

+1  A: 

There are a number of reasons not to use the "Add Service Reference" functionality in Visual Studio. Here's a good (and long) article on the issues, and how to use WCF creating your clients. I'm working through these issues myself, right now.

Among the concerns about "Add Service Reference" include code bloat in the downloadable client .XAP file, difficulty in maintaining generated code, difficulty in staging or shipping code when the server addresses and ports are hard-coded in the client config file (also embedded in the .XAP), and lots more. Building your own clients will also give you better capability to manage exceptions in client code.

There are some tradeoffs; you'll need to make your data contract classes portable to the Silverlight environment. (You can't just add a reference to a server-side .NET assembly; it doesn't work.) There same site linked above has a good article on re-using assemblies in Silverlight, but probably the easiest way to deal with this is to add links to your server-side classes from your Silverlight project. (In the Silverlight project, right-click and Add -> Add existing item... and find the item you want to include, but instead of clicking on the Add button, click the down-arrow beside it and click on "Add as Link".) Watch out for other references and using statements that refer to server-side classes; you may need to do conditional compiles so that your data contract classes compile cleanly in the client-side project.

Overall, it really looks like a cleaner way to go, especially for large projects that may use lots of service contracts and data contracts, or where you need to ship your Silverlight projects as part of a commercial application that runs on other people's servers. It should also be a lot cleaner for testability, especially for integration and staging testing.

Cylon Cat
thanks, i'll dig into these pages, although i do not want to change the way i talk to the WCF. Using Add Service Reference is very 'handy' and i do not have the time atm ..
Christian
A: 

I have encountered this problem before - you need to add exception handling code around your ServiceClient setup code. I typically check for the following CommunicationException, TimeoutException, and EndpointNotFoundException and provide the user with an appropriate dialog telling them something is broken:

ServiceClient serviceClient;
try
{
   serviceClient = new ServiceClient(); 
   serviceClient.GetServerTimeCompleted += new EventHandler<GetServerTimeCompletedEventArgs>(serviceClient_GetServerTimeCompleted); 
   serviceClient.GetServerTimeAsync();
}
catch (EndpointNotFoundException ex)
{
   // log exception
   // show error dialog
}

Note: this will not handle errors encountered during the asnchronous method callback - it will need it's own (similar) exception handling.

Bermo
Bermo, do you have a sample which show what to wrap around the ServiceClient Setup code? i mean, do you use a Service Reference?thanksChristian
Christian
Updated to add some sample code.
Bermo