Often, we have transient problems in our application, such as a network failure, system rebooting, or anything else that throws an exception. In this article, we are going to learn how to implement retry logic in C# to help us handle these problems.

To download the source code for this article, you can visit our GitHub repository.

Let’s start.

Simulate a Failure in Our Application

Before we create the retry logic in C#, we need a method that can create a transient problem. That said, let’s create a very basic logic to simulate the failure:

Support Code Maze on Patreon to get rid of ads and get the best discounts on our products!
Become a patron at Patreon!
public static void FirstSimulationMethod()
{
    const int forbiddenNumber = 3;

    Console.Write("Write a number: ");
    var number = int.Parse(Console.ReadLine() ?? "0");

    if (number == forbiddenNumber)
        throw new ArgumentException($"The generated number must be different from {forbiddenNumber}");

    Console.Write("Not Equal");
}

First, this method asks for a number. After parsing this number into an integer, it compares this number to a forbidden number we previously set.

If the input number is equal to the forbidden number, this method is going to throw an exception with a message, otherwise, it prints the “Not Equal” message in the console.

This exception simulates a transient problem that may occur by a brief network failure or something like this.

Creating the Second Method

Let’s inspect the second method:

public static int SecondSimulationMethod()
{
    const int forbiddenNumber = 3;

    Console.Write("Write a number: ");
    var number = int.Parse(Console.ReadLine() ?? "0");

    if (number == forbiddenNumber)
        throw new ArgumentException($"The generated number must be different from {forbiddenNumber}");

    Console.Write("Not Equal");

    return number;
}

Note that this method is very similar to the FirstSimulationMethod, however, in the end, it returns the input value. This method is important to show how to implement retry logic using Action or Func delegates.

In case you are not familiar with the Action and Func delegates, or delegates overall, you can learn more here.

Implementing the Retry Logic in C#

Once we have the methods to simulate the transient problems, we can focus on writing the retry logic in C#. Let’s create an Executor static class with an Execute method:

public static class Executor
{
    public static void Execute(Action action, int numberOfRetries)
    {
        var tries = 0;

        while (tries <= numberOfRetries)
        {
            try
            {
                action();
                return;
            }
            catch
            {
                tries++;
            }
        }

        throw new RetryException($"Error after {tries} tries");
    }
}

The Execute method is responsible to execute the logic several times if there’s any problem. It receives an Action as a first parameter and the number of times we want to retry (numberOfRetries) as a second parameter.

Then, we need to loop and execute the method until the tries variable value is lower or equal to the numberOfRetries variable value. If the Action executes successfully, the retry logic finishes its execution. However, in case of exception, it increments the tries variable and retries to execute the Action.

When the tries value is greater or equal than the numberOfRetries, it finishes the execution and throws an exception with some message.

Retry Logic in C# With the Func Delegate

Now, let’s create a new overload of the Execute method:

public static TResult? Execute<TResult>(Func<TResult> func, int numberOfRetries)
{
    var tries = 0;
    
    while (tries <= numberOfRetries)
    {
        try
        {
            return func();
        }
        catch
        {
            tries++;
        }
    }

    throw new RetryException($"Error after {tries} tries");
}

Note that the main difference is that this time this is a generic method with a return type.

Once it has a return type, instead of receiving an Action as a parameter, this method receives a Func, and then, we return the result of this Func.

With both previous methods, we can use this retry logic in C# for both, Action and Func delegates.

Using the Executor Class

Once we have defined the Executor class and its methods, it is time to execute the FirstSimulationMethod and the SecondSimulationMethod methods.

Let’s check it:

Executor.Execute(FirstSimulationMethod, 3);

We call the Execute method under the Executor class passing the method we want to execute, and the maximum number of retries as parameters.

Now, let’s use the overload method:

var result = Executor.Execute(SecondSimulationMethod, 3);

This time, we pass a Func as the first parameter. That said, we need to declare a result variable to receive the return from this Func.

It is good to mention that when we send 3 as the number of retries, this method is going to execute 4 times. The first execution and three retries. 

Retry Logic in C# Using Polly

Polly is a NuGet Package that allows us to handle transient problems. We often use it to create resilient microservices.

To use Polly, first, we need to install the Polly NuGet Package:

Install-Package Polly

Once we have Polly installed, let’s check how to use its retry feature:

Policy
    .Handle<ArgumentException>()
    .Retry(3)
    .Execute(FirstSimulationMethod);

First, we need to use the Handle generic method inside the Policy static class to tell Polly which kind of exception we are expecting. In case we are expecting multiple exceptions, after the Handle method, we can use the Or<>()method to specify the other exception we want to handle.

Next, we use the Retry method passing an integer as a parameter that represents the number of times we want to retry. 

Finally, we call the Execute method and pass an Action or a Func we want to execute as a parameter. 

Conclusion

In this article, we’ve implemented our basic retry logic to use in our daily routine. Also, we have seen how to use Polly to achieve the same result. Among all Polly’s features, in this article, we covered the retry policy, however, we highly recommend looking at Polly’s GitHub Source Code and Polly’s Wiki to see all the other features it contains.

Liked it? Take a second to support Code Maze on Patreon and get the ad free reading experience!
Become a patron at Patreon!