public override AsyncUnaryCall <TResponse> AsyncUnaryCall <TRequest, TResponse>(TRequest request,
                                                                                        ClientInterceptorContext <TRequest, TResponse> context,
                                                                                        AsyncUnaryCallContinuation <TRequest, TResponse> continuation)
        {
            var currentRetry = 0;

            string headerTimeout = context.GetHeaderStringValue(GrpcConstants.TimeoutMetadataKey, true);
            int    timeout       = headerTimeout == null ? GrpcConstants.DefaultRequestTimeout : int.Parse(headerTimeout);
            var    timeoutSpan   = TimeSpan.FromMilliseconds(timeout);

            string headerRetryCount = context.GetHeaderStringValue(GrpcConstants.RetryCountMetadataKey, true);
            int    retryCount       = headerRetryCount == null
                ? NetworkConstants.DefaultRequestRetryCount
                : int.Parse(headerRetryCount);

            async Task <TResponse> RetryCallback(Task <TResponse> responseTask)
            {
                var response = responseTask;

                // if no problem occured return
                if (!response.IsFaulted)
                {
                    return(response.Result);
                }

                // if a problem occured but reached the max retries
                if (currentRetry == retryCount)
                {
                    return(response.Result);
                }

                currentRetry++;

                // try again
                var retryContext = BuildNewContext(context, timeoutSpan);

                var result = GetResponseAsync(continuation(request, retryContext), timeoutSpan)
                             .ContinueWith(RetryCallback).Unwrap();

                return(await result);
            }

            var newContext           = BuildNewContext(context, timeoutSpan);
            var responseContinuation = continuation(request, newContext);

            var responseAsync = GetResponseAsync(responseContinuation, timeoutSpan).ContinueWith(RetryCallback)
                                .Unwrap();

            return(new AsyncUnaryCall <TResponse>(
                       responseAsync,
                       responseContinuation.ResponseHeadersAsync,
                       responseContinuation.GetStatus,
                       responseContinuation.GetTrailers,
                       responseContinuation.Dispose));
        }
        public void GetHeader_Test()
        {
            var context = new ClientInterceptorContext <string, string>(null, null, new CallOptions());

            context.GetHeaderStringValue(GrpcConstants.RetryCountMetadataKey).ShouldBeNull();

            context = new ClientInterceptorContext <string, string>(null, null, new CallOptions(new Metadata()));
            context.GetHeaderStringValue(GrpcConstants.RetryCountMetadataKey).ShouldBeNull();

            Metadata data = new Metadata
            {
                { GrpcConstants.TimeoutMetadataKey, "TimeoutMetadata" },
                { GrpcConstants.RetryCountMetadataKey, "2" }
            };

            context = new ClientInterceptorContext <string, string>(null, null, new CallOptions(data));
            context.GetHeaderStringValue(GrpcConstants.TimeoutMetadataKey).ShouldBe("TimeoutMetadata");
            context.GetHeaderStringValue(GrpcConstants.RetryCountMetadataKey).ShouldBe("2");

            context.GetHeaderStringValue(GrpcConstants.TimeoutMetadataKey, true).ShouldBe("TimeoutMetadata");
            context.GetHeaderStringValue(GrpcConstants.RetryCountMetadataKey, true).ShouldBe("2");

            context.GetHeaderStringValue(GrpcConstants.TimeoutMetadataKey).ShouldBeNull();
            context.GetHeaderStringValue(GrpcConstants.RetryCountMetadataKey).ShouldBeNull();
        }