mirror of
https://github.com/Ombi-app/Ombi.git
synced 2025-08-20 05:13:18 -07:00
Switch to use a single HTTPClient rather than a new one every request !dev
This commit is contained in:
parent
5d9ce785c7
commit
bec5604720
4 changed files with 153 additions and 75 deletions
|
@ -16,29 +16,18 @@ namespace Ombi.Api
|
||||||
{
|
{
|
||||||
public class Api : IApi
|
public class Api : IApi
|
||||||
{
|
{
|
||||||
public Api(ILogger<Api> log, ISettingsService<OmbiSettings> s, ICacheService cache)
|
public Api(ILogger<Api> log, ISettingsService<OmbiSettings> s, ICacheService cache, IOmbiHttpClient client)
|
||||||
{
|
{
|
||||||
Logger = log;
|
Logger = log;
|
||||||
_settings = s;
|
_settings = s;
|
||||||
_cache = cache;
|
_cache = cache;
|
||||||
|
_client = client;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ILogger<Api> Logger { get; }
|
private ILogger<Api> Logger { get; }
|
||||||
private readonly ISettingsService<OmbiSettings> _settings;
|
private readonly ISettingsService<OmbiSettings> _settings;
|
||||||
private readonly ICacheService _cache;
|
private readonly ICacheService _cache;
|
||||||
|
private readonly IOmbiHttpClient _client;
|
||||||
private async Task<HttpMessageHandler> GetHandler()
|
|
||||||
{
|
|
||||||
var settings = await _cache.GetOrAdd(CacheKeys.OmbiSettings, async () => await _settings.GetSettingsAsync(), DateTime.Now.AddHours(1));
|
|
||||||
if (settings.IgnoreCertificateErrors)
|
|
||||||
{
|
|
||||||
return new HttpClientHandler
|
|
||||||
{
|
|
||||||
ServerCertificateCustomValidationCallback = (message, certificate2, arg3, arg4) => true,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return new HttpClientHandler();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static readonly JsonSerializerSettings Settings = new JsonSerializerSettings
|
private static readonly JsonSerializerSettings Settings = new JsonSerializerSettings
|
||||||
{
|
{
|
||||||
|
@ -47,89 +36,82 @@ namespace Ombi.Api
|
||||||
|
|
||||||
public async Task<T> Request<T>(Request request)
|
public async Task<T> Request<T>(Request request)
|
||||||
{
|
{
|
||||||
using(var handler = await GetHandler())
|
using (var httpRequestMessage = new HttpRequestMessage(request.HttpMethod, request.FullUri))
|
||||||
using (var httpClient = new HttpClient(handler))
|
|
||||||
{
|
{
|
||||||
using (var httpRequestMessage = new HttpRequestMessage(request.HttpMethod, request.FullUri))
|
// Add the Json Body
|
||||||
|
if (request.JsonBody != null)
|
||||||
{
|
{
|
||||||
// Add the Json Body
|
httpRequestMessage.Content = new JsonContent(request.JsonBody);
|
||||||
if (request.JsonBody != null)
|
httpRequestMessage.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json"); // Emby connect fails if we have the charset in the header
|
||||||
{
|
}
|
||||||
httpRequestMessage.Content = new JsonContent(request.JsonBody);
|
|
||||||
httpRequestMessage.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json"); // Emby connect fails if we have the charset in the header
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add headers
|
// Add headers
|
||||||
foreach (var header in request.Headers)
|
foreach (var header in request.Headers)
|
||||||
{
|
{
|
||||||
httpRequestMessage.Headers.Add(header.Key, header.Value);
|
httpRequestMessage.Headers.Add(header.Key, header.Value);
|
||||||
|
|
||||||
}
|
}
|
||||||
using (var httpResponseMessage = await httpClient.SendAsync(httpRequestMessage))
|
using (var httpResponseMessage = await _client.SendAsync(httpRequestMessage))
|
||||||
|
{
|
||||||
|
if (!httpResponseMessage.IsSuccessStatusCode)
|
||||||
{
|
{
|
||||||
if (!httpResponseMessage.IsSuccessStatusCode)
|
Logger.LogError(LoggingEvents.Api, $"StatusCode: {httpResponseMessage.StatusCode}, Reason: {httpResponseMessage.ReasonPhrase}");
|
||||||
{
|
}
|
||||||
Logger.LogError(LoggingEvents.Api, $"StatusCode: {httpResponseMessage.StatusCode}, Reason: {httpResponseMessage.ReasonPhrase}");
|
// do something with the response
|
||||||
}
|
var data = httpResponseMessage.Content;
|
||||||
// do something with the response
|
var receivedString = await data.ReadAsStringAsync();
|
||||||
var data = httpResponseMessage.Content;
|
if (request.ContentType == ContentType.Json)
|
||||||
var receivedString = await data.ReadAsStringAsync();
|
{
|
||||||
if (request.ContentType == ContentType.Json)
|
request.OnBeforeDeserialization?.Invoke(receivedString);
|
||||||
{
|
return JsonConvert.DeserializeObject<T>(receivedString, Settings);
|
||||||
request.OnBeforeDeserialization?.Invoke(receivedString);
|
}
|
||||||
return JsonConvert.DeserializeObject<T>(receivedString, Settings);
|
else
|
||||||
}
|
{
|
||||||
else
|
// XML
|
||||||
{
|
XmlSerializer serializer = new XmlSerializer(typeof(T));
|
||||||
// XML
|
StringReader reader = new StringReader(receivedString);
|
||||||
XmlSerializer serializer = new XmlSerializer(typeof(T));
|
var value = (T)serializer.Deserialize(reader);
|
||||||
StringReader reader = new StringReader(receivedString);
|
return value;
|
||||||
var value = (T)serializer.Deserialize(reader);
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<string> RequestContent(Request request)
|
public async Task<string> RequestContent(Request request)
|
||||||
{
|
{
|
||||||
using (var httpClient = new HttpClient(await GetHandler()))
|
using (var httpRequestMessage = new HttpRequestMessage(request.HttpMethod, request.FullUri))
|
||||||
{
|
{
|
||||||
using (var httpRequestMessage = new HttpRequestMessage(request.HttpMethod, request.FullUri))
|
// Add the Json Body
|
||||||
|
if (request.JsonBody != null)
|
||||||
{
|
{
|
||||||
// Add the Json Body
|
httpRequestMessage.Content = new JsonContent(request.JsonBody);
|
||||||
if (request.JsonBody != null)
|
}
|
||||||
|
|
||||||
|
// Add headers
|
||||||
|
foreach (var header in request.Headers)
|
||||||
|
{
|
||||||
|
httpRequestMessage.Headers.Add(header.Key, header.Value);
|
||||||
|
|
||||||
|
}
|
||||||
|
using (var httpResponseMessage = await _client.SendAsync(httpRequestMessage))
|
||||||
|
{
|
||||||
|
if (!httpResponseMessage.IsSuccessStatusCode)
|
||||||
{
|
{
|
||||||
httpRequestMessage.Content = new JsonContent(request.JsonBody);
|
Logger.LogError(LoggingEvents.Api, $"StatusCode: {httpResponseMessage.StatusCode}, Reason: {httpResponseMessage.ReasonPhrase}");
|
||||||
}
|
}
|
||||||
|
// do something with the response
|
||||||
// Add headers
|
var data = httpResponseMessage.Content;
|
||||||
foreach (var header in request.Headers)
|
|
||||||
{
|
|
||||||
httpRequestMessage.Headers.Add(header.Key, header.Value);
|
|
||||||
|
|
||||||
}
|
|
||||||
using (var httpResponseMessage = await httpClient.SendAsync(httpRequestMessage))
|
|
||||||
{
|
|
||||||
if (!httpResponseMessage.IsSuccessStatusCode)
|
|
||||||
{
|
|
||||||
Logger.LogError(LoggingEvents.Api, $"StatusCode: {httpResponseMessage.StatusCode}, Reason: {httpResponseMessage.ReasonPhrase}");
|
|
||||||
}
|
|
||||||
// do something with the response
|
|
||||||
var data = httpResponseMessage.Content;
|
|
||||||
|
|
||||||
|
|
||||||
return await data.ReadAsStringAsync();
|
return await data.ReadAsStringAsync();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Request(Request request)
|
public async Task Request(Request request)
|
||||||
{
|
{
|
||||||
using (var httpClient = new HttpClient(await GetHandler()))
|
|
||||||
{
|
|
||||||
using (var httpRequestMessage = new HttpRequestMessage(request.HttpMethod, request.FullUri))
|
using (var httpRequestMessage = new HttpRequestMessage(request.HttpMethod, request.FullUri))
|
||||||
{
|
{
|
||||||
// Add the Json Body
|
// Add the Json Body
|
||||||
|
@ -144,7 +126,7 @@ namespace Ombi.Api
|
||||||
httpRequestMessage.Headers.Add(header.Key, header.Value);
|
httpRequestMessage.Headers.Add(header.Key, header.Value);
|
||||||
|
|
||||||
}
|
}
|
||||||
using (var httpResponseMessage = await httpClient.SendAsync(httpRequestMessage))
|
using (var httpResponseMessage = await _client.SendAsync(httpRequestMessage))
|
||||||
{
|
{
|
||||||
if (!httpResponseMessage.IsSuccessStatusCode)
|
if (!httpResponseMessage.IsSuccessStatusCode)
|
||||||
{
|
{
|
||||||
|
@ -152,7 +134,6 @@ namespace Ombi.Api
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
10
src/Ombi.Api/IOmbiHttpClient.cs
Normal file
10
src/Ombi.Api/IOmbiHttpClient.cs
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Ombi.Api
|
||||||
|
{
|
||||||
|
public interface IOmbiHttpClient
|
||||||
|
{
|
||||||
|
Task<HttpResponseMessage> SendAsync(HttpRequestMessage request);
|
||||||
|
}
|
||||||
|
}
|
86
src/Ombi.Api/OmbiHttpClient.cs
Normal file
86
src/Ombi.Api/OmbiHttpClient.cs
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
#region Copyright
|
||||||
|
// /************************************************************************
|
||||||
|
// Copyright (c) 2017 Jamie Rees
|
||||||
|
// File: OmbiHttpClient.cs
|
||||||
|
// Created By: Jamie Rees
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
// a copy of this software and associated documentation files (the
|
||||||
|
// "Software"), to deal in the Software without restriction, including
|
||||||
|
// without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
// permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
// the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be
|
||||||
|
// included in all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
// ************************************************************************/
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Ombi.Core.Settings;
|
||||||
|
using Ombi.Helpers;
|
||||||
|
using Ombi.Settings.Settings.Models;
|
||||||
|
|
||||||
|
namespace Ombi.Api
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The purpose of this class is simple, keep one instance of the HttpClient in play.
|
||||||
|
/// There are many articles related to when using multiple HttpClient's keeping the socket in a WAIT state
|
||||||
|
/// https://blogs.msdn.microsoft.com/alazarev/2017/12/29/disposable-finalizers-and-httpclient/
|
||||||
|
/// https://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/
|
||||||
|
/// </summary>
|
||||||
|
public class OmbiHttpClient : IOmbiHttpClient
|
||||||
|
{
|
||||||
|
public OmbiHttpClient(ICacheService cache, ISettingsService<OmbiSettings> s)
|
||||||
|
{
|
||||||
|
_cache = cache;
|
||||||
|
_settings = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static HttpClient _client;
|
||||||
|
private static HttpMessageHandler _handler;
|
||||||
|
|
||||||
|
private readonly ICacheService _cache;
|
||||||
|
private readonly ISettingsService<OmbiSettings> _settings;
|
||||||
|
|
||||||
|
|
||||||
|
public async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request)
|
||||||
|
{
|
||||||
|
if (_client == null)
|
||||||
|
{
|
||||||
|
if (_handler == null)
|
||||||
|
{
|
||||||
|
// Get the handler
|
||||||
|
_handler = await GetHandler();
|
||||||
|
}
|
||||||
|
_client = new HttpClient(_handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
return await _client.SendAsync(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<HttpMessageHandler> GetHandler()
|
||||||
|
{
|
||||||
|
var settings = await _cache.GetOrAdd(CacheKeys.OmbiSettings, async () => await _settings.GetSettingsAsync(), DateTime.Now.AddHours(1));
|
||||||
|
if (settings.IgnoreCertificateErrors)
|
||||||
|
{
|
||||||
|
return new HttpClientHandler
|
||||||
|
{
|
||||||
|
ServerCertificateCustomValidationCallback = (message, certificate2, arg3, arg4) => true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return new HttpClientHandler();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -86,6 +86,7 @@ namespace Ombi.DependencyInjection
|
||||||
public static void RegisterApi(this IServiceCollection services)
|
public static void RegisterApi(this IServiceCollection services)
|
||||||
{
|
{
|
||||||
services.AddTransient<IApi, Api.Api>();
|
services.AddTransient<IApi, Api.Api>();
|
||||||
|
services.AddSingleton<IOmbiHttpClient, OmbiHttpClient>(); // https://blogs.msdn.microsoft.com/alazarev/2017/12/29/disposable-finalizers-and-httpclient/
|
||||||
services.AddTransient<IMovieDbApi, Api.TheMovieDb.TheMovieDbApi>();
|
services.AddTransient<IMovieDbApi, Api.TheMovieDb.TheMovieDbApi>();
|
||||||
services.AddTransient<IPlexApi, PlexApi>();
|
services.AddTransient<IPlexApi, PlexApi>();
|
||||||
services.AddTransient<IEmbyApi, EmbyApi>();
|
services.AddTransient<IEmbyApi, EmbyApi>();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue