Exception User-Unhandled reported in VS Debugger when using Polly

user2197446 picture user2197446 · May 18, 2017 · Viewed 9.3k times · Source

I'm using Polly to catch an exception while calling a Pittney Bowes Geocoder service. I'm using a g1client library that throws a MessageProcessingException. I've wrapped the call in a Polly network policy to retry the call up to 3 times if this exception is thrown, but Visual Studio insists that the exception is "User-Unhandled" What do I need to modify to make this exception be handled? I'm using Visual Studio 2017 community Edition and C# 4.6.1.

try
{
    var networkPolicy = Policy
                              .Handle<MessageProcessingException>()
                              .Or<Exception>()
                              .WaitAndRetry(
                                   3,
                                   retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)),
                                   (exception, timeSpan, context) =>
                                   {
                                       System.Diagnostics.Debug.WriteLine("Exception being retried" + exception);
                                   });
    geocoderResponse = networkPolicy.Execute(() => geocoderService.Process(geocoderRequest));
}
catch (MessageProcessingException ex)
{
    log.Error("MessageProcessingException calling the Geocoder service", ex);
    throw ex;
}
catch (Exception ex)
{
    log.Error("Exception calling the Geocoder service", ex);
    throw ex;
}

The error message is:

g1client.MessageProcessingException occurred
  HResult=0x80131500
  Message=Unable to read data from the transport connection: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond. Client timeout
  Source=g1client
  StackTrace:
   at g1client.UTF8Serializer.DeserializeHashtable(NetworkStream networkStream)
   at g1client.UTF8Serializer.GetMessage(NetworkStream networkStream)
   at g1client.SocketGatewayConnection.ProcessBytes(Byte[] bytesIn)
   at g1client.SocketGatewayConnection.Process(Message message)
   at g1client.RemoteService.Process(Message message)
   at Midas.Core.PBGeocoder.Geocoder.<>c__DisplayClass27_0.<Bulk2PassGeocode>b__2() in E:\Source Code\GitHub\Midas.Core\Midas.Core.PBGeocoder\Geocoder.cs:line 321
   at Polly.Policy.<>c__DisplayClass75_0`1.<Execute>b__0(CancellationToken ct)
   at Polly.Policy.<>c__DisplayClass27_0`1.<Execute>b__0(CancellationToken ct)
   at Polly.RetrySyntax.<>c__DisplayClass11_0.<WaitAndRetry>b__1(CancellationToken ct)
   at Polly.Retry.RetryEngine.Implementation[TResult](Func`2 action, CancellationToken cancellationToken, IEnumerable`1 shouldRetryExceptionPredicates, IEnumerable`1 shouldRetryResultPredicates, Func`1 policyStateFactory)

I'd like to also track down why I'm getting this error, so any help debugging that would be great also. I only get it the first time I call the service with a large request. In this case I was sending 1000 addresses to be processed. The next run the request will be handled in under a second, but the first time it doesn't work.

Answer

mountain traveller picture mountain traveller · May 19, 2017

TL;DR You are just seeing the VS debugger breaking on exceptions.

You may be understanding the Visual Studio Debugger's (inherently confusing) terminology user-unhandled exception to mean that the executing codebase as a whole is not handling the exception; this is not the case.

User-unhandled exception in this case means that the exception is first handled other than by your code - here, by the Polly policy.

First, Visual Studio divides code you are debugging into 'my code' aka 'user code', and 'non-user code'. In your scenario, Polly and the Geocoder library will be classified 'non-user code'.

Second, by default, the Visual Studio debugger breaks[+] on exceptions handled by 'non-user code' (but using this potentially confusing and alarming term 'user-unhandled'!).

Visual Studio breaks[+] by default so that you can see the line that triggered the exception as it happened (even if subsequent code will handle it...). So, it sounds (dpdg on debugger settings) as if you are seeing Visual Studio breaking, even though the exception will be handled as configured by the Polly policy. Just press F5/Continue in the debugger, and the subsequent code will resume.

You can also change this behaviour[+] by following the instructions in this article under the heading Tell the debugger to continue on user-unhandled exceptions.

You can further satisfy yourself the Polly policy is working by examining the behaviour of the line System.Diagnostics.Debug.WriteLine("Exception being retried" + exception);. You should see output from that line - or see it hit if you set a breakpoint on it - if retries are being invoked.


Finally, a Polly retry policy rethrows any final exception if all configured retries have been exhausted. This is intentional - to indicate that eventuality - not a failure.

You correctly have a try { ... } catch (MessageProcessingException ex) { ... } for this, but the debugger may again misleadingly label that final exception 'user-unhandled' - even though you have a try-catch for it - due to its initially being caught by Polly.