public virtual TResponse Request <TResponse>(RequestData requestData) where TResponse : class, ITransportResponse, new() { int?statusCode = null; IEnumerable <string> warnings = null; Stream responseStream = null; Exception ex = null; string mimeType = null; ReadOnlyDictionary <TcpState, int> tcpStats = null; ReadOnlyDictionary <string, ThreadPoolStatistics> threadPoolStats = null; try { var request = CreateHttpWebRequest(requestData); var data = requestData.PostData; if (data != null) { using (var stream = request.GetRequestStream()) { if (requestData.HttpCompression) { using (var zipStream = new GZipStream(stream, CompressionMode.Compress)) data.Write(zipStream, requestData.ConnectionSettings); } else { data.Write(stream, requestData.ConnectionSettings); } } } requestData.MadeItToResponse = true; if (requestData.TcpStats) { tcpStats = TcpStats.GetStates(); } if (requestData.ThreadPoolStats) { threadPoolStats = ThreadPoolStats.GetStats(); } //http://msdn.microsoft.com/en-us/library/system.net.httpwebresponse.getresponsestream.aspx //Either the stream or the response object needs to be closed but not both although it won't //throw any errors if both are closed atleast one of them has to be Closed. //Since we expose the stream we let closing the stream determining when to close the connection var httpWebResponse = (HttpWebResponse)request.GetResponse(); HandleResponse(httpWebResponse, out statusCode, out responseStream, out mimeType); //response.Headers.HasKeys() can return false even if response.Headers.AllKeys has values. if (httpWebResponse.SupportsHeaders && httpWebResponse.Headers.Count > 0 && httpWebResponse.Headers.AllKeys.Contains("Warning")) { warnings = httpWebResponse.Headers.GetValues("Warning"); } } catch (WebException e) { ex = e; if (e.Response is HttpWebResponse httpWebResponse) { HandleResponse(httpWebResponse, out statusCode, out responseStream, out mimeType); } } responseStream ??= Stream.Null; var response = ResponseBuilder.ToResponse <TResponse>(requestData, ex, statusCode, warnings, responseStream, mimeType); // set TCP and threadpool stats on the response here so that in the event the request fails after the point of // gathering stats, they are still exposed on the call details. Ideally these would be set inside ResponseBuilder.ToResponse, // but doing so would be a breaking change in 7.x response.ApiCall.TcpStats = tcpStats; response.ApiCall.ThreadPoolStats = threadPoolStats; return(response); }
public virtual async Task <TResponse> RequestAsync <TResponse>(RequestData requestData, CancellationToken cancellationToken ) where TResponse : class, ITransportResponse, new() { Action unregisterWaitHandle = null; int? statusCode = null; IEnumerable <string> warnings = null; Stream responseStream = null; Exception ex = null; string mimeType = null; ReadOnlyDictionary <TcpState, int> tcpStats = null; ReadOnlyDictionary <string, ThreadPoolStatistics> threadPoolStats = null; try { var data = requestData.PostData; var request = CreateHttpWebRequest(requestData); using (cancellationToken.Register(() => request.Abort())) { if (data != null) { var apmGetRequestStreamTask = Task.Factory.FromAsync(request.BeginGetRequestStream, r => request.EndGetRequestStream(r), null); unregisterWaitHandle = RegisterApmTaskTimeout(apmGetRequestStreamTask, request, requestData); using (var stream = await apmGetRequestStreamTask.ConfigureAwait(false)) { if (requestData.HttpCompression) { using (var zipStream = new GZipStream(stream, CompressionMode.Compress)) await data.WriteAsync(zipStream, requestData.ConnectionSettings, cancellationToken).ConfigureAwait(false); } else { await data.WriteAsync(stream, requestData.ConnectionSettings, cancellationToken).ConfigureAwait(false); } } unregisterWaitHandle?.Invoke(); } requestData.MadeItToResponse = true; //http://msdn.microsoft.com/en-us/library/system.net.httpwebresponse.getresponsestream.aspx //Either the stream or the response object needs to be closed but not both although it won't //throw any errors if both are closed atleast one of them has to be Closed. //Since we expose the stream we let closing the stream determining when to close the connection var apmGetResponseTask = Task.Factory.FromAsync(request.BeginGetResponse, r => request.EndGetResponse(r), null); unregisterWaitHandle = RegisterApmTaskTimeout(apmGetResponseTask, request, requestData); if (requestData.TcpStats) { tcpStats = TcpStats.GetStates(); } if (requestData.ThreadPoolStats) { threadPoolStats = ThreadPoolStats.GetStats(); } var httpWebResponse = (HttpWebResponse)await apmGetResponseTask.ConfigureAwait(false); HandleResponse(httpWebResponse, out statusCode, out responseStream, out mimeType); if (httpWebResponse.SupportsHeaders && httpWebResponse.Headers.HasKeys() && httpWebResponse.Headers.AllKeys.Contains("Warning")) { warnings = httpWebResponse.Headers.GetValues("Warning"); } } } catch (WebException e) { ex = e; if (e.Response is HttpWebResponse httpWebResponse) { HandleResponse(httpWebResponse, out statusCode, out responseStream, out mimeType); } } finally { unregisterWaitHandle?.Invoke(); } responseStream ??= Stream.Null; var response = await ResponseBuilder.ToResponseAsync <TResponse> (requestData, ex, statusCode, warnings, responseStream, mimeType, cancellationToken) .ConfigureAwait(false); // set TCP and threadpool stats on the response here so that in the event the request fails after the point of // gathering stats, they are still exposed on the call details. Ideally these would be set inside ResponseBuilder.ToResponse, // but doing so would be a breaking change in 7.x response.ApiCall.TcpStats = tcpStats; response.ApiCall.ThreadPoolStats = threadPoolStats; return(response); }