From 0bdc8a49d5ea17417b3552d6db21239190bc4b6b Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sat, 30 Nov 2013 01:07:25 -0500 Subject: [PATCH] switch from httpclient to plain httpwebrequest --- .../BaseApplicationHost.cs | 5 +- .../HttpClientManager/HttpClientInfo.cs | 6 - .../HttpClientManager/HttpClientManager.cs | 443 ++++++++++-------- MediaBrowser.Common/Net/IHttpClient.cs | 5 + .../ApplicationHost.cs | 10 - .../MediaBrowser.ServerApplication.csproj | 1 - .../Native/HttpClientFactory.cs | 35 -- 7 files changed, 263 insertions(+), 242 deletions(-) delete mode 100644 MediaBrowser.ServerApplication/Native/HttpClientFactory.cs diff --git a/MediaBrowser.Common.Implementations/BaseApplicationHost.cs b/MediaBrowser.Common.Implementations/BaseApplicationHost.cs index f1d8c94e55..becf649f44 100644 --- a/MediaBrowser.Common.Implementations/BaseApplicationHost.cs +++ b/MediaBrowser.Common.Implementations/BaseApplicationHost.cs @@ -22,7 +22,6 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; -using System.Net.Http; using System.Reflection; using System.Threading; using System.Threading.Tasks; @@ -353,7 +352,7 @@ namespace MediaBrowser.Common.Implementations FileSystemManager = CreateFileSystemManager(); RegisterSingleInstance(FileSystemManager); - HttpClient = new HttpClientManager.HttpClientManager(ApplicationPaths, Logger, CreateHttpClient, FileSystemManager); + HttpClient = new HttpClientManager.HttpClientManager(ApplicationPaths, Logger, FileSystemManager); RegisterSingleInstance(HttpClient); NetworkManager = CreateNetworkManager(); @@ -378,8 +377,6 @@ namespace MediaBrowser.Common.Implementations return new CommonFileSystem(Logger, true); } - protected abstract HttpClient CreateHttpClient(bool enableHttpCompression); - /// /// Gets a list of types within an assembly /// This will handle situations that would normally throw an exception - such as a type within the assembly that depends on some other non-existant reference diff --git a/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientInfo.cs b/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientInfo.cs index 33f7079df3..8af6ef6c6e 100644 --- a/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientInfo.cs +++ b/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientInfo.cs @@ -1,5 +1,4 @@ using System; -using System.Net.Http; namespace MediaBrowser.Common.Implementations.HttpClientManager { @@ -8,11 +7,6 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager /// public class HttpClientInfo { - /// - /// Gets or sets the HTTP client. - /// - /// The HTTP client. - public HttpClient HttpClient { get; set; } /// /// Gets or sets the last timeout. /// diff --git a/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs b/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs index 181c83fd3a..ea1a5c7266 100644 --- a/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs +++ b/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs @@ -1,5 +1,4 @@ -using System.Reflection; -using MediaBrowser.Common.Configuration; +using MediaBrowser.Common.Configuration; using MediaBrowser.Common.IO; using MediaBrowser.Common.Net; using MediaBrowser.Model.Logging; @@ -10,7 +9,10 @@ using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; +using System.Net; +using System.Net.Cache; using System.Net.Http; +using System.Reflection; using System.Text; using System.Threading; using System.Threading.Tasks; @@ -32,9 +34,6 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager /// private readonly IApplicationPaths _appPaths; - public delegate HttpClient GetHttpClientHandler(bool enableHttpCompression); - - private readonly GetHttpClientHandler _getHttpClientHandler; private readonly IFileSystem _fileSystem; /// @@ -48,7 +47,7 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager /// or /// logger /// - public HttpClientManager(IApplicationPaths appPaths, ILogger logger, GetHttpClientHandler getHttpClientHandler, IFileSystem fileSystem) + public HttpClientManager(IApplicationPaths appPaths, ILogger logger, IFileSystem fileSystem) { if (appPaths == null) { @@ -60,7 +59,6 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager } _logger = logger; - _getHttpClientHandler = getHttpClientHandler; _fileSystem = fileSystem; _appPaths = appPaths; } @@ -92,111 +90,59 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager if (!_httpClients.TryGetValue(key, out client)) { - client = new HttpClientInfo - { + client = new HttpClientInfo(); - HttpClient = _getHttpClientHandler(enableHttpCompression) - }; _httpClients.TryAdd(key, client); } return client; } - public async Task GetResponse(HttpRequestOptions options) - { - ValidateParams(options.Url, options.CancellationToken); - - options.CancellationToken.ThrowIfCancellationRequested(); + private PropertyInfo _httpBehaviorPropertyInfo; - var client = GetHttpClient(GetHostFromUrl(options.Url), options.EnableHttpCompression); + private HttpWebRequest GetRequest(HttpRequestOptions options, string method, bool enableHttpCompression) + { + var request = HttpWebRequest.CreateHttp(options.Url); - if ((DateTime.UtcNow - client.LastTimeout).TotalSeconds < 30) + if (!string.IsNullOrEmpty(options.AcceptHeader)) { - throw new HttpException(string.Format("Cancelling connection to {0} due to a previous timeout.", options.Url)) { IsTimedOut = true }; + request.Accept = options.AcceptHeader; } - using (var message = GetHttpRequestMessage(options)) - { - if (options.ResourcePool != null) - { - await options.ResourcePool.WaitAsync(options.CancellationToken).ConfigureAwait(false); - } - - if ((DateTime.UtcNow - client.LastTimeout).TotalSeconds < 30) - { - if (options.ResourcePool != null) - { - options.ResourcePool.Release(); - } - - throw new HttpException(string.Format("Connection to {0} timed out", options.Url)) { IsTimedOut = true }; - } - - _logger.Info("HttpClientManager.Get url: {0}", options.Url); - - try - { - options.CancellationToken.ThrowIfCancellationRequested(); - - var response = await client.HttpClient.SendAsync(message, HttpCompletionOption.ResponseContentRead, options.CancellationToken).ConfigureAwait(false); - - EnsureSuccessStatusCode(response); + request.AutomaticDecompression = enableHttpCompression ? DecompressionMethods.Deflate : DecompressionMethods.None; + request.CachePolicy = new RequestCachePolicy(RequestCacheLevel.Revalidate); + request.ConnectionGroupName = GetHostFromUrl(options.Url); + request.KeepAlive = true; + request.Method = method; + request.Pipelined = true; + request.Timeout = 20000; - options.CancellationToken.ThrowIfCancellationRequested(); - - return new HttpResponseInfo - { - Content = await response.Content.ReadAsStreamAsync().ConfigureAwait(false), - - StatusCode = response.StatusCode, - - ContentType = response.Content.Headers.ContentType.MediaType - }; - } - catch (OperationCanceledException ex) - { - var exception = GetCancellationException(options.Url, options.CancellationToken, ex); - - var httpException = exception as HttpException; + if (!string.IsNullOrEmpty(options.UserAgent)) + { + request.UserAgent = options.UserAgent; + } - if (httpException != null && httpException.IsTimedOut) - { - client.LastTimeout = DateTime.UtcNow; - } + var sp = request.ServicePoint; - throw exception; - } - catch (HttpRequestException ex) - { - _logger.ErrorException("Error getting response from " + options.Url, ex); + if (_httpBehaviorPropertyInfo == null) + { + _httpBehaviorPropertyInfo = sp.GetType().GetProperty("HttpBehaviour", BindingFlags.Instance | BindingFlags.NonPublic); + } - throw new HttpException(ex.Message, ex); - } - catch (Exception ex) - { - _logger.ErrorException("Error getting response from " + options.Url, ex); + _httpBehaviorPropertyInfo.SetValue(sp, (byte)0, null); - throw; - } - finally - { - if (options.ResourcePool != null) - { - options.ResourcePool.Release(); - } - } - } + return request; } /// - /// Performs a GET request and returns the resulting stream + /// Gets the response internal. /// /// The options. - /// Task{Stream}. - /// - /// - public async Task Get(HttpRequestOptions options) + /// The HTTP method. + /// Task{HttpResponseInfo}. + /// + /// + public async Task GetResponse(HttpRequestOptions options) { ValidateParams(options.Url, options.CancellationToken); @@ -209,72 +155,110 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager throw new HttpException(string.Format("Cancelling connection to {0} due to a previous timeout.", options.Url)) { IsTimedOut = true }; } - using (var message = GetHttpRequestMessage(options)) + var httpWebRequest = GetRequest(options, "GET", options.EnableHttpCompression); + + if (options.ResourcePool != null) + { + await options.ResourcePool.WaitAsync(options.CancellationToken).ConfigureAwait(false); + } + + if ((DateTime.UtcNow - client.LastTimeout).TotalSeconds < 30) { if (options.ResourcePool != null) { - await options.ResourcePool.WaitAsync(options.CancellationToken).ConfigureAwait(false); + options.ResourcePool.Release(); } - if ((DateTime.UtcNow - client.LastTimeout).TotalSeconds < 30) - { - if (options.ResourcePool != null) - { - options.ResourcePool.Release(); - } + throw new HttpException(string.Format("Connection to {0} timed out", options.Url)) { IsTimedOut = true }; + } - throw new HttpException(string.Format("Connection to {0} timed out", options.Url)) { IsTimedOut = true }; - } + _logger.Info("HttpClientManager.GET url: {0}", options.Url); - _logger.Info("HttpClientManager.Get url: {0}", options.Url); + try + { + options.CancellationToken.ThrowIfCancellationRequested(); - try + using (var response = await httpWebRequest.GetResponseAsync().ConfigureAwait(false)) { + var httpResponse = (HttpWebResponse)response; + + EnsureSuccessStatusCode(httpResponse); + options.CancellationToken.ThrowIfCancellationRequested(); - var response = await client.HttpClient.SendAsync(message, HttpCompletionOption.ResponseContentRead, options.CancellationToken).ConfigureAwait(false); + using (var stream = httpResponse.GetResponseStream()) + { + var memoryStream = new MemoryStream(); - EnsureSuccessStatusCode(response); + await stream.CopyToAsync(memoryStream).ConfigureAwait(false); - options.CancellationToken.ThrowIfCancellationRequested(); + memoryStream.Position = 0; - return await response.Content.ReadAsStreamAsync().ConfigureAwait(false); - } - catch (OperationCanceledException ex) - { - var exception = GetCancellationException(options.Url, options.CancellationToken, ex); + return new HttpResponseInfo + { + Content = memoryStream, - var httpException = exception as HttpException; + StatusCode = httpResponse.StatusCode, - if (httpException != null && httpException.IsTimedOut) - { - client.LastTimeout = DateTime.UtcNow; + ContentType = httpResponse.ContentType + }; } - - throw exception; } - catch (HttpRequestException ex) - { - _logger.ErrorException("Error getting response from " + options.Url, ex); + } + catch (OperationCanceledException ex) + { + var exception = GetCancellationException(options.Url, options.CancellationToken, ex); - throw new HttpException(ex.Message, ex); - } - catch (Exception ex) - { - _logger.ErrorException("Error getting response from " + options.Url, ex); + var httpException = exception as HttpException; - throw; + if (httpException != null && httpException.IsTimedOut) + { + client.LastTimeout = DateTime.UtcNow; } - finally + + throw exception; + } + catch (HttpRequestException ex) + { + _logger.ErrorException("Error getting response from " + options.Url, ex); + + throw new HttpException(ex.Message, ex); + } + catch (WebException ex) + { + _logger.ErrorException("Error getting response from " + options.Url, ex); + + throw new HttpException(ex.Message, ex); + } + catch (Exception ex) + { + _logger.ErrorException("Error getting response from " + options.Url, ex); + + throw; + } + finally + { + if (options.ResourcePool != null) { - if (options.ResourcePool != null) - { - options.ResourcePool.Release(); - } + options.ResourcePool.Release(); } } } + /// + /// Performs a GET request and returns the resulting stream + /// + /// The options. + /// Task{Stream}. + /// + /// + public async Task Get(HttpRequestOptions options) + { + var response = await GetResponse(options).ConfigureAwait(false); + + return response.Content; + } + /// /// Performs a GET request and returns the resulting stream /// @@ -306,64 +290,112 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager /// /// Performs a POST request /// - /// The URL. + /// The options. /// Params to add to the POST data. - /// The resource pool. - /// The cancellation token. /// stream on success, null on failure + /// + /// /// postData /// - public async Task Post(string url, Dictionary postData, SemaphoreSlim resourcePool, CancellationToken cancellationToken) + public async Task Post(HttpRequestOptions options, Dictionary postData) { - ValidateParams(url, cancellationToken); + ValidateParams(options.Url, options.CancellationToken); - if (postData == null) - { - throw new ArgumentNullException("postData"); - } + options.CancellationToken.ThrowIfCancellationRequested(); - cancellationToken.ThrowIfCancellationRequested(); + var httpWebRequest = GetRequest(options, "POST", options.EnableHttpCompression); var strings = postData.Keys.Select(key => string.Format("{0}={1}", key, postData[key])); var postContent = string.Join("&", strings.ToArray()); - var content = new StringContent(postContent, Encoding.UTF8, "application/x-www-form-urlencoded"); + var bytes = Encoding.UTF8.GetBytes(postContent); + + httpWebRequest.ContentType = "application/x-www-form-urlencoded"; + httpWebRequest.ContentLength = bytes.Length; + httpWebRequest.GetRequestStream().Write(bytes, 0, bytes.Length); - if (resourcePool != null) + if (options.ResourcePool != null) { - await resourcePool.WaitAsync(cancellationToken).ConfigureAwait(false); + await options.ResourcePool.WaitAsync(options.CancellationToken).ConfigureAwait(false); } - _logger.Info("HttpClientManager.Post url: {0}", url); + _logger.Info("HttpClientManager.POST url: {0}", options.Url); try { - cancellationToken.ThrowIfCancellationRequested(); + options.CancellationToken.ThrowIfCancellationRequested(); + + using (var response = await httpWebRequest.GetResponseAsync().ConfigureAwait(false)) + { + var httpResponse = (HttpWebResponse)response; + + EnsureSuccessStatusCode(httpResponse); + + options.CancellationToken.ThrowIfCancellationRequested(); - var msg = await GetHttpClient(GetHostFromUrl(url), true).HttpClient.PostAsync(url, content, cancellationToken).ConfigureAwait(false); + using (var stream = httpResponse.GetResponseStream()) + { + var memoryStream = new MemoryStream(); + + await stream.CopyToAsync(memoryStream).ConfigureAwait(false); - EnsureSuccessStatusCode(msg); + memoryStream.Position = 0; - return await msg.Content.ReadAsStreamAsync().ConfigureAwait(false); + return memoryStream; + } + } } catch (OperationCanceledException ex) { - throw GetCancellationException(url, cancellationToken, ex); + var exception = GetCancellationException(options.Url, options.CancellationToken, ex); + + throw exception; } catch (HttpRequestException ex) { - _logger.ErrorException("Error getting response from " + url, ex); + _logger.ErrorException("Error getting response from " + options.Url, ex); + + throw new HttpException(ex.Message, ex); + } + catch (WebException ex) + { + _logger.ErrorException("Error getting response from " + options.Url, ex); throw new HttpException(ex.Message, ex); } + catch (Exception ex) + { + _logger.ErrorException("Error getting response from " + options.Url, ex); + + throw; + } finally { - if (resourcePool != null) + if (options.ResourcePool != null) { - resourcePool.Release(); + options.ResourcePool.Release(); } } } + /// + /// Performs a POST request + /// + /// The URL. + /// Params to add to the POST data. + /// The resource pool. + /// The cancellation token. + /// stream on success, null on failure + public Task Post(string url, Dictionary postData, SemaphoreSlim resourcePool, CancellationToken cancellationToken) + { + return Post(new HttpRequestOptions + { + Url = url, + ResourcePool = resourcePool, + CancellationToken = cancellationToken + + }, postData); + } + /// /// Downloads the contents of a given url into a temporary location /// @@ -392,6 +424,8 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager options.CancellationToken.ThrowIfCancellationRequested(); + var httpWebRequest = GetRequest(options, "GET", options.EnableHttpCompression); + if (options.ResourcePool != null) { await options.ResourcePool.WaitAsync(options.CancellationToken).ConfigureAwait(false); @@ -399,60 +433,79 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager options.Progress.Report(0); - _logger.Info("HttpClientManager.GetTempFile url: {0}, temp file: {1}", options.Url, tempFile); + _logger.Info("HttpClientManager.GetTempFileResponse url: {0}", options.Url); try { options.CancellationToken.ThrowIfCancellationRequested(); - using (var message = GetHttpRequestMessage(options)) + using (var response = await httpWebRequest.GetResponseAsync().ConfigureAwait(false)) { - using (var response = await GetHttpClient(GetHostFromUrl(options.Url), options.EnableHttpCompression).HttpClient.SendAsync(message, HttpCompletionOption.ResponseHeadersRead, options.CancellationToken).ConfigureAwait(false)) - { - EnsureSuccessStatusCode(response); + var httpResponse = (HttpWebResponse)response; - options.CancellationToken.ThrowIfCancellationRequested(); + EnsureSuccessStatusCode(httpResponse); - var contentLength = GetContentLength(response); + options.CancellationToken.ThrowIfCancellationRequested(); + + var contentLength = GetContentLength(httpResponse); - if (!contentLength.HasValue) + if (!contentLength.HasValue) + { + // We're not able to track progress + using (var stream = httpResponse.GetResponseStream()) { - // We're not able to track progress - using (var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false)) + using (var fs = _fileSystem.GetFileStream(tempFile, FileMode.Create, FileAccess.Write, FileShare.Read, true)) { - using (var fs = _fileSystem.GetFileStream(tempFile, FileMode.Create, FileAccess.Write, FileShare.Read, true)) - { - await stream.CopyToAsync(fs, StreamDefaults.DefaultCopyToBufferSize, options.CancellationToken).ConfigureAwait(false); - } + await stream.CopyToAsync(fs, StreamDefaults.DefaultCopyToBufferSize, options.CancellationToken).ConfigureAwait(false); } } - else + } + else + { + using (var stream = ProgressStream.CreateReadProgressStream(httpResponse.GetResponseStream(), options.Progress.Report, contentLength.Value)) { - using (var stream = ProgressStream.CreateReadProgressStream(await response.Content.ReadAsStreamAsync().ConfigureAwait(false), options.Progress.Report, contentLength.Value)) + using (var fs = _fileSystem.GetFileStream(tempFile, FileMode.Create, FileAccess.Write, FileShare.Read, true)) { - using (var fs = _fileSystem.GetFileStream(tempFile, FileMode.Create, FileAccess.Write, FileShare.Read, true)) - { - await stream.CopyToAsync(fs, StreamDefaults.DefaultCopyToBufferSize, options.CancellationToken).ConfigureAwait(false); - } + await stream.CopyToAsync(fs, StreamDefaults.DefaultCopyToBufferSize, options.CancellationToken).ConfigureAwait(false); } } + } - options.Progress.Report(100); + options.Progress.Report(100); - return new HttpResponseInfo - { - TempFilePath = tempFile, + return new HttpResponseInfo + { + TempFilePath = tempFile, - StatusCode = response.StatusCode, + StatusCode = httpResponse.StatusCode, - ContentType = response.Content.Headers.ContentType.MediaType - }; - } + ContentType = httpResponse.ContentType + }; } } + catch (OperationCanceledException ex) + { + var exception = GetCancellationException(options.Url, options.CancellationToken, ex); + + throw exception; + } + catch (HttpRequestException ex) + { + _logger.ErrorException("Error getting response from " + options.Url, ex); + + throw new HttpException(ex.Message, ex); + } + catch (WebException ex) + { + _logger.ErrorException("Error getting response from " + options.Url, ex); + + throw new HttpException(ex.Message, ex); + } catch (Exception ex) { - throw GetTempFileException(ex, options, tempFile); + _logger.ErrorException("Error getting response from " + options.Url, ex); + + throw; } finally { @@ -522,6 +575,18 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager return long.Parse(string.Join(string.Empty, lengthValues.ToArray()), UsCulture); } + private long? GetContentLength(HttpWebResponse response) + { + var length = response.ContentLength; + + if (length == 0) + { + return null; + } + + return length; + } + protected static readonly CultureInfo UsCulture = new CultureInfo("en-US"); /// @@ -614,11 +679,6 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager { if (dispose) { - foreach (var client in _httpClients.Values.ToList()) - { - client.HttpClient.Dispose(); - } - _httpClients.Clear(); } } @@ -659,6 +719,17 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager } } + private void EnsureSuccessStatusCode(HttpWebResponse response) + { + var statusCode = response.StatusCode; + var isSuccessful = statusCode >= HttpStatusCode.OK && statusCode <= (HttpStatusCode)299; + + if (!isSuccessful) + { + throw new HttpException(response.StatusDescription) { StatusCode = response.StatusCode }; + } + } + /// /// Posts the specified URL. /// diff --git a/MediaBrowser.Common/Net/IHttpClient.cs b/MediaBrowser.Common/Net/IHttpClient.cs index 93348d4ca0..54d6665e23 100644 --- a/MediaBrowser.Common/Net/IHttpClient.cs +++ b/MediaBrowser.Common/Net/IHttpClient.cs @@ -73,6 +73,11 @@ namespace MediaBrowser.Common.Net /// Task GetTempFile(HttpRequestOptions options); + /// + /// Gets the temporary file response. + /// + /// The options. + /// Task{HttpResponseInfo}. Task GetTempFileResponse(HttpRequestOptions options); } } \ No newline at end of file diff --git a/MediaBrowser.ServerApplication/ApplicationHost.cs b/MediaBrowser.ServerApplication/ApplicationHost.cs index fcd7d299cf..be865881af 100644 --- a/MediaBrowser.ServerApplication/ApplicationHost.cs +++ b/MediaBrowser.ServerApplication/ApplicationHost.cs @@ -702,16 +702,6 @@ namespace MediaBrowser.ServerApplication OnApplicationUpdated(package.version); } - /// - /// Creates the HTTP client. - /// - /// if set to true [enable HTTP compression]. - /// HttpClient. - protected override HttpClient CreateHttpClient(bool enableHttpCompression) - { - return HttpClientFactory.GetHttpClient(enableHttpCompression); - } - protected override void ConfigureAutoRunAtStartup(bool autorun) { Autorun.Configure(autorun); diff --git a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj index cfacffe087..795799ca3e 100644 --- a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj +++ b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj @@ -190,7 +190,6 @@ - diff --git a/MediaBrowser.ServerApplication/Native/HttpClientFactory.cs b/MediaBrowser.ServerApplication/Native/HttpClientFactory.cs deleted file mode 100644 index 368c60254b..0000000000 --- a/MediaBrowser.ServerApplication/Native/HttpClientFactory.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System; -using System.Net; -using System.Net.Cache; -using System.Net.Http; - -namespace MediaBrowser.ServerApplication.Native -{ - /// - /// Class HttpClientFactory - /// - public static class HttpClientFactory - { - /// - /// Gets the HTTP client. - /// - /// if set to true [enable HTTP compression]. - /// HttpClient. - public static HttpClient GetHttpClient(bool enableHttpCompression) - { - var client = new HttpClient(new WebRequestHandler - { - CachePolicy = new RequestCachePolicy(RequestCacheLevel.Revalidate), - AutomaticDecompression = enableHttpCompression ? DecompressionMethods.Deflate : DecompressionMethods.None - - }) - { - Timeout = TimeSpan.FromSeconds(20) - }; - - client.DefaultRequestHeaders.Add("Connection", "Keep-Alive"); - - return client; - } - } -}