I have this extension method that allows me to retry an operation if there is an exception, a typical use is trying to write to a file, but for some reason I can't so I retry a bit later...
The extension looks like:
public static void WithRetry<T>(this Action action, int timeToWait = 500, int timesToRetry = 3) where T : Exception
{
int retryCount = 0;
bool successful = false;
do
{
try
{
action();
successful = true;
}
catch (T)
{
retryCount++;
Thread.Sleep(timeToWait);
if (retryCount == timesToRetry) throw;
}
catch (Exception)
{
throw;
}
} while (retryCount < timesToRetry && !successful);
}
Visual studio tells me that I'm swallowing an exception in the first catch block, is this bad?
Thanks.
The warning is exactly what you are trying to achieve. You are swallowing the exceptions (timesToRetry-1) times. On the last try only you are actually throwing the exception. Until then all the exceptions will be swallowed and lost. Since this is the behavior you are trying to achieve. There is no harm in suppressing the message.
But as #HimBromBeere stated remove the catch(Exception) block. Also you can try logging the exception on each re-try because you will loose this data. What if different kind of exception is thrown each time. There is no way to be sure.
The warning is correct, you swallow exceptions. If you retry 10 times you will never know what went wrong the first 9 times, you only get exception number 10.
Maybe that's what you want. Personally, I would put all the occurring exceptions into an AggregateException and throw that when you hit your retry count.
Maybe like this:
public static void WithRetry<T>(this Action action, int timeToWait = 500, int timesToRetry = 3) where T : Exception
{
var exceptions = new List<Exception>();
for (int tryIndex = 0; tryIndex < timesToRetry; tryIndex++)
{
try
{
action();
return;
}
catch (T t)
{
exceptions.Add(t);
}
Thread.Sleep(timeToWait);
}
throw new AggregateException(exceptions);
}
Related
I have a general retry on exception handler which I would like it to repeat a function for a definite number of time and here's the code for it
public static void Retry(this MethodInfo methodInfo, object[] parametrsList, short after = 0, short? retry = 1)
{
if (retry < 0)
return;
try
{
short waitingPeriodMs = after*1000;
Thread.Sleep(waitingPeriodMs);
Type classObjType = methodInfo.ReflectedType;
object classObj = Activator.CreateInstance(classObjType);
methodInfo.Invoke(classObj, parametrsList);
}
catch (TargetInvocationException ex)
{
Debug.WriteLine("Exception Caught");
methodInfo.Retry(parametrsList, after, --retry);
}
catch (Exception ex)
{
Debug.WriteLine("Exception Caught");
methodInfo.Retry(parametrsList, after, --retry);
}
}
The problem is whenever I an unhandled exception is throw in the method that I'm invoking neither of the two catch statements catches it
I've made sure that the Use Only My Code checkbox is not checked
I've used those two Debug.Writeline statements to make sure that it's not a debugger related issue and checked the Output window and made sure those two statements were not executed
P.S. I'm aware the using a general retry on exception code is risky and could lead to an infinite number of retries the I'm using it because of a project related reason
Update:
A unit test example that reproduces the question
[TestClass]
public class ExceptionTest
{
[TestMethod]
public void TestExceptionRetry()
{
Action act = () => { throw new Exception(); };
act.Method.Retry(new object[0]);
}
}
I have a method calling combo as below:
Void MainMethod()
{
try
{
for(i = 0; i < 10; i++)
{
Childmethod_1();
}
}
catch(Exception ex)
{
throw ex;
}
}
Childmethod_1()
{
try
{
Childmethod_2();
}
catch(Exception ex)
{
Report(ex);
}
}
Childmethod_2()
{
try
{
[Block of Code]
}
catch(Exception ex)
{
throw ex;
}
}
Report(ex) in the Childmethod_1() is used to log the exception details into Database. If there is an exception occures in the Childmethod_2() whenever 'i' in the MainMethod(): For Loop is 4, will this exception block the rest 6 from the action?
The throw from Childmethod_2 will be caught by the catch from Childmethod_1 and logged to DB too. That catch block does not throw it again, so the exception will not be seen in your main loop, which will not be interrupted.
By the way,
catch(ex)
{
throw ex;
}
isn't only bad practice, it's completely useless. Why not just let the exception happen? Furthermore, the exception sent will not be complete, you'll lose the stack trace. If you really wish to do so, just throw like that:
catch(ex)
{
throw;
}
The answer to your question depends on implementation of Report(ex) method. If it doesn't rethrow the exception, but only stored exception data into the DB, then all iterations of your loop will be executed regardless exceptions occurred. In this case you can simplify your code (look below). Note that in this case you should make sure that Report(ex) method can't throw other exceptions (for example accessing to the database).
void MainMethod()
{
for(i = 0; i < 10; i++)
{
Childmethod_1();
}
}
Childmethod_1()
{
try
{
[Block of Code]
}
catch(Exception ex)
{
Report(ex);
}
}
On the other hand if Report(ex) rethrows exception after storing data into the DB, then the exception will be caught in the catch block of MainMethod and other iterations will not be executed. In this case you can't omit the try-catch block in MainMethod. However ChildMethod_2 is still redundant.
This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
C# cleanest way to write retry logic?
i having a function contains web service call to the server which fails sometime (unable to connect remote server error) due to some disturbance in network. The code is in try catch block. i want to rerun the web service call within try block so that the web call will be done successfully.
const int MaxRetries = 5;
for(int i = 0; i < MaxRetries; i++)
{
try
{
// do stuff
break; // jump out of for loop if everything succeeded
}
catch(Exception)
{
Thread.Sleep(100); // optional delay here
}
}
bool success = false;
int retry = 0;
while (!success && retry<3)
{
try{
// web service calls
success = true;
} catch(Exception) {
retry ++;
}
}
public void Connect()
{
Connect(1);
}
private void Connect(int num)
{
if (num > 3)
throw new Exception("Maximum number of attempts reached");
try
{
// do stuff
}
catch
{
Connect(num++);
}
}
You can put a loop around the try catch block like this:
bool repeat = true
while( repeat){
repeat = false;
try
{
...
}
catch( Exception )
{
repeat = true;
}
}
I think you have your answer here. I just wanted to add a couple of suggestions based on my abundant experience with this problem.
If you add logging to the catch block, you can ascertain how often the web service call fails, and how many attempts were made in all. (Maybe put a toggle in web.config to turn this logging off once the issue subsides.)
That information may prove useful in discussions with system administrators if, for example, the web service provider is within your organization, such as on an intranet.
In addition, if you find that the calls are still failing too often, you could introduce a delay in the catch, so that the retry is not immediate. You might only want to do that on the final attempt. Sometimes it is worth the wait for the user, who doesn't want to lose all the data they have just entered.
And finally, depending on the situation, you could add a Retry button to the UI, so that the user could keep trying. The user could choose to wait five minutes for the network problem to clear itself up, and click Retry.
Wrap the try/catch in a while loop. Set a flag on success to exit the while (or just break out). Make sure you have some sort of retry limit so it won't keep going forever.
while (true)
{
try
{
// call webservice
// handle results
break;
}
catch (TemporaryException e)
{
// do any logging you wish
continue;
}
catch (FatalException e)
{
// do any logging you wish
break;
}
}
If you want to limit the retries, change the termination condition on the while loop.
void Method()
{
do
{
try
{
DoStuff();
return;
}
catch (Exception e)
{
// Do Something about exception.
}
}
while (true);
}
If you find yourself wanting to do this frequently in your code, you might consider implementing a reusable class that encapsulates the "re-try when an error is encountered" logic. This way, you can ensure that the behavior is standardized throughout your code base, instead of repeated each time.
There's an excellent example available on Dan Gartner's blog:
public class Retrier<TResult>
{
public TResult Try(Func<TResult> func, int maxRetries)
{
return TryWithDelay(func, maxRetries, 0);
}
public TResult TryWithDelay(Func<TResult> func, int maxRetries, int delayInMilliseconds)
{
TResult returnValue = default(TResult);
int numTries = 0;
bool succeeded = false;
while (numTries < maxRetries)
{
try
{
returnValue = func();
succeeded = true;
}
catch (Exception)
{
//todo: figure out what to do here
}
finally
{
numTries++;
}
if (succeeded)
return returnValue;
System.Threading.Thread.Sleep(delayInMilliseconds);
}
return default(TResult);
}
}
Well, the easiest would be to copy the code to the catch-block, right?
Another approach could look like:
private void YourMethodThatTriesToCallWebService()
{
//Don't catch errors
}
public void TryToCallWebService(int numTries)
{
bool failed = true;
for(int i = 0; i < numTries && failed; i++)
{
try{
YourMethodThatTriesToCallWebService();
failed = false;
}catch{
//do nothing
}
}
}
You should put the entire catch block into a while statement:
while(retryCount < MAX_RETRY && !success)
{
try
{
//do stuff , calling web service
success = true;
}
catch
{
retryCount++
success = false;
}
}
How is it possible to resume code execution after an exception is thrown?
For example, take the following code:
namespace ConsoleApplication1
{
public class Test
{
public void s()
{
throw new NotSupportedException();
string #class = "" ;
Console.WriteLine(#class);
Console.ReadLine();
}
}
public class Program
{
public static void Main(string[] args)
{
try
{
new Test().s();
}
catch (ArgumentException x)
{
}
catch (Exception ex)
{
}
}
}
}
After catching the exception when stepping through, the program will stop running. How can I still carry on execution?
EDIT: What I specifically mean is the line Console.WriteLine(#class); does not seem to be hit, because when I run to it when in debug mode, the program exits from debug mode. I want to run to this line and stop at it.
Thanks
Well, you don't have any code after the catch blocks, so the program would stop running. Not sure what you're trying to do.
The following should be proof that the program doesn't simply "stop" after the catch blocks. It will execute code after the catch blocks if there is code to be executed:
static void Main(string[] args)
{
try
{
new Test().s();
}
catch (ArgumentException x)
{
Console.WriteLine("ArgumentException caught!");
}
catch (Exception ex)
{
Console.WriteLine("Exception caught!");
}
Console.WriteLine("I am some code that's running after the exception!");
}
The code will print the appropriate string depending on the exception that was caught. Then, it will print I am some code that's running after the exception! at the end.
UPDATE
In your edit you asked why Console.WriteLine(#class); does not seem to be hit. The reason is that you are explicitly throwing an exception in the very first line of your s() method; anything that follows is ignored. When an exception is encountered, execution stops and the exception is propagated up the call stack until the appropriate handler can handle it (this may be a catch block that corresponds to the try that wraps the statement in question within the same method, or it may be a catch block further up the call-stack. If no appropriate handler is found, the program will terminate with a stacktrace [at least in Java - not sure if the same happens in C#]).
If you want to hit the Console.WriteLine line, then you shouldn't be explicitly throwing an exception at the beginning of the method.
It sounds like you're wanting resumeable exceptions. C# doesn't do resumeable exceptions, and I'm doubtful that CLR supports them.
The purpose of throwing an exception is to abort a function and an entire operation (call stack) if/when something in the call environment (parameters, object state, global state) makes the function's operation impossible or invalid. Passing a zero param to a function that needs to divide a quantity by that param, for example. Division by zero won't produce a meaningful result, and if that's the sole purpose of the function, then the function can't return a meaningful result either. So, throw an exception. This will cause execution to jump to the nearest catch or finally block on the call stack. There is no returning to the function that threw the exception.
If you want to step into your code in the debugger to trace the Console.WriteLine() calls, you need to remove the throw new NotSupportedException() line from your code and recompile.
If you're worried that an exception will be thrown in the method but you want the method to continue, add an error handler inside the method.
class Test
{
public void s()
{
try
{
// Code that may throw an exception
throw new NotSupportedException();
}
catch(Exception ex)
{
// Handle the exception - log?, reset some values?
}
string #class = "" ;
Console.WriteLine(#class);
Console.ReadLine();
}
}
You could also return a bool or some other value to indicate the state.
Disclaimer: I am not suggesting that you actually do this.
You can mimic the old VB style On Error Resume Next with the following code.
public static class ControlFlow
{
public static Exception ResumeOnError(Action action)
{
try
{
action();
return null;
}
catch (Exception caught)
{
return caught;
}
}
}
And then it could be used like the following.
public static void Main()
{
ControlFlow.ResumeOnError(() => { throw new NotSupportedException(); });
ControlFlow.ResumeOnError(() => { Console.WriteLine(); });
ControlFlow.ResumeOnError(() => { Console.ReadLine(); });
}
Some simple code I put together to catch exceptions that are thrown inside a catch block:
try
{
//do code here
}
catch (Exception ex)
{
try { SomeMethod1(); }
catch { }
try { SomeMethod2(); }
catch { }
try { SomeMethod3(); }
catch { }
}
finally
{
//cleanup goes here
}
Execution is still carying on but there is no code after the exception is caught. If you want to repeatedly call s then consider wrapping the try/catch block in a while loop.
The program stops running because there is no following code to be executed in the Main() method! You can add the following line to your code to keep the program running until there is a console input:
Console.ReadLine();
For that code, you can't. If you break the tasks up to smaller chunks, you can resume at the next chunk. But normally it's easier to have a different mechanism than exceptions to report non-fatal errors, such as a callback function which returns whether or not to continue.
You can use the "step-over" feature in debugging to achieve this on a per-run basis.
Instead of thowing the NotSupportedException, you could track that an exception was encountered, use a default value, and throw the exception at the end of the method call:
namespace ConsoleApplication1
{
public class Test
{
public void s()
{
bool exceptionEncountered = false;
if(someConditionNotSupported){//stub condition
exceptionEncountered=true
#class="DefaultValue";
}
Console.WriteLine(#class);
Console.ReadLine();
if(exceptionEncountered){
throw new NotSupportedException();
}
}
}
public class Program
{
public static void Main(string[] args)
{
try
{
new Test().s();
}
catch (ArgumentException x)
{
}
catch (Exception ex)
{
}
}
}
}
public static void Main()
{
for (int j = 0; j <= 100000; j++)
{
try
{
// TODO: Application logic...
}
catch
{
System.Threading.Thread.Sleep(1000);
}
}
}
I want to go once through a loop but only if an exception is thrown go back through the loop. How would I write this in C#?
Thanks
This smells of bad design to me. The general rule is: exceptions should not be used for flow control. There are a number of reasons for this; namely, there are usually better/more reliable methods that can be used to check things before an exceptions is thrown, and also it decreases efficiency.
Nonetheless, just for the sake of argument, you could do something like the following:
while (true)
{
try
{
// do stuff here
}
catch (MyException)
{
continue;
}
// all is good
break;
}
Again - this is not the recommended way. I would be happy to suggest something better if you could provide a bit more context/examples/
What about the following where you can set a retry count:
int tryCount = 0;
while (tryCount < 3)
{
try
{
someReturn = SomeFunction(someParams);
}
catch (Exception)
{
tryCount++;
continue;
}
break;
}
That really depends on what you're doing, and the type of exception being thrown. Many exceptions aren't something that would be fixed by just trying again with the exact same inputs/data, and thus looping would just keep generating the exception ad infinitum.
Instead, you should check for relevant exceptions and then handle them in an appropriate manner for those particular exceptions.
You could use Polly
and then you just need to configure the Policy with your exceptions and retry count:
var retryPolicy = Policy
.Handle<IOException>(x => x.Message.Contains("already exist"))
.Or<FormatException>()
.Retry(3);
and you use like this:
retryPolicy.Execute(() =>
{
throw new FormatException();
});
Why not call a function that actually does the loop, and have a catch after it that would call the function again.
private void loop() {
for(...) {
}
}
some other method:
try {
loop();
} catch(Exception e) {
loop();
}
Something like:
bool done = false;
while( ! done )
{
try
{
DoSomething();
done = true;
} catch(Exception ex)
{
HandleException(ex);
}
}
As Noldorin said, it smells like a bad design. You're using exceptions to control the flow of the program. Better to have explicit checks for the conditions that will cause you to repeat the operation.
So I am using this simple stuff :D
bool exceptionthrow = false;
while (!exceptionthrow)
{
try
{
value = Convert.ToInt32(Console.ReadLine()); //example
exceptionthrow = true;
}
catch (Exception)
{
exceptionthrow = false;
continue;
}
}
Hope it helps :)