Search code examples
c#.netwcfsoapevent-based-programming

C# - Handling Fault Exceptions in event-based WCF proxy


I am consuming a WCF service using an event-based proxy generated by Visual Studio. I have run into an issue, where my application will hang if the call to the service times out. The call to the service is as follows:

ServiceClient client = new ServiceClient(binding, endpointAddress);
client.AuthenticateCompleted += (sender, e) =>
{
    if (e.Error != null)
        throw e.Error;
};
client.AuthenticateAsync(username, password);

Browsing through countless other questions, the general consensus is that any exceptions should be caught by WCF and found in e.Error above. However, when my service times out, this is not the case, the error is either null, or in some other tests I've run, the app has crashed before reaching this point in the code. Another user suggested wrapping the above code in a try/catch block, however, doing this also fails to catch the exception.

I have also tried placing try/catch blocks inside the completion handler, as well as numerous other more complicated methods which are beyond the scope of the question, as I really just need this working in its simplest form to continue.

It may also be worth mentioning that while many of these failures occurred on the live service with a open, close, send, and receive timeout of 30 seconds each, I have also been attempting to test fixes to the issue by bringing the timeout down to <1 second. I presume this would still be generating Timeout Exceptions and not causing any other issues, but I'm not 100% sure.

I also did not create the WCF service, so if something specific needs to be done on the server side to throw exceptions back to the client, it is possible this element is missing. If this is the case, is there any way around this?


Solution

  • It turns out the error is thrown by the IService.EndMethodName method which is not accessible through the class that is generated by Visual Studio.

    Instead I decided to access the channel directly so I have more control over things. The final implementation looks like the following (IService being the interface generated by Visual Studio):

    ChannelFactory<IService> factory = new ChannelFactory<IService>(binding, endpointAddress);
    
    // CreateChannel may not require any parameters outside of Mono
    IService channel = factory.CreateChannel(endpointAddress);
    
    channel.BeginAuthenticate(new AuthenticateRequest(arg0, arg1), result =>
    {
        try
        {
            channel.EndAuthenticate(result);
        }
        catch(Exception ex)
        {
            throw;
        }
    }, channel);
    

    This is in its simplest form, but the general idea is that the call is ended in the AsyncCallback within a try/catch block to do any exception handling there.