How to implement retry n times in case of exception in C #?

I am developing a WPF 4.0 application in which we receive data from a remote web service. The web service provides customers with over 120 methods. If the web service call from my WPF application fails, I need to repeat it n times, which is configured through App.Config. How to implement this? Are there design patterns to solve this problem?

+8
c #
source share
7 answers
static T TryNTimes<T>(Func<T> func, int times) { while (times>0) { try { return func(); } catch(Exception e) { if (--times <= 0) throw; } } } 
+6
source share

I wrote this code not so long ago to do something similar to what you want. It can be changed according to your needs. This is a common waiting method. Pass the function, and if the expected result is not returned, wait and then try again and exit after the X number of attempts.

 /// <summary> /// Wait for the result of func to return the expeceted result /// </summary> /// <param name="func">Function to execute each cycle</param> /// <param name="result">Desired result returned by func</param> /// <param name="waitInterval">How long to wait (ms) per cycle </param> /// <param name="cycles">How many times to execute func before failing</param> /// <returns>True if desired result was attained. False if specified time runs out before desired result is returned by func</returns> protected static bool WaitForEvent(Func<bool> func, bool result, int waitInterval, int cycles) { int waitCount = 0; while (func() != result) { if (waitCount++ < cycles) { Thread.Sleep(waitInterval); } else { return false; } } return true; } 
+3
source share
 while(retries < maxTries) try { //retryable code here break; } catch(Exception ex) { if(++retries == maxTries) throw; continue; } 

Of course, nothing unusual, but he will do his job. The main template, which would be common to almost any implementation, is some kind of loop construction that contains a somewhat controlled try-catch; which can be either a recursive call, or some iterative loop like the while loop above. Make sure you successfully complete the loop after a successful attempt and keep track of retries; inability to execute or will cause an infinite loop.

+1
source share
 while(true) { try { Method(); break; } catch(Exception ex) { i++; if(i == n) throw ex; } } 
0
source share

Here is a similar code that wraps an IO exchange violation. This is the same idea: we have a delegate and a static shell method:

 /// <summary> /// Defines a sharing violation wrapper delegate. /// </summary> public delegate void WrapSharingViolationsCallback(); /// <summary> /// Wraps sharing violations that could occur on a file IO operation. /// </summary> /// <param name="action">The action to execute. May not be null.</param> /// <param name="exceptionsCallback">The exceptions callback. May be null.</param> /// <param name="retryCount">The retry count.</param> /// <param name="waitTime">The wait time in milliseconds.</param> public static void WrapSharingViolations(WrapSharingViolationsCallback action, WrapSharingViolationsExceptionsCallback exceptionsCallback, int retryCount, int waitTime) { if (action == null) throw new ArgumentNullException("action"); for (int i = 0; i < retryCount; i++) { try { action(); return; } catch (IOException ioe) { if ((IsSharingViolation(ioe)) && (i < (retryCount - 1))) { bool wait = true; if (exceptionsCallback != null) { wait = exceptionsCallback(ioe, i, retryCount, waitTime); } if (wait) { Thread.Sleep(waitTime); } } else { throw; } } } } 

And then we call it that way (lambda expression is perfect here):

  WrapSharingViolations(() => DoWhatever(...)); 
0
source share

You can use a functional approach to this:

 class Program { static T Retry<T, TException>(Func<T> thingToTry, int timesToRetry) where TException : Exception { // Start at 1 instead of 0 to allow for final attempt for (int i = 1; i < timesToRetry; i++) { try { return thingToTry(); } catch (TException) { // Maybe: Trace.WriteLine("Failed attempt..."); } } return thingToTry(); // Final attempt, let exception bubble up } static int ServiceCall() { if (DateTime.Now.Ticks % 2 == 0) { throw new InvalidOperationException("Randomly not working"); } return DateTime.Now.Second; } static void Main() { int s = Retry<int, InvalidOperationException>(ServiceCall, 10); } } 

You can use this to catch certain exceptions (add additional TException parameters if necessary).

0
source share

Maybe you can do it with GOTO (gasp)

 int count = 0; try { TryAgain: // Do something with your web service } catch(Exception e) { if(count < numberOfAttemptsAllowed) { count++; goto TryAgain; } } 

I'm sure there may be a better way, but it can do what you need.

0
source share

All Articles