Documentation Coverage Report
Current view: top level - Azure/EnterpriseLibrary.Azure.TransientFaultHandling.ServiceBus.NetCore - ServiceBusTransientErrorDetectionStrategy.cs Hit Total Coverage
Version: 4.0 Artefacts: 2 2 100.0 %
Date: 2019-11-24 03:15:41

          Line data    Source code
       1             : // Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
       2             : 
       3             : namespace Microsoft.Practices.EnterpriseLibrary.TransientFaultHandling
       4             : {
       5             :         using System;
       6             :         using Microsoft.IdentityModel.Tokens;
       7             :         using System.Linq;
       8             :         using System.Net;
       9             :         using System.Net.Sockets;
      10             :         using System.Security;
      11             :         using System.ServiceModel;
      12             :         using System.Text.RegularExpressions;
      13             :         using Microsoft.Azure.ServiceBus;
      14             : 
      15             :         /// <summary> 
      16             :         /// Provides the transient error detection logic that can recognize transient faults when dealing with Windows Azure Service Bus. 
      17             :         /// </summary> 
      18             :         public class ServiceBusTransientErrorDetectionStrategy : ITransientErrorDetectionStrategy
      19           1 :         {
      20             :                 /// <summary> 
      21             :                 /// Provides a compiled regular expression used for extracting the error code from the message. 
      22             :                 /// </summary> 
      23             :                 private static readonly Regex acsErrorCodeRegex = new Regex(@"Error:Code:(\d+):SubCode:(\w\d+)", RegexOptions.IgnoreCase | RegexOptions.Compiled);
      24             :                 private static readonly int[] httpStatusCodes = new[] { (int)HttpStatusCode.InternalServerError, (int)HttpStatusCode.GatewayTimeout, (int)HttpStatusCode.ServiceUnavailable, (int)HttpStatusCode.RequestTimeout };
      25             :                 private static readonly WebExceptionStatus[] webExceptionStatus = new[] { WebExceptionStatus.ConnectionClosed, WebExceptionStatus.Timeout, WebExceptionStatus.RequestCanceled };
      26             : 
      27             :                 /// <summary> 
      28             :                 /// Determines whether the specified exception represents a transient failure that can be compensated by a retry. 
      29             :                 /// </summary> 
      30             :                 /// <param name="ex">The exception object to be verified.</param> 
      31             :                 /// <returns>true if the specified exception is considered transient; otherwise, false.</returns> 
      32           1 :                 public bool IsTransient(Exception ex)
      33             :                 {
      34             :                         return ex != null && (CheckIsTransient(ex) || (ex.InnerException != null && CheckIsTransient(ex.InnerException)));
      35             :                 }
      36             : 
      37             :                 // SecuritySafeCritical because it references MessagingException
      38             :                 [SecuritySafeCritical]
      39             :                 private static bool CheckIsTransient(Exception ex)
      40             :                 {
      41             :                         var messagingException = ex as ServiceBusException;
      42             :                         if (messagingException != null)
      43             :                         {
      44             :                                 // The IsTransient property already covers the following scenarios:
      45             :                                 //if (ex is MessageLockLostException) return false;
      46             :                                 //if (ex is MessagingEntityAlreadyExistsException) return false;
      47             :                                 //if (ex is MessagingEntityNotFoundException) return false;
      48             :                                 //if (ex is MessagingCommunicationException) return true;
      49             :                                 //if (ex is ServerBusyException) return true;
      50             :                                 return messagingException.IsTransient;
      51             :                         }
      52             : 
      53             :                         if (ex is FaultException) return false;
      54             : 
      55             :                         if (ex is CommunicationObjectFaultedException) return false;
      56             : 
      57             :                         if (ex is TimeoutException) return true;
      58             : 
      59             :                         var webException = ex as WebException;
      60             :                         if (webException != null)
      61             :                         {
      62             :                                 if (webExceptionStatus.Contains(webException.Status)) return true;
      63             : 
      64             :                                 if (webException.Status == WebExceptionStatus.ProtocolError)
      65             :                                 {
      66             :                                         var response = webException.Response as HttpWebResponse;
      67             :                                         if (response != null && httpStatusCodes.Contains((int)response.StatusCode)) return true;
      68             :                                 }
      69             :                         }
      70             : 
      71             :                         if (ex is SecurityTokenException) return true;
      72             : 
      73             :                         if (ex is ServerTooBusyException) return true;
      74             : 
      75             :                         if (ex is ProtocolException) return true;
      76             : 
      77             :                         // This exception may occur when a listener and a consumer are being 
      78             :                         // initialized out of sync (e.g. consumer is reaching to a listener that 
      79             :                         // is still in the process of setting up the Service Host). 
      80             :                         if (ex is EndpointNotFoundException) return true;
      81             : 
      82             :                         if (ex is CommunicationException) return true;
      83             : 
      84             :                         var socketFault = ex as SocketException;
      85             :                         if (socketFault != null)
      86             :                         {
      87             :                                 return socketFault.SocketErrorCode == SocketError.TimedOut;
      88             :                         }
      89             : 
      90             :                         if (ex is UnauthorizedAccessException)
      91             :                         {
      92             :                                 // Need to provide some resilience against the following fault that was seen a few times: 
      93             :                                 // System.UnauthorizedAccessException: The token provider was unable to provide a security token while accessing 'https://xxx.accesscontrol.windows.net/WRAPv0.9/'.  
      94             :                                 // Token provider returned message: 'Error:Code:500:SubCode:T9002:Detail:An internal network error occured. Please try again.'.  
      95             :                                 // System.IdentityModel.Tokens.SecurityTokenException: The token provider was unable to provide a security token while accessing 'https://xxx.accesscontrol.windows.net/WRAPv0.9/'.  
      96             :                                 // Token provider returned message: 'Error:Code:500:SubCode:T9002:Detail:An internal network error occured. Please try again.'.  
      97             :                                 // System.Net.WebException: The remote server returned an error: (500) Internal Server Error. 
      98             :                                 var match = acsErrorCodeRegex.Match(ex.Message);
      99             :                                 var errorCode = 0;
     100             : 
     101             :                                 if (match.Success && match.Groups.Count > 1 && int.TryParse(match.Groups[1].Value, out errorCode))
     102             :                                 {
     103             :                                         return httpStatusCodes.Contains(errorCode);
     104             :                                 }
     105             :                         }
     106             : 
     107             :                         return false;
     108             :                 }
     109             :         }
     110             : }

Generated by: LCOV version 1.13