private void HandleOnCallBegin(InvokeInfo invokeInfo)
 {
     this.OnCallBegin(this, new OnCallBeginHandlerArguments
     {
         ServiceType = _originalServiceInterfaceType,
         InvokeInfo  = invokeInfo
     });
 }
 public Task InvokeAsync(Func <TServiceInterface, Task> method, InvokeInfo invokeInfo = null)
 {
     return(this.InvokeAsync(async provider =>
     {
         await method(provider).ConfigureAwait(false);
         return Task.FromResult(true);
     }, invokeInfo));
 }
 /// <summary>
 /// This function is called when a proxy's method is called that should return void.
 /// </summary>
 /// <param name="method">Method implementing the service call using WCF</param>
 /// <param name="invokeInfo"></param>
 public void Invoke(Action <TServiceInterface> method, InvokeInfo invokeInfo = null)
 {
     Invoke(provider =>
     {
         method(provider);
         return(new VoidReturnType());
     }, invokeInfo);
 }
 private TServiceInterface Delay(
     int iteration,
     IDelayPolicy delayPolicy,
     TServiceInterface provider,
     InvokeInfo invokeInfo)
 {
     Thread.Sleep(delayPolicy.GetDelay(iteration));
     return(RefreshProvider(provider, iteration, invokeInfo));
 }
 private void HandleOnBeforeInvoke(int retryCounter, InvokeInfo invokeInfo)
 {
     this.OnBeforeInvoke(this, new OnInvokeHandlerArguments
     {
         ServiceType  = _originalServiceInterfaceType,
         RetryCounter = retryCounter,
         InvokeInfo   = invokeInfo
     });
 }
        private async Task <TServiceInterface> DelayAsync(
            int iteration,
            IDelayPolicy delayPolicy,
            TServiceInterface provider,
            InvokeInfo invokeInfo)
        {
            await Task.Delay(delayPolicy.GetDelay(iteration)).ConfigureAwait(false);

            return(RefreshProvider(provider, iteration, invokeInfo));
        }
 private void HandleOnException(Exception exception, int retryCounter, InvokeInfo invokeInfo)
 {
     this.OnException(this, new OnExceptionHandlerArguments
     {
         Exception    = exception,
         ServiceType  = _originalServiceInterfaceType,
         RetryCounter = retryCounter,
         InvokeInfo   = invokeInfo,
     });
 }
        private void HandleOnAfterInvoke(int retryCounter, object response, InvokeInfo invokeInfo)
        {
            // set return value if non-void
            if (invokeInfo != null && response != null && response.GetType() != typeof(VoidReturnType))
            {
                invokeInfo.MethodHasReturnValue = true;
                invokeInfo.ReturnValue          = response;
            }

            this.OnAfterInvoke(this, new OnInvokeHandlerArguments
            {
                ServiceType  = _originalServiceInterfaceType,
                RetryCounter = retryCounter,
                InvokeInfo   = invokeInfo,
            });
        }
        private void DisposeProvider(TServiceInterface provider, int retryCount, InvokeInfo invokeInfo)
        {
            var communicationObject = provider as ICommunicationObject;

            if (communicationObject == null || communicationObject.State == CommunicationState.Closed)
            {
                return;
            }

            bool success = false;

            try
            {
                if (communicationObject.State != CommunicationState.Faulted)
                {
                    communicationObject.Close();
                    success = true;
                }
            }
            catch (CommunicationException ex)
            {
                this.HandleOnException(ex, retryCount, invokeInfo);
            }
            catch (TimeoutException ex)
            {
                this.HandleOnException(ex, retryCount, invokeInfo);
            }
            catch (Exception ex)
            {
                this.HandleOnException(ex, retryCount, invokeInfo);
                throw;
            }
            finally
            {
                if (!success)
                {
                    this.AbortServiceChannel(communicationObject, retryCount, invokeInfo);
                }
            }
        }
 private void AbortServiceChannel(ICommunicationObject communicationObject, int retryCount, InvokeInfo invokeInfo)
 {
     try
     {
         communicationObject.Abort();
     }
     catch (Exception ex)
     {
         this.HandleOnException(ex, retryCount, invokeInfo);
     }
 }
        /// <summary>
        /// Refreshes the proxy by disposing and recreating it if it's faulted.
        /// </summary>
        /// <param name="provider">The provider.</param>
        /// <param name="retryCount">Number of retries to perform</param>
        /// <param name="invokeInfo"></param>
        /// <returns></returns>
        private TServiceInterface RefreshProvider(TServiceInterface provider, int retryCount, InvokeInfo invokeInfo)
        {
            var communicationObject = provider as ICommunicationObject;

            if (communicationObject == null)
            {
                return(_wcfActionProviderCreator());
            }

            if (communicationObject.State == CommunicationState.Opened)
            {
                return(provider);
            }

            DisposeProvider(provider, retryCount, invokeInfo);
            provider = null;

            return(_wcfActionProviderCreator());
        }
        private void HandleOnCallSuccess(TimeSpan callDuration, object response, int requestAttempts, InvokeInfo invokeInfo)
        {
            if (invokeInfo != null && response != null && response.GetType() != typeof(VoidReturnType))
            {
                invokeInfo.MethodHasReturnValue = true;
                invokeInfo.ReturnValue          = response;
            }

            this.OnCallSuccess(this, new OnCallSuccessHandlerArguments
            {
                ServiceType     = _originalServiceInterfaceType,
                InvokeInfo      = invokeInfo,
                CallDuration    = callDuration,
                RequestAttempts = requestAttempts
            });
        }
        public async Task <TResponse> InvokeAsync <TResponse>(Func <TServiceInterface, Task <TResponse> > method, InvokeInfo invokeInfo = null)
        {
            TServiceInterface provider     = RefreshProvider(null, 0, invokeInfo);
            TResponse         lastResponse = default(TResponse);
            IDelayPolicy      delayPolicy  = DelayPolicyFactory();

            var sw = Stopwatch.StartNew();

            try
            {
                this.HandleOnCallBegin(invokeInfo);

                Exception mostRecentException = null;
                for (int i = 0; i < RetryCount + 1; i++)
                {
                    try
                    {
                        this.HandleOnBeforeInvoke(i, invokeInfo);

                        TResponse response = await method(provider).ConfigureAwait(false);

                        this.HandleOnAfterInvoke(i, response, invokeInfo);

                        if (ResponseInRetryable(response))
                        {
                            lastResponse = response;
                            provider     = await DelayAsync(i, delayPolicy, provider, invokeInfo).ConfigureAwait(false);

                            continue;
                        }

                        sw.Stop();

                        response = this.ExecuteResponseHandlers(response);

                        this.HandleOnCallSuccess(sw.Elapsed, response, (i + 1), invokeInfo);

                        return(response);
                    }
                    catch (Exception ex)
                    {
                        this.HandleOnException(ex, i, invokeInfo);

                        // determine whether to retry the service call
                        if (ExceptionIsRetryable(ex))
                        {
                            mostRecentException = ex;

                            provider = await DelayAsync(i, delayPolicy, provider, invokeInfo).ConfigureAwait(false);
                        }
                        else
                        {
                            throw;
                        }
                    }
                }

                if (mostRecentException != null)
                {
                    if (RetryCount == 0)
                    {
                        throw mostRecentException;
                    }

                    var exception = this.RetryFailureExceptionFactory(this.RetryCount, mostRecentException, invokeInfo);
                    throw exception;
                }
            }
            finally
            {
                DisposeProvider(provider, -1, invokeInfo);
            }

            return(lastResponse);
        }