public async Task <IBoxResponse <T> > ExecuteAsync <T>(IBoxRequest request) where T : class { // Need to account for special cases when the return type is a stream bool isStream = typeof(T) == typeof(Stream); var retryCounter = 0; ExponentialBackoff expBackoff = new ExponentialBackoff(); try { // TODO: yhu@ better handling of different request var isMultiPartRequest = request.GetType() == typeof(BoxMultiPartRequest); var isBinaryRequest = request.GetType() == typeof(BoxBinaryRequest); while (true) { HttpRequestMessage httpRequest = getHttpRequest(request, isMultiPartRequest, isBinaryRequest); Debug.WriteLine(string.Format("RequestUri: {0}", httpRequest.RequestUri)); HttpResponseMessage response = await getResponse(request, isStream, httpRequest).ConfigureAwait(false); //need to wait for Retry-After seconds and then retry request var retryAfterHeader = response.Headers.RetryAfter; // If we get a retryable/transient error code and this is not a multi part request (meaning a file upload, which cannot be retried // because the stream cannot be reset) and we haven't exceeded the number of allowed retries, then retry the request. // If we get a 202 code and has a retry-after header, we will retry after if (!isMultiPartRequest && (response.StatusCode == TooManyRequests || response.StatusCode == HttpStatusCode.InternalServerError || response.StatusCode == HttpStatusCode.BadGateway || response.StatusCode == HttpStatusCode.ServiceUnavailable || response.StatusCode == HttpStatusCode.GatewayTimeout || (response.StatusCode == HttpStatusCode.Accepted && retryAfterHeader != null)) && retryCounter++ < RetryLimit) { TimeSpan delay = expBackoff.GetRetryTimeout(retryCounter); Debug.WriteLine("HttpCode : {0}. Waiting for {1} seconds to retry request. RequestUri: {2}", response.StatusCode, delay.Seconds, httpRequest.RequestUri); await Task.Delay(delay); } else { BoxResponse <T> boxResponse = await getBoxResponse <T>(isStream, response).ConfigureAwait(false); return(boxResponse); } } } catch (Exception ex) { Debug.WriteLine(string.Format("Exception: {0}", ex.Message)); throw; } }
public async Task <IBoxResponse <T> > ExecuteAsyncWithoutRetry <T>(IBoxRequest request) where T : class { // Need to account for special cases when the return type is a stream bool isStream = typeof(T) == typeof(Stream); try { // TODO: yhu@ better handling of different request var isMultiPartRequest = request.GetType() == typeof(BoxMultiPartRequest); var isBinaryRequest = request.GetType() == typeof(BoxBinaryRequest); HttpRequestMessage httpRequest = getHttpRequest(request, isMultiPartRequest, isBinaryRequest); Debug.WriteLine(string.Format("RequestUri: {0}", httpRequest.RequestUri)); HttpResponseMessage response = await getResponse(request, isStream, httpRequest).ConfigureAwait(false); BoxResponse <T> boxResponse = await getBoxResponse <T>(isStream, response).ConfigureAwait(false); return(boxResponse); } catch (Exception ex) { Debug.WriteLine(string.Format("Exception: {0}", ex.Message)); throw; } }
public async Task <IBoxResponse <T> > ExecuteAsync <T>(IBoxRequest request) where T : class { // Need to account for special cases when the return type is a stream bool isStream = typeof(T) == typeof(Stream); HttpRequestMessage httpRequest = request.GetType() == typeof(BoxMultiPartRequest) ? BuildMultiPartRequest(request as BoxMultiPartRequest) : BuildRequest(request); // Add headers foreach (var kvp in request.HttpHeaders) { if (kvp.Key == Constants.RequestParameters.ContentMD5) { httpRequest.Content.Headers.Add(kvp.Key, kvp.Value); } else { httpRequest.Headers.TryAddWithoutValidation(kvp.Key, kvp.Value); } } // If we are retrieving a stream, we should return without reading the entire response HttpCompletionOption completionOption = isStream ? HttpCompletionOption.ResponseHeadersRead : HttpCompletionOption.ResponseContentRead; Debug.WriteLine(string.Format("RequestUri: {0}", httpRequest.RequestUri));//, RequestHeader: {1} , httpRequest.Headers.Select(i => string.Format("{0}:{1}", i.Key, i.Value)).Aggregate((i, j) => i + "," + j))); try { HttpClient client = CreateClient(request); HttpResponseMessage response = await client.SendAsync(httpRequest, completionOption).ConfigureAwait(false); BoxResponse <T> boxResponse = new BoxResponse <T>(); boxResponse.Headers = response.Headers; // Translate the status codes that interest us boxResponse.StatusCode = response.StatusCode; switch (response.StatusCode) { case HttpStatusCode.OK: case HttpStatusCode.Created: case HttpStatusCode.NoContent: case HttpStatusCode.Found: boxResponse.Status = ResponseStatus.Success; break; case HttpStatusCode.Accepted: boxResponse.Status = ResponseStatus.Pending; break; case HttpStatusCode.Unauthorized: boxResponse.Status = ResponseStatus.Unauthorized; break; case HttpStatusCode.Forbidden: boxResponse.Status = ResponseStatus.Forbidden; break; default: boxResponse.Status = ResponseStatus.Error; break; } if (isStream && boxResponse.Status == ResponseStatus.Success) { var resObj = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); boxResponse.ResponseObject = resObj as T; } else { boxResponse.ContentString = await response.Content.ReadAsStringAsync().ConfigureAwait(false); } return(boxResponse); } catch (Exception ex) { Debug.WriteLine(string.Format("Exception: {0}", ex.Message)); throw; } }
public async Task <IBoxResponse <T> > ExecuteAsync <T>(IBoxRequest request) where T : class { // Need to account for special cases when the return type is a stream bool isStream = typeof(T) == typeof(Stream); var retryCounter = 0; ExponentialBackoff expBackoff = new ExponentialBackoff(); try { // TODO: yhu@ better handling of different request var isMultiPartRequest = request.GetType() == typeof(BoxMultiPartRequest); var isBinaryRequest = request.GetType() == typeof(BoxBinaryRequest); while (true) { HttpRequestMessage httpRequest = null; if (isMultiPartRequest) { httpRequest = BuildMultiPartRequest(request as BoxMultiPartRequest); } else if (isBinaryRequest) { httpRequest = BuildBinaryRequest(request as BoxBinaryRequest); } else { httpRequest = BuildRequest(request); } // Add headers foreach (var kvp in request.HttpHeaders) { // They could not be added to the headers directly if (kvp.Key == Constants.RequestParameters.ContentMD5 || kvp.Key == Constants.RequestParameters.ContentRange) { httpRequest.Content.Headers.Add(kvp.Key, kvp.Value); } else { httpRequest.Headers.TryAddWithoutValidation(kvp.Key, kvp.Value); } } // If we are retrieving a stream, we should return without reading the entire response HttpCompletionOption completionOption = isStream ? HttpCompletionOption.ResponseHeadersRead : HttpCompletionOption.ResponseContentRead; Debug.WriteLine(string.Format("RequestUri: {0}", httpRequest.RequestUri)); HttpClient client = GetClient(request); // Not disposing the reponse since it will affect stream response var response = await client.SendAsync(httpRequest, completionOption).ConfigureAwait(false); //need to wait for Retry-After seconds and then retry request var retryAfterHeader = response.Headers.RetryAfter; // If we get a retryable/transient error code and this is not a multi part request (meaning a file upload, which cannot be retried // because the stream cannot be reset) and we haven't exceeded the number of allowed retries, then retry the request. // If we get a 202 code and has a retry-after header, we will retry after if (!isMultiPartRequest && (response.StatusCode == TooManyRequests || response.StatusCode == HttpStatusCode.InternalServerError || response.StatusCode == HttpStatusCode.GatewayTimeout || response.StatusCode == HttpStatusCode.BadGateway || (response.StatusCode == HttpStatusCode.Accepted && retryAfterHeader != null)) && retryCounter++ < RetryLimit) { TimeSpan delay = expBackoff.GetRetryTimeout(retryCounter); Debug.WriteLine("HttpCode : {0}. Waiting for {1} seconds to retry request. RequestUri: {2}", response.StatusCode, delay.Seconds, httpRequest.RequestUri); await Task.Delay(delay); } else { BoxResponse <T> boxResponse = new BoxResponse <T>(); boxResponse.Headers = response.Headers; // Translate the status codes that interest us boxResponse.StatusCode = response.StatusCode; switch (response.StatusCode) { case HttpStatusCode.OK: case HttpStatusCode.Created: case HttpStatusCode.NoContent: case HttpStatusCode.Found: case HttpStatusCode.PartialContent: // Download with range boxResponse.Status = ResponseStatus.Success; break; case HttpStatusCode.Accepted: boxResponse.Status = ResponseStatus.Pending; break; case HttpStatusCode.Unauthorized: boxResponse.Status = ResponseStatus.Unauthorized; break; case HttpStatusCode.Forbidden: boxResponse.Status = ResponseStatus.Forbidden; break; case TooManyRequests: boxResponse.Status = ResponseStatus.TooManyRequests; break; default: boxResponse.Status = ResponseStatus.Error; break; } if (isStream && boxResponse.Status == ResponseStatus.Success) { var resObj = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); boxResponse.ResponseObject = resObj as T; } else { boxResponse.ContentString = await response.Content.ReadAsStringAsync().ConfigureAwait(false); // We can safely dispose the response now since all of it has been read response.Dispose(); } return(boxResponse); } } } catch (Exception ex) { Debug.WriteLine(string.Format("Exception: {0}", ex.Message)); throw; } }
public async Task <IBoxResponse <T> > ExecuteAsync <T>(IBoxRequest request) where T : class { // Need to account for special cases when the return type is a stream bool isStream = typeof(T) == typeof(Stream); var numRetries = 3; try { // TODO: yhu@ better handling of different request var isMultiPartRequest = request.GetType() == typeof(BoxMultiPartRequest); var isBinaryRequest = request.GetType() == typeof(BoxBinaryRequest); while (true) { HttpRequestMessage httpRequest = null; if (isMultiPartRequest) { httpRequest = BuildMultiPartRequest(request as BoxMultiPartRequest); } else if (isBinaryRequest) { httpRequest = BuildBinaryRequest(request as BoxBinaryRequest); } else { httpRequest = BuildRequest(request); } // Add headers foreach (var kvp in request.HttpHeaders) { // They could not be added to the headers directly if (kvp.Key == Constants.RequestParameters.ContentMD5 || kvp.Key == Constants.RequestParameters.ContentRange) { httpRequest.Content.Headers.Add(kvp.Key, kvp.Value); } else { httpRequest.Headers.TryAddWithoutValidation(kvp.Key, kvp.Value); } } // If we are retrieving a stream, we should return without reading the entire response HttpCompletionOption completionOption = isStream ? HttpCompletionOption.ResponseHeadersRead : HttpCompletionOption.ResponseContentRead; Debug.WriteLine(string.Format("RequestUri: {0}", httpRequest.RequestUri));//, RequestHeader: {1} , httpRequest.Headers.Select(i => string.Format("{0}:{1}", i.Key, i.Value)).Aggregate((i, j) => i + "," + j))); HttpClient client = GetClient(request); // Not disposing the reponse since it will affect stream response var response = await client.SendAsync(httpRequest, completionOption).ConfigureAwait(false); //need to wait for Retry-After seconds and then retry request var retryAfterHeader = response.Headers.RetryAfter; // If we get a 429 error code and this is not a multi part request (meaning a file upload, which cannot be retried // because the stream cannot be reset) and we haven't exceeded the number of allowed retries, then retry the request. // If we get a 202 code and has a retry-after header, we will retry after if ( ((response.StatusCode == TooManyRequests && !isMultiPartRequest) || (response.StatusCode == HttpStatusCode.Accepted && retryAfterHeader != null)) && numRetries-- > 0) { TimeSpan delay = TimeSpan.FromSeconds(2); if (retryAfterHeader.Delta.HasValue) { delay = retryAfterHeader.Delta.Value; } Debug.WriteLine("HttpCode : {0}. Waiting for {1} seconds to retry request. RequestUri: {2}", response.StatusCode, delay.Seconds, httpRequest.RequestUri); await CrossPlatform.Delay(delay); } else { BoxResponse <T> boxResponse = new BoxResponse <T>(); boxResponse.Headers = response.Headers; // Translate the status codes that interest us boxResponse.StatusCode = response.StatusCode; switch (response.StatusCode) { case HttpStatusCode.OK: case HttpStatusCode.Created: case HttpStatusCode.NoContent: case HttpStatusCode.Found: boxResponse.Status = ResponseStatus.Success; break; case HttpStatusCode.Accepted: boxResponse.Status = ResponseStatus.Pending; break; case HttpStatusCode.Unauthorized: boxResponse.Status = ResponseStatus.Unauthorized; break; case HttpStatusCode.Forbidden: boxResponse.Status = ResponseStatus.Forbidden; break; case TooManyRequests: boxResponse.Status = ResponseStatus.TooManyRequests; break; default: boxResponse.Status = ResponseStatus.Error; break; } if (isStream && boxResponse.Status == ResponseStatus.Success) { var resObj = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); boxResponse.ResponseObject = resObj as T; } else { boxResponse.ContentString = await response.Content.ReadAsStringAsync().ConfigureAwait(false); } return(boxResponse); } } } catch (Exception ex) { Debug.WriteLine(string.Format("Exception: {0}", ex.Message)); throw; } }
public async Task <IBoxResponse <T> > ExecuteAsync <T>(IBoxRequest request) where T : class { // Need to account for special cases when the return type is a stream bool isStream = typeof(T) == typeof(Stream); var numRetries = 3; try { while (true) { HttpRequestMessage httpRequest = request.GetType() == typeof(BoxMultiPartRequest) ? BuildMultiPartRequest(request as BoxMultiPartRequest) : BuildRequest(request); // Add headers foreach (var kvp in request.HttpHeaders) { if (kvp.Key == Constants.RequestParameters.ContentMD5) { httpRequest.Content.Headers.Add(kvp.Key, kvp.Value); } else { httpRequest.Headers.TryAddWithoutValidation(kvp.Key, kvp.Value); } } // If we are retrieving a stream, we should return without reading the entire response HttpCompletionOption completionOption = isStream ? HttpCompletionOption.ResponseHeadersRead : HttpCompletionOption.ResponseContentRead; Debug.WriteLine(string.Format("RequestUri: {0}", httpRequest.RequestUri));//, RequestHeader: {1} , httpRequest.Headers.Select(i => string.Format("{0}:{1}", i.Key, i.Value)).Aggregate((i, j) => i + "," + j))); HttpClient client = CreateClient(request); BoxResponse <T> boxResponse = new BoxResponse <T>(); HttpResponseMessage response = await client.SendAsync(httpRequest, completionOption).ConfigureAwait(false); if (response.StatusCode == TooManyRequests && numRetries-- > 0) { //need to wait for Retry-After seconds and then retry request var retryAfterHeader = response.Headers.RetryAfter; TimeSpan delay; if (retryAfterHeader.Delta.HasValue) { delay = retryAfterHeader.Delta.Value; } else { delay = TimeSpan.FromMilliseconds(2000); } Debug.WriteLine("TooManyRequests error (429). Waiting for {0} seconds to retry request. RequestUri: {1}", delay.Seconds, httpRequest.RequestUri); await CrossPlatform.Delay(Convert.ToInt32(delay.TotalMilliseconds)); } else { boxResponse.Headers = response.Headers; // Translate the status codes that interest us boxResponse.StatusCode = response.StatusCode; switch (response.StatusCode) { case HttpStatusCode.OK: case HttpStatusCode.Created: case HttpStatusCode.NoContent: case HttpStatusCode.Found: boxResponse.Status = ResponseStatus.Success; break; case HttpStatusCode.Accepted: boxResponse.Status = ResponseStatus.Pending; break; case HttpStatusCode.Unauthorized: boxResponse.Status = ResponseStatus.Unauthorized; break; case HttpStatusCode.Forbidden: boxResponse.Status = ResponseStatus.Forbidden; break; case TooManyRequests: boxResponse.Status = ResponseStatus.TooManyRequests; break; default: boxResponse.Status = ResponseStatus.Error; break; } if (isStream && boxResponse.Status == ResponseStatus.Success) { var resObj = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); boxResponse.ResponseObject = resObj as T; } else { boxResponse.ContentString = await response.Content.ReadAsStringAsync().ConfigureAwait(false); } return(boxResponse); } } } catch (Exception ex) { Debug.WriteLine(string.Format("Exception: {0}", ex.Message)); throw; } }