/// <summary> /// Ends executing an asynchronous request. /// </summary> private void InternalEndExecuteRequest(IAsyncResult asyncResult) { AsyncExecutionState state = (AsyncExecutionState)asyncResult.AsyncState; AsyncRequestResult asyncRequestResult = null; bool retried = false; try { asyncRequestResult = new AsyncRequestResult(new Response( state.CurrentRequest.EndGetResponse(asyncResult))); } catch (WebException ex) { // Returns null if the attempt was retried. retried = HandleFailedRequest(state, ex, out asyncRequestResult); } catch (Exception ex) // Unknown exception. { asyncRequestResult = new AsyncRequestResult( new GoogleApiRequestException(Service, this, null, ex)); } finally { // If the async result is null, this indicates that the request was retried. // Another handler will be executed to respond to that attempt, so do not // call the handler yet. if (!retried) { state.ResponseHandler(asyncRequestResult); } } }
private static void _completeGetRequestStream <TResponse>(IAsyncResult ar) { AsyncExecutionState <TResponse> r = (AsyncExecutionState <TResponse>)ar.AsyncState; System.IO.Stream reqstr; try { reqstr = r.request.EndGetRequestStream(ar); } catch (WebException wex) { r.handleWebException(wex); r.completedWithError(wex); r.clear(); r = null; reqstr = null; return; } catch (Exception ex) { r.handleException(ex); r.completedWithError(ex); r.clear(); r = null; reqstr = null; return; } try { using (reqstr) reqstr.Write(r.bodyBytes, 0, r.bodyBytes.Length); } catch (WebException wex) { r.handleWebException(wex); r.completedWithError(wex); r.clear(); r = null; reqstr = null; return; } catch (Exception ex) { r.handleException(ex); r.completedWithError(ex); r.clear(); r = null; reqstr = null; return; } // Start an async operation to get the response: r.request.BeginGetResponse(_completeGetResponse <TResponse>, r); }
private static void _completeGetResponse <TResponse>(IAsyncResult ar) { AsyncExecutionState <TResponse> r = (AsyncExecutionState <TResponse>)ar.AsyncState; HttpWebResponse rsp; try { rsp = (HttpWebResponse)r.request.EndGetResponse(ar); } catch (WebException wex) { r.handleWebException(wex); r.completedWithError(wex); r.clear(); r = null; return; } catch (Exception ex) { r.handleException(ex); r.completedWithError(ex); r.clear(); r = null; return; } try { using (var rs = rsp.GetResponseStream()) { Debug.Assert(r.deserializeBody != null); var result = (TResponse)r.deserializeBody(rs, typeof(TResponse)); r.handleResponse(result); } } catch (WebException wex) { r.handleWebException(wex); r.completedWithError(wex); r.clear(); } catch (Exception ex) { r.handleException(ex); r.completedWithError(ex); r.clear(); } finally { rsp.Close(); r.clear(); } }
/// <summary> /// Fetches the request asynchronously and calls one of the appropriate handlers when completed (likely on a separate thread). /// </summary> /// <typeparam name="TResponse">The type to deserialize the response object to</typeparam> /// <param name="handleWebException">Called if a WebException is generated</param> /// <param name="handleGenericException">Called if an Exception is generated</param> /// <param name="completedWithError">Called when either error handler completes</param> /// <param name="handleResponse">Called to handle the successful response with the deserialized response object</param> public void FetchAsync <TResponse>( Action <WebException> handleWebException, Action <Exception> handleGenericException, Action <Exception> completedWithError, Action <TResponse> handleResponse) { if (handleResponse == null) { throw new ArgumentNullException("handleResponse"); } var _handleWebException = handleWebException ?? _defaultHandleWebException; var _handleException = handleGenericException ?? _defaultHandleException; var _completedWithError = completedWithError ?? _defaultDoNothing; try { _bodyBytes = serializeBody(); _auth.Authenticate(_request, _bodyBytes); _auth = null; var _handleResponse = handleResponse; var ast = new AsyncExecutionState <TResponse>(_bodyBytes, _request, _handleWebException, _handleException, _completedWithError, _deserializeBody, _handleResponse); if (_bodyBytes != null) { // Send the body: _request.BeginGetRequestStream(_completeGetRequestStream <TResponse>, ast); } else { _request.BeginGetResponse(_completeGetResponse <TResponse>, ast); } } catch (WebException wex) { _handleWebException(wex); _completedWithError(wex); } catch (Exception ex) { _handleException(ex); _completedWithError(ex); } }
/// <summary> /// Executes the request asynchronously, and calls the specified delegate once done. /// </summary> /// <param name="responseHandler">The method to call once a response has been received.</param> public void ExecuteRequestAsync(Action <IAsyncRequestResult> responseHandler) { // Validate the input. var validator = new MethodValidator(Method, Parameters); if (validator.ValidateAllParameters() == false) { throw new InvalidOperationException("Request parameter validation failed for [" + this + "]"); } // Begin a new request and when it is completed being assembled, execute it asynchronously. CreateWebRequest((request) => { // When the request is completed constructing, execute it. var state = new AsyncExecutionState() { ResponseHandler = responseHandler, Try = 1, WaitTime = RetryInitialWaitTime, CurrentRequest = request }; InternalBeginExecuteRequest(state); }); }
/// <summary> /// Begins executing a request based upon the current execution state. /// </summary> /// <remarks>Does not check preconditions.</remarks> private void InternalBeginExecuteRequest(AsyncExecutionState state) { state.CurrentRequest.BeginGetResponse(InternalEndExecuteRequest, state); }
/// <summary> /// Handles a failed request, and tries to fix it if possible. /// </summary> /// <remarks> /// Can not throw an exception. /// </remarks> /// <returns> /// Returns true if the request was handled and is being retried. /// Returns false if the request could not be retried. /// </returns> private bool HandleFailedRequest(AsyncExecutionState state, WebException exception, out AsyncRequestResult asyncRequestResult) { try { RequestError error = null; // Try to get an error response object. if (exception.Response != null) { IResponse errorResponse = new Response(exception.Response); error = Service.DeserializeError(errorResponse); } // Try to handle the response somehow. if (SupportsRetry && state.Try < MaximumRetries) { // Wait some time before sending another request. Thread.Sleep((int)state.WaitTime); state.WaitTime *= RetryWaitTimeIncreaseFactor; state.Try++; foreach (IErrorResponseHandler handler in GetErrorResponseHandlers()) { if (handler.CanHandleErrorResponse(exception, error)) { state.CurrentRequest = CreateWebRequest(); // The provided handler was able to handle this error. Retry sending the request. handler.HandleErrorResponse(exception, error, state.CurrentRequest); logger.Warning("Retrying request [{0}]", this); InternalBeginExecuteRequest(state); // Signal that this begin/end request pair has no result because it has been retried. asyncRequestResult = null; return true; } } } // Retrieve additional information about the http response (if applicable). HttpStatusCode status = 0; HttpWebResponse httpResponse = exception.Response as HttpWebResponse; if (httpResponse != null) { status = httpResponse.StatusCode; } // We were unable to handle the exception. Throw it wrapped in a GoogleApiRequestException. asyncRequestResult = new AsyncRequestResult( new GoogleApiRequestException(Service, this, error, exception) { HttpStatusCode = status }); } catch (Exception ex) { asyncRequestResult = new AsyncRequestResult( new GoogleApiRequestException(Service, this, null, ex)); } return false; }
/// <summary> /// Handles a failed request, and tries to fix it if possible. /// </summary> /// <remarks> /// Can not throw an exception. /// </remarks> /// <returns> /// Returns true if the request was handled and is being retried. /// Returns false if the request could not be retried. /// </returns> private bool HandleFailedRequest(AsyncExecutionState state, WebException exception, out AsyncRequestResult asyncRequestResult) { try { RequestError error = null; // Try to get an error response object. if (exception.Response != null) { IResponse errorResponse = new Response(exception.Response); error = Service.DeserializeError(errorResponse); } // Try to handle the response somehow. if (SupportsRetry && state.Try < MaximumRetries) { // Wait some time before sending another request. Thread.Sleep((int)state.WaitTime); state.WaitTime *= RetryWaitTimeIncreaseFactor; state.Try++; foreach (IErrorResponseHandler handler in GetErrorResponseHandlers()) { if (handler.CanHandleErrorResponse(exception, error)) { // The provided handler was able to handle this error. Retry sending the request. handler.HandleErrorResponse(exception, error, state.CurrentRequest); logger.Warning("Retrying request [{0}]", this); // Begin a new request and when it is completed being assembled, execute it // asynchronously. state.CurrentRequest = CreateWebRequest((request) => { InternalBeginExecuteRequest(state); }); // Signal that this begin/end request pair has no result because it has been retried. asyncRequestResult = null; return(true); } } } // Retrieve additional information about the http response (if applicable). HttpStatusCode status = 0; HttpWebResponse httpResponse = exception.Response as HttpWebResponse; if (httpResponse != null) { status = httpResponse.StatusCode; } // We were unable to handle the exception. Throw it wrapped in a GoogleApiRequestException. asyncRequestResult = new AsyncRequestResult( new GoogleApiRequestException(Service, this, error, exception) { HttpStatusCode = status }); } catch (Exception) { asyncRequestResult = new AsyncRequestResult( new GoogleApiRequestException(Service, this, null, exception)); } return(false); }
/// <summary> /// Executes the request asynchronously, and calls the specified delegate once done. /// </summary> /// <param name="responseHandler">The method to call once a response has been received.</param> public void ExecuteRequestAsync(Action<IAsyncRequestResult> responseHandler) { // Validate the input. var validator = new MethodValidator(Method, Parameters); if (validator.ValidateAllParameters() == false) { throw new InvalidOperationException("Request parameter validation failed for [" + this + "]"); } // Begin a new request and when it is completed being assembled, execute it asynchronously. CreateWebRequest((request) => { // When the request is completed constructing, execute it. var state = new AsyncExecutionState() { ResponseHandler = responseHandler, Try = 1, WaitTime = RetryInitialWaitTime, CurrentRequest = request }; InternalBeginExecuteRequest(state); }); }