/// <summary> /// Called by Send method if an exception occurs, for instance a System.Net.WebException because the server /// returned an HTTP error code. Override if you want to handle specific exceptions or always want to parse the /// response to a custom ErrorResponse DTO type instead of ServiceStack's ErrorResponse class. In case ex is a /// <c>System.Net.WebException</c>, do not use /// <c>createWebRequest</c>/<c>getResponse</c>/<c>HandleResponse<TResponse></c> to parse the response /// because that will result in the same exception again. Use /// <c>ThrowWebServiceException<YourErrorResponseType></c> to parse the response and to throw a /// <c>WebServiceException</c> containing the parsed DTO. Then override Send to handle that exception. /// </summary> protected virtual bool HandleResponseException <TResponse>(Exception ex, object request, string requestUri, Func <WebRequest> createWebRequest, Func <WebRequest, WebResponse> getResponse, out TResponse response) { try { if (WebRequestUtils.ShouldAuthenticate(ex, this.UserName, this.Password)) { // adamfowleruk : Check response object to see what type of auth header to add var client = createWebRequest(); var webEx = ex as WebException; if (webEx != null && webEx.Response != null) { WebHeaderCollection headers = ((HttpWebResponse)webEx.Response).Headers; var doAuthHeader = headers[HttpHeaders.WwwAuthenticate]; // check value of WWW-Authenticate header if (doAuthHeader == null) { client.AddBasicAuth(this.UserName, this.Password); } else { this.authInfo = new AuthenticationInfo(doAuthHeader); client.AddAuthInfo(this.UserName, this.Password, authInfo); } } if (OnAuthenticationRequired != null) { OnAuthenticationRequired(client); } var webResponse = getResponse(client); response = HandleResponse <TResponse>(webResponse); return(true); } } catch (Exception subEx) { // Since we are effectively re-executing the call, // the new exception should be shown to the caller rather // than the old one. // The new exception is either this one or the one thrown // by the following method. ThrowResponseTypeException <TResponse>(request, subEx, requestUri); throw; } // If this doesn't throw, the calling method // should rethrow the original exception upon // return value of false. ThrowResponseTypeException <TResponse>(request, ex, requestUri); response = default(TResponse); return(false); }
private void ResponseCallback <T>(IAsyncResult asyncResult) { var requestState = (AsyncState <T>)asyncResult.AsyncState; try { var webRequest = requestState.WebRequest; requestState.WebResponse = (HttpWebResponse)webRequest.EndGetResponse(asyncResult); if (requestState.OnResponseInit != null) { requestState.OnResponseInit(requestState.WebResponse); } if (requestState.ResponseContentLength == default(long)) { requestState.ResponseContentLength = requestState.WebResponse.ContentLength; } ApplyWebResponseFilters(requestState.WebResponse); if (typeof(T) == typeof(HttpWebResponse)) { requestState.HandleSuccess((T)(object)requestState.WebResponse); return; } // Read the response into a Stream object. var responseStream = requestState.WebResponse.GetResponseStream(); requestState.ResponseStream = responseStream; var task = responseStream.ReadAsync(requestState.BufferRead, 0, BufferSize); ReadCallBack(task, requestState); } catch (Exception ex) { var webEx = ex as WebException; var firstCall = Interlocked.Increment(ref requestState.RequestCount) == 1; if (firstCall && WebRequestUtils.ShouldAuthenticate(webEx, this.UserName, this.Password)) { try { requestState.WebRequest = (HttpWebRequest)WebRequest.Create(requestState.Url); if (StoreCookies) { requestState.WebRequest.CookieContainer = CookieContainer; } HandleAuthException(ex, requestState.WebRequest); if (OnAuthenticationRequired != null) { OnAuthenticationRequired(requestState.WebRequest); } SendWebRequestAsync( requestState.HttpMethod, requestState.Request, requestState, requestState.WebRequest); } catch (Exception /*subEx*/) { HandleResponseError(ex, requestState); } return; } if (ExceptionFilter != null && webEx != null && webEx.Response != null) { var cachedResponse = ExceptionFilter(webEx, webEx.Response, requestState.Url, typeof(T)); if (cachedResponse is T) { requestState.OnSuccess((T)cachedResponse); return; } } HandleResponseError(ex, requestState); } }
private async Task <T> SendWebRequestAsync <T>(string httpMethod, string absoluteUrl, object request, CancellationToken token, bool recall = false) { if (httpMethod == null) { throw new ArgumentNullException(nameof(httpMethod)); } this.PopulateRequestMetadata(request); var requestUri = absoluteUrl; var hasQueryString = request != null && !HttpUtils.HasRequestBody(httpMethod); if (hasQueryString) { var queryString = QueryStringSerializer.SerializeToString(request); if (!string.IsNullOrEmpty(queryString)) { requestUri += "?" + queryString; } } var webReq = this.CreateHttpWebRequest(requestUri); if (webReq != null && Proxy != null) { webReq.Proxy = Proxy; } var timedOut = false; ITimer timer = null; timer = PclExportClient.Instance.CreateTimer(state => { timedOut = true; webReq?.Abort(); webReq = null; timer?.Cancel(); timer = null; }, this.Timeout.GetValueOrDefault(DefaultTimeout), this); Exception ResolveException(Exception ex) { if (token.IsCancellationRequested) { return(new OperationCanceledException(token)); } if (timedOut) { return(PclExportClient.Instance.CreateTimeoutException(ex, "The request timed out")); } return(ex); } bool returningWebResponse = false; HttpWebResponse webRes = null; T Complete(T response) { timer.Cancel(); PclExportClient.Instance.SynchronizeCookies(this); ResultsFilterResponse?.Invoke(webRes, response, httpMethod, absoluteUrl, request); return(response); } webReq.Accept = ContentType; if (this.EmulateHttpViaPost) { webReq.Method = "POST"; webReq.Headers[HttpHeaders.XHttpMethodOverride] = httpMethod; } else { webReq.Method = httpMethod; } PclExportClient.Instance.AddHeader(webReq, Headers); PclExport.Instance.Config(webReq, userAgent: UserAgent); if (this.authInfo != null && !string.IsNullOrEmpty(this.UserName)) { webReq.AddAuthInfo(this.UserName, this.Password, authInfo); } else if (this.BearerToken != null) { webReq.Headers[HttpHeaders.Authorization] = "Bearer " + this.BearerToken; } else if (this.Credentials != null) { webReq.Credentials = this.Credentials; } else if (this.AlwaysSendBasicAuthHeader) { webReq.AddBasicAuth(this.UserName, this.Password); } if (!DisableAutoCompression) { PclExport.Instance.AddCompression(webReq); } ApplyWebRequestFilters(webReq); try { if (HttpUtils.HasRequestBody(webReq.Method)) { webReq.ContentType = ContentType; if (RequestCompressionType != null) { webReq.Headers[HttpHeaders.ContentEncoding] = RequestCompressionType; } using var requestStream = await webReq.GetRequestStreamAsync().ConfigAwait(); token.ThrowIfCancellationRequested(); if (request != null) { StreamSerializer(null, request, requestStream); } } } catch (Exception ex) { if (Log.IsDebugEnabled) { Log.Debug($"Error Sending Request: {ex.Message}", ex); } throw HandleResponseError <T>(ResolveException(ex), requestUri, request); } try { webRes = (HttpWebResponse)await webReq.GetResponseAsync().ConfigAwait(); { token.ThrowIfCancellationRequested(); ApplyWebResponseFilters(webRes); returningWebResponse = typeof(T) == typeof(HttpWebResponse); if (returningWebResponse) { return(Complete((T)(object)webRes)); } var responseStream = webRes.ResponseStream(); var responseBodyLength = webRes.ContentLength; var bufferRead = new byte[BufferSize]; var totalRead = 0; int read; var ms = MemoryStreamFactory.GetStream(); while ((read = await responseStream.ReadAsync(bufferRead, 0, bufferRead.Length, token).ConfigAwait()) != 0) { await ms.WriteAsync(bufferRead, 0, read, token).ConfigAwait(); totalRead += read; OnDownloadProgress?.Invoke(totalRead, responseBodyLength); } try { ms.Position = 0; if (typeof(T) == typeof(Stream)) { return(Complete((T)(object)ms)); } else { var stream = ms; try { if (typeof(T) == typeof(string)) { return(Complete((T)(object)await stream.ReadToEndAsync().ConfigAwait())); } else if (typeof(T) == typeof(byte[])) { return(Complete((T)(object)stream.ToArray())); } else { return(Complete((T)this.StreamDeserializer(typeof(T), stream))); } } finally { if (stream.CanRead) { stream.Dispose(); // Not yet disposed, but could've been. } } } } catch (Exception ex) { if (Log.IsDebugEnabled) { Log.Debug($"Error Reading Response Error: {ex.Message}", ex); } throw; } finally { responseStream.Close(); } } } catch (Exception ex) { var webEx = ex as WebException; var firstCall = !recall; var hasRefreshTokenCookie = this.CookieContainer.GetRefreshTokenCookie(BaseUri) != null; var hasRefreshToken = RefreshToken != null || hasRefreshTokenCookie; if (firstCall && WebRequestUtils.ShouldAuthenticate(webEx, (!string.IsNullOrEmpty(UserName) && !string.IsNullOrEmpty(Password)) || Credentials != null || BearerToken != null || hasRefreshToken || OnAuthenticationRequired != null)) { try { if (hasRefreshToken) { var refreshRequest = new GetAccessToken { RefreshToken = RefreshToken, UseTokenCookie = UseTokenCookie, }; var uri = this.RefreshTokenUri ?? this.BaseUri.CombineWith(refreshRequest.ToPostUrl()); GetAccessTokenResponse tokenResponse; try { tokenResponse = (await uri.PostJsonToUrlAsync(refreshRequest, requestFilter: req => { if (UseTokenCookie || hasRefreshTokenCookie) { req.CookieContainer = CookieContainer; } }, token: token).ConfigAwait()).FromJson <GetAccessTokenResponse>(); } catch (WebException refreshEx) { var webServiceEx = ServiceClientBase.ToWebServiceException(refreshEx, stream => StreamDeserializer(typeof(T), stream), ContentType); if (webServiceEx != null) { throw new RefreshTokenException(webServiceEx); } throw new RefreshTokenException(refreshEx.Message, refreshEx); } var accessToken = tokenResponse?.AccessToken; var refreshClient = webReq = (HttpWebRequest)WebRequest.Create(requestUri); var tokenCookie = this.CookieContainer.GetTokenCookie(BaseUri); if (UseTokenCookie) { if (tokenCookie == null) { throw new RefreshTokenException("Could not retrieve new AccessToken Cooke from: " + uri); } refreshClient.CookieContainer.SetTokenCookie(BaseUri, tokenCookie); } else { if (string.IsNullOrEmpty(accessToken)) { throw new RefreshTokenException("Could not retrieve new AccessToken from: " + uri); } if (tokenCookie != null) { this.CookieContainer.SetTokenCookie(accessToken, BaseUri); refreshClient.CookieContainer.SetTokenCookie(BaseUri, accessToken); } else { refreshClient.AddBearerToken(this.BearerToken = accessToken); } } return(await SendWebRequestAsync <T>(httpMethod, absoluteUrl, request, token, recall : true).ConfigAwait()); } OnAuthenticationRequired?.Invoke(); var newReq = (HttpWebRequest)WebRequest.Create(requestUri); if (StoreCookies) { newReq.CookieContainer = CookieContainer; } HandleAuthException(ex, webReq); return(await SendWebRequestAsync <T>(httpMethod, absoluteUrl, request, token, recall : true).ConfigAwait()); } catch (WebServiceException) { throw; } catch (Exception /*subEx*/) { throw HandleResponseError <T>(ResolveException(ex), requestUri, request); } } if (ExceptionFilter != null && webEx?.Response != null) { var cachedResponse = ExceptionFilter(webEx, webEx.Response, requestUri, typeof(T)); if (cachedResponse is T variable) { return(variable); } } throw HandleResponseError <T>(ResolveException(ex), requestUri, request); } finally { if (!returningWebResponse) { webRes?.Dispose(); } } }
private void ResponseCallback <T>(IAsyncResult asyncResult) { var requestState = (AsyncState <T>)asyncResult.AsyncState; try { requestState.Token.ThrowIfCancellationRequested(); var webRequest = requestState.WebRequest; requestState.WebResponse = (HttpWebResponse)webRequest.EndGetResponse(asyncResult); requestState.OnResponseInit?.Invoke(requestState.WebResponse); if (requestState.ResponseContentLength == default(long)) { requestState.ResponseContentLength = requestState.WebResponse.ContentLength; } ApplyWebResponseFilters(requestState.WebResponse); if (typeof(T) == typeof(HttpWebResponse)) { requestState.HandleSuccess((T)(object)requestState.WebResponse); return; } // Read the response into a Stream object. #if NETSTANDARD1_1 || NETSTANDARD1_6 var responseStream = requestState.WebResponse.GetResponseStream() .Decompress(requestState.WebResponse.Headers[HttpHeaders.ContentEncoding]); #else var responseStream = requestState.WebResponse.GetResponseStream(); #endif requestState.ResponseStream = responseStream; var task = responseStream.ReadAsync(requestState.BufferRead, 0, BufferSize); ReadCallBack(task, requestState); } catch (Exception ex) { var webEx = ex as WebException; var firstCall = Interlocked.Increment(ref requestState.RequestCount) == 1; if (firstCall && WebRequestUtils.ShouldAuthenticate(webEx, (!string.IsNullOrEmpty(UserName) && !string.IsNullOrEmpty(Password)) || Credentials != null || BearerToken != null || RefreshToken != null || OnAuthenticationRequired != null)) { try { if (RefreshToken != null) { var refreshRequest = new GetAccessToken { RefreshToken = RefreshToken }; var uri = this.RefreshTokenUri ?? this.BaseUri.CombineWith(refreshRequest.ToPostUrl()); var tokenResponse = uri.PostJsonToUrl(refreshRequest).FromJson <GetAccessTokenResponse>(); var accessToken = tokenResponse?.AccessToken; if (string.IsNullOrEmpty(accessToken)) { throw new Exception("Could not retrieve new AccessToken from: " + uri); } var refreshClient = requestState.WebRequest = (HttpWebRequest)WebRequest.Create(requestState.Url); if (this.CookieContainer.GetTokenCookie(BaseUri) != null) { this.CookieContainer.SetTokenCookie(accessToken, BaseUri); refreshClient.CookieContainer.SetTokenCookie(BaseUri, accessToken); } else { refreshClient.AddBearerToken(this.BearerToken = accessToken); } SendWebRequestAsync( requestState.HttpMethod, requestState.Request, requestState, requestState.WebRequest); return; } OnAuthenticationRequired?.Invoke(); requestState.WebRequest = (HttpWebRequest)WebRequest.Create(requestState.Url); if (StoreCookies) { requestState.WebRequest.CookieContainer = CookieContainer; } HandleAuthException(ex, requestState.WebRequest); SendWebRequestAsync( requestState.HttpMethod, requestState.Request, requestState, requestState.WebRequest); } catch (Exception /*subEx*/) { HandleResponseError(ex, requestState); } return; } if (ExceptionFilter != null && webEx != null && webEx.Response != null) { var cachedResponse = ExceptionFilter(webEx, webEx.Response, requestState.Url, typeof(T)); if (cachedResponse is T) { requestState.OnSuccess((T)cachedResponse); return; } } HandleResponseError(ex, requestState); } }
private void ResponseCallback <T>(IAsyncResult asyncResult) { var requestState = (AsyncState <T>)asyncResult.AsyncState; try { requestState.Token.ThrowIfCancellationRequested(); var webRequest = requestState.WebRequest; requestState.WebResponse = (HttpWebResponse)webRequest.EndGetResponse(asyncResult); requestState.OnResponseInit?.Invoke(requestState.WebResponse); if (requestState.ResponseContentLength == default(long)) { requestState.ResponseContentLength = requestState.WebResponse.ContentLength; } ApplyWebResponseFilters(requestState.WebResponse); if (typeof(T) == typeof(HttpWebResponse)) { requestState.HandleSuccess((T)(object)requestState.WebResponse); return; } // Read the response into a Stream object. #if NETSTANDARD1_1 || NETSTANDARD1_6 var responseStream = requestState.WebResponse.GetResponseStream() .Decompress(requestState.WebResponse.Headers[HttpHeaders.ContentEncoding]); #else var responseStream = requestState.WebResponse.GetResponseStream(); #endif requestState.ResponseStream = responseStream; var task = responseStream.ReadAsync(requestState.BufferRead, 0, BufferSize); ReadCallBack(task, requestState); } catch (Exception ex) { var webEx = ex as WebException; var firstCall = Interlocked.Increment(ref requestState.RequestCount) == 1; if (firstCall && WebRequestUtils.ShouldAuthenticate(webEx, (!string.IsNullOrEmpty(UserName) && !string.IsNullOrEmpty(Password)) || Credentials != null || BearerToken != null || OnAuthenticationRequired != null)) { try { OnAuthenticationRequired?.Invoke(); requestState.WebRequest = (HttpWebRequest)WebRequest.Create(requestState.Url); if (StoreCookies) { requestState.WebRequest.CookieContainer = CookieContainer; } HandleAuthException(ex, requestState.WebRequest); SendWebRequestAsync( requestState.HttpMethod, requestState.Request, requestState, requestState.WebRequest); } catch (Exception /*subEx*/) { HandleResponseError(ex, requestState); } return; } if (ExceptionFilter != null && webEx != null && webEx.Response != null) { var cachedResponse = ExceptionFilter(webEx, webEx.Response, requestState.Url, typeof(T)); if (cachedResponse is T) { requestState.OnSuccess((T)cachedResponse); return; } } HandleResponseError(ex, requestState); } }