2

Below is my code in C# Windows application, where connection with Oracle, FTP and Null Reference Exception are handled:

public Result Execute()
{
    Result result = null;
    string errorMessage = string.Empty;

    var retryTimes = 1000;
    var retryableErrorCodes = new[] { "ORA-03113", "ORA-03114", "ORA-12543",
        "ORA-12170", "ORA-12154", "ORA-12541", "ORA-12560", "ORA-03135",
        "Connection request timed out" };
    var retryExceptionError = new[] { "Object reference not set to an instance of an object" };

    RetryPolicy retryPolicyFTP = Policy
        .Handle<Xceed.Ftp.FtpInvalidStateException>().Or<Xceed.Ftp.FtpIOException>()
        .WaitAndRetry(retryTimes, _ => TimeSpan.FromSeconds(1));

    RetryPolicy retryPolicyOracle = Policy
        .Handle<OracleException>(ex => retryableErrorCodes.Any(errorCode => ex.Message.ToString().Contains(errorCode)))
        .WaitAndRetry(retryTimes, _ => TimeSpan.FromSeconds(1));

    RetryPolicy retryException = Policy
        .Handle<Exception>(ex => retryExceptionError.Any(errorCode => ex.Message.ToString().Contains(errorCode)))
        .WaitAndRetry(retryTimes, _ => TimeSpan.FromSeconds(1));

    Policy.Wrap(retryPolicyFTP, retryPolicyOracle, retryException).Execute(() =>
    {
        //few lines of C# Code like fetching details from Database
        if(some condition)
        {
            //Some Operations
            return new Result(ResultType.Failure, "This function has Failed");
        }
        if(some other condition)
        {
            //Some Operations
            return new Result(ResultType.Success, "This function is Successful");
        }
        //Some more lines of C# Code
    });
    return Result.Successful;
}

With this code, I cannot use return keyword in the middle of the function, because Polly framework does not allow it to do so.

Could you please suggest what is the better way of handling return keyword in the middle of the function?

2
  • Your question isn't clear. Did you mean to put the return Result.Successful before the }); on the line above? Commented Jul 21, 2021 at 13:10
  • 1
    There are return keywords inside Policy.Wrap. When you copy the same code in Visual Studio , then you would see to red squigglies for the return keywords inside if conditions. I would like to have an executable code with this Policy.Wrap. Commented Jul 21, 2021 at 13:14

1 Answer 1

7

In Polly you can define decorators for methods and for functions.

In case of a method the retry policy should be defined like this:

RetryPolicy retryPolicyFTP = Policy
    .Handle<Xceed.Ftp.FtpInvalidStateException>().Or<Xceed.Ftp.FtpIOException>()
    .WaitAndRetry(retryTimes, _ => TimeSpan.FromSeconds(1));

In case of a function the retry policy should be defined like this:

RetryPolicy<Result> retryPolicyFTP = Policy<Result>
    .Handle<Xceed.Ftp.FtpInvalidStateException>().Or<Xceed.Ftp.FtpIOException>()
    .WaitAndRetry(retryTimes, _ => TimeSpan.FromSeconds(1));

You should spot here the <Result> parts on lhs and rhs as well.


With this knowledge your method could be rewritten like this:

public Result Execute()
{
    Result result = null;
    string errorMessage = string.Empty;

    var retryTimes = 1000;
    var retryableErrorCodes = new[] { "ORA-03113", "ORA-03114", "ORA-12543", "ORA-12170", "ORA-12154", "ORA-12541", "ORA-12560", "ORA-03135", "Connection request timed out" };
    var retryExceptionError = new[] { "Object reference not set to an instance of an object" };

    RetryPolicy<Result> retryPolicyFTP = Policy<Result>
        .Handle<Xceed.Ftp.FtpInvalidStateException>().Or<Xceed.Ftp.FtpIOException>()
        .WaitAndRetry(retryTimes, _ => TimeSpan.FromSeconds(1));

    RetryPolicy<Result> retryPolicyOracle = Policy<Result>
        .Handle<OracleException>(ex => retryableErrorCodes.Any(errorCode => ex.Message.ToString().Contains(errorCode)))
        .WaitAndRetry(retryTimes, _ => TimeSpan.FromSeconds(1));

    RetryPolicy<Result> retryException = Policy<Result>
        .Handle<Exception>(ex => retryExceptionError.Any(errorCode => ex.Message.ToString().Contains(errorCode)))
        .WaitAndRetry(retryTimes, _ => TimeSpan.FromSeconds(1));

    Result res = Policy.Wrap(retryPolicyFTP, retryPolicyOracle, retryException).Execute(() =>
    {
        if (some condition)
        {
            return new Result(ResultType.Failure, "This function has Failed");
        }
        if (some other condition)
        {
            return new Result(ResultType.Success, "This function is Successful");
        }
        return Result.Successful;
    });
    return res;
}

Because your Execute has to return a Result that's why the Result.Successful could be moved inside the Execute block.


I would also suggest to separate strategy declaration and execution like this:

public Result Execute()
{
    ...

    var strategy = Policy.Wrap(retryPolicyFTP, retryPolicyOracle, retryException)
    return strategy.Execute(() =>
    {
        if (some condition)
        {
            return new Result(ResultType.Failure, "This function has Failed");
        }
        if (some other condition)
        {
            return new Result(ResultType.Success, "This function is Successful");
        }
        return Result.Successful;
    });
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.