0

I am implementing retry logic for WCF services on the client side. I have multiple operations in WCF service with various input parameters and return types.

I created a wrapper that can make a call to these certain methods that have no return type(void) using Action delegate. Is there any way to call methods that have various input parameters and return type.

Or is there any logic to implement retry functionality on the client side that can handle multiple WCF services.

Class RetryPolicy<T>
{
 public T ExecuteAction(Func<T> funcdelegate,int? pretrycount = null,bool? pexponenialbackoff = null)
        {
            try
            {
                var T = funcdelegate();
                return T;
            }
            catch(Exception e)
            {
                if (enableRetryPolicy=="ON" && TransientExceptions.IsTransient(e))
                {

                    int? rcount = pretrycount == null ? retrycount : pretrycount;
                    bool? exbackoff = pexponenialbackoff == null ? exponentialbackoff : pexponenialbackoff;

                    int rt = 0;
                    for (rt = 0; rt < rcount; rt++)
                    {
                        if (exponentialbackoff)
                        {
                            delayinms = getWaitTimeExp(rt);
                        }

                        System.Threading.Thread.Sleep(delayinms);

                        try
                        {
                            var T = funcdelegate();
                            return T;
                        }
                        catch(Exception ex)
                        {
                            if (TransientExceptions.IsTransient(ex))
                            {

                                int? rcount1 = pretrycount == null ? retrycount : pretrycount;
                                bool? exbackoff1 = pexponenialbackoff == null ? exponentialbackoff : pexponenialbackoff;

                            }
                            else
                            {
                                throw;
                            }
                        }
                    }

                    //throw exception back to caller if exceeded number of retries
                    if(rt == rcount)
                    {
                        throw;
                    }
                }
                else
                {
                    throw;
                }
            }
            return default(T);
        }
}  

I use above method and make a call

  public string GetCancelNumber(string property, Guid uid)
        {
            RetryPolicy<string> rp = new RetryPolicy<string>();
            return rp.ExecuteAction(()=>Channel.GetCancelNumber(property, uid, out datasetarray));
        }

I keep getting error "cannot use ref or out parameters in anonymous delegate"

Deepak
  • 23
  • 2
  • 7

1 Answers1

2

Here is an example of a simple Retry method:

bool Retry(int numberOfRetries, Action method)
{
    if (numberOfRetries > 0)
    {
        try
        {
            method();
            return true;
        }
        catch (Exception e)
        {
            // Log the exception
            LogException(e); 

            // wait half a second before re-attempting. 
            // should be configurable, it's hard coded just for the example.
            Thread.Sleep(500); 

            // retry
            return Retry(--numberOfRetries, method);
        }
    }
    return false;
}

It will return true if the method succeed at least once, and log any exception until then. If the method fails on every retry, it will return false.

(Succeed means completed without throwing an exception in this case)

How to use:

Assuming sample Action (void method) and sample Func (a method with a return type)

void action(int param) {/* whatever implementation you want */}
int function(string param) {/* whatever implementation you want */}

Execute a function:

int retries = 3;
int result = 0;
var stringParam = "asdf";
if (!Retry(retries, () => result = function(stringParam)))
{
    Console.WriteLine("Failed in all {0} attempts", retries);
}
else
{
    Console.WriteLine(result.ToString());
}

Execute an action:

int retries = 7;
int number = 42;
if (!Retry(retries, () => action(number)))
{
    Console.WriteLine("Failed in all {0} attempts", retries);
}
else
{
    Console.WriteLine("Success");
}

Execute a function with an out parameter (int function(string param, out int num)):

int retries = 3;
int result = 0;
int num = 0;
var stringParam = "asdf";
if (!Retry(retries, () => result = function(stringParam, out num)))
{
    Console.WriteLine("Failed in all {0} attempts", retries);
}
else
{
    Console.WriteLine("{0} - {1}", result, num);
}
Zohar Peled
  • 79,642
  • 10
  • 69
  • 121
  • Hi, thanks for answer.. but most my functions also have out parameter and func, action is not accepting out parameter..any idea how to include out parameters. – Deepak Nov 02 '17 at 11:58
  • Not a problem at all. The action itself doesn't include any parameter, but it does execute whatever you want. Edited my answer with an example. The only thing here that is a bit counter-intuitive is that you must initialize the out parameter as well. – Zohar Peled Nov 02 '17 at 12:32
  • Come to think about it, I must initialize `num` since I'm using it in the `else`. – Zohar Peled Nov 02 '17 at 12:38
  • Hi,, p.CallwithAction(() => returnVal = Channel.Isvaliduser( userName, password, out isClientCertified, out sessionid, out userid, out logonReason)); , it throws an error saying "cannot use ref or out parameters inside an anonymous method,lambda expression or query expression" – Deepak Nov 02 '17 at 15:21
  • i initialzed the varaibles isClientCertified,sessionid,userid,logonreason – Deepak Nov 02 '17 at 15:23
  • I don't see it. [Fiddle is having problems with the try...catch but works anyway.](https://dotnetfiddle.net/vjjWVR) – Zohar Peled Nov 02 '17 at 15:45
  • Hi, Most of the answer is correct and it works well in fiddle, but i am not sure why, i still keep getting error "cannot user ref or out parameters insider anonymous method".. i am using.Net 4.0 and also i edited my question with the code. – Deepak Nov 06 '17 at 13:28
  • You can also use ready-made libraries like Polly https://github.com/App-vNext/Polly ; https://www.nuget.org/packages/Polly.Net40Async/ ; rather than re-write this functionality from scratch. [Disclosure: I'm involved with Polly]. – mountain traveller Nov 06 '17 at 14:04
  • Re "Cannot use ref or out parameter in lambda expressions", see https://stackoverflow.com/questions/1365689/cannot-use-ref-or-out-parameter-in-lambda-expressions – mountain traveller Nov 06 '17 at 14:04
  • I didn't try ref, but out was working fine for me. My suggestion is either go with mountain traveller's suggestion or don't use ref and out parameters in this section of the code. – Zohar Peled Nov 06 '17 at 15:21