/// <summary> /// This method makes the actual web request and marshalls the response body or error returned from the service. /// For some error response a retry will be attempted after an exponential pause. /// </summary> /// <typeparam name="X">The user facing request type.</typeparam> /// <typeparam name="Y">The user facing response type.</typeparam> /// <param name="request">The wrapper around the user facing request.</param> /// <param name="signer">The type of signer to use for the request.</param> /// <param name="unmarshaller">The object used to unmarshall the response body.</param> /// <returns>The response object for the request</returns> internal Y Invoke <X, Y>(IRequest <X> request, AbstractAWSSigner signer, IResponseUnmarshaller <Y, UnmarshallerContext> unmarshaller) { Type requestType = typeof(X); string requestName = requestType.Name; this.logger.DebugFormat("Starting request {0} at {1}", requestName, this.config.ServiceURL); request.Endpoint = new Uri(this.config.ServiceURL); signer.Sign(request, this.config, this.awsAccessKeyId, this.clearAwsSecretAccessKey, this.awsSecretAccessKey); string queryString = AWSSDKUtils.GetParametersAsString(request.Parameters); byte[] requestData = Encoding.UTF8.GetBytes(queryString); this.logger.DebugFormat("Request body's content [{0}] with size {1}", queryString, requestData.Length); int retries = 0; while (true) { retries++; try { HttpWebRequest webRequest = this.ConfigureWebRequest <X>(request, requestData); try { Y result; DateTime requestSent = DateTime.UtcNow; using (HttpWebResponse httpResponse = webRequest.GetResponse() as HttpWebResponse) { DateTime responseReceived = DateTime.UtcNow; this.logger.InfoFormat("Received response for {0} with status code {1} in {2} ms.", requestName, httpResponse.StatusCode, (responseReceived - requestSent).TotalMilliseconds); XmlTextReader reader = new XmlTextReader(new StreamReader(httpResponse.GetResponseStream())); UnmarshallerContext context = new UnmarshallerContext(reader); result = unmarshaller.Unmarshall(context); } return(result); } catch (WebException we) { processWebException <X, Y>(requestName, we, webRequest, unmarshaller, request, retries); } } catch (Exception e) { this.logger.Error(string.Format("Error configuring web request {0} to {1}.", requestName, request.Endpoint.ToString()), e); throw; } } }
private void processWebException <X, Y>(string requestName, WebException we, HttpWebRequest webRequest, IResponseUnmarshaller <Y, UnmarshallerContext> unmarshaller, IRequest <X> request, int retries) { HttpStatusCode statusCode; AmazonServiceException errorResponseException = null; using (HttpWebResponse httpErrorResponse = we.Response as HttpWebResponse) { if (httpErrorResponse == null) { // Abort the unsuccessful request webRequest.Abort(); // If it is a keep alive error then attempt a retry if (we != null && retries <= config.MaxErrorRetry && we.Status == WebExceptionStatus.KeepAliveFailure) { pauseExponentially(retries); return; } throw new AmazonServiceException(we); } statusCode = httpErrorResponse.StatusCode; XmlTextReader errorReader; #if NOSTREAM string responseBody = new StreamReader(httpErrorResponse.GetResponseStream()).ReadToEnd();; errorReader = new XmlTextReader(new StringReader(responseBody)); #else errorReader = new XmlTextReader(new StreamReader(httpErrorResponse.GetResponseStream())); #endif UnmarshallerContext errorContext = new UnmarshallerContext(errorReader); errorResponseException = unmarshaller.UnmarshallException(errorContext, we, statusCode); httpErrorResponse.Close(); webRequest.Abort(); if (isTemporaryRedirect(httpErrorResponse)) { string redirectedLocation = httpErrorResponse.Headers["location"]; this.logger.InfoFormat("Request {0} is being redirected to {1}.", requestName, redirectedLocation); request.Endpoint = new Uri(redirectedLocation); return; } else if (ShouldRetry(statusCode, this.config, errorResponseException, retries)) { this.logger.InfoFormat("Retry number {0} for request {1}.", retries, requestName); pauseExponentially(retries); return; } } if (errorResponseException != null) { this.logger.Error(string.Format("Error making request {0}.", requestName), errorResponseException); throw errorResponseException; } AmazonServiceException excep = new AmazonServiceException("Unable to make request", we, statusCode); this.logger.Error(string.Format("Error making request {0}.", requestName), excep); throw excep; }
/// <summary> /// This method makes the actual web request and marshalls the response body or error returned from the service. /// For some error response a retry will be attempted after an exponential pause. /// </summary> /// <typeparam name="X">The user facing request type.</typeparam> /// <typeparam name="Y">The user facing response type.</typeparam> /// <param name="request">The wrapper around the user facing request.</param> /// <param name="signer">The type of signer to use for the request.</param> /// <param name="unmarshaller">The object used to unmarshall the response body.</param> /// <returns>The response object for the request</returns> internal Y Invoke <X, Y>(IRequest <X> request, AbstractAWSSigner signer, IResponseUnmarshaller <Y, UnmarshallerContext> unmarshaller) where X : AmazonWebServiceRequest { Type requestType = typeof(X); string requestName = requestType.Name; request.Endpoint = new Uri(this.config.ServiceURL); request.Headers["User-Agent"] = this.config.UserAgent; request.Headers["Content-Type"] = AWSSDKUtils.UrlEncodedContent; ProcessRequestHandlers(request); this.logger.DebugFormat("Starting request {0} at {1}", requestName, this.config.ServiceURL); signer.Sign(request, this.config, this.awsAccessKeyId, this.clearAwsSecretAccessKey, this.awsSecretAccessKey); string queryString = AWSSDKUtils.GetParametersAsString(request.Parameters); byte[] requestData = Encoding.UTF8.GetBytes(queryString); this.logger.DebugFormat("Request body's content [{0}] with size {1}", queryString, requestData.Length); int retries = 0; while (true) { retries++; try { HttpWebRequest webRequest = this.ConfigureWebRequest <X>(request, requestData); try { Y result; DateTime requestSent = DateTime.UtcNow; using (HttpWebResponse httpResponse = webRequest.GetResponse() as HttpWebResponse) { DateTime responseReceived = DateTime.UtcNow; this.logger.InfoFormat("Received response for {0} with status code {1} in {2} ms.", requestName, httpResponse.StatusCode, (responseReceived - requestSent).TotalMilliseconds); XmlTextReader reader; // Using NOSTREAM is the less effcient way of dealing with the response body but it is helpful // for debug purposes to see the entire xml body coming back from the server. #if NOSTREAM string responseBody = new StreamReader(httpResponse.GetResponseStream()).ReadToEnd();; reader = new XmlTextReader(new StringReader(responseBody)); #else reader = new XmlTextReader(new StreamReader(httpResponse.GetResponseStream())); #endif UnmarshallerContext context = new UnmarshallerContext(reader); result = unmarshaller.Unmarshall(context); } return(result); } catch (WebException we) { processWebException <X, Y>(requestName, we, webRequest, unmarshaller, request, retries); } } catch (IOException e) { if (this.isInnerExceptionThreadAbort(e)) { throw; } this.logger.Error(string.Format("IOException making request {0} to {1}.", requestName, request.Endpoint.ToString()), e); if (retries > this.config.MaxErrorRetry) { throw; } else { this.logger.Error(string.Format("IOException making request {0} to {1}. Attempting retry {2}.", requestName, request.Endpoint.ToString(), retries), e); } } catch (Exception e) { this.logger.Error(string.Format("Error configuring web request {0} to {1}.", requestName, request.Endpoint.ToString()), e); throw; } } }