From ba94f4689a8de4787af845e610758850d596c7cc Mon Sep 17 00:00:00 2001 From: Developer 02 Date: Wed, 26 Jun 2024 13:38:08 +0200 Subject: [PATCH] =?UTF-8?q?feat:=20Implementierung=20von=20BaseHttpClientS?= =?UTF-8?q?ervice=20und=20DIExtensions=20f=C3=BCr=20HTTP-Client-Dienste?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Hinzugefügt: `BaseHttpClientService` zur Handhabung von HTTP-Anfragen mit Cookie-Verwaltung. - Implementiert: `HttpClientService`, das `BaseHttpClientService` für typisierte Client-Optionen erweitert. - Erstellt: `DIExtensions` zur Registrierung von HTTP-Client-Diensten im Dependency Injection Container. - Bereitgestellt: Methoden zum Hinzufügen von HTTP-Client-Diensten mit und ohne spezifische Client-Optionen. - Konfiguriert: Optionen zum Festlegen der Basis-URI für HTTP-Clients. --- .../Client/IBaseHttpClientService.cs | 16 +++++ .../Client/IHttpClientService.cs | 7 ++ .../BaseHttpClientService.cs | 67 +++++++++++++++++++ DigitalData.Core.Client/DIExtensions.cs | 34 ++++++++++ .../DigitalData.Core.Client.csproj | 8 +-- DigitalData.Core.Client/HttpClientOptions.cs | 7 ++ DigitalData.Core.Client/HttpClientService.cs | 14 ++++ DigitalData.Core.Client/HttpExtensions.cs | 1 - 8 files changed, 148 insertions(+), 6 deletions(-) create mode 100644 DigitalData.Core.Abstractions/Client/IBaseHttpClientService.cs create mode 100644 DigitalData.Core.Abstractions/Client/IHttpClientService.cs create mode 100644 DigitalData.Core.Client/BaseHttpClientService.cs create mode 100644 DigitalData.Core.Client/DIExtensions.cs create mode 100644 DigitalData.Core.Client/HttpClientOptions.cs create mode 100644 DigitalData.Core.Client/HttpClientService.cs diff --git a/DigitalData.Core.Abstractions/Client/IBaseHttpClientService.cs b/DigitalData.Core.Abstractions/Client/IBaseHttpClientService.cs new file mode 100644 index 0000000..1d76d72 --- /dev/null +++ b/DigitalData.Core.Abstractions/Client/IBaseHttpClientService.cs @@ -0,0 +1,16 @@ +namespace DigitalData.Core.Abstractions.Client +{ + public interface IBaseHttpClientService + { + public string Uri { get; init; } + + Task FetchAsync( + string route = "", + HttpMethod? method = null, + HttpContent? body = null, + Dictionary? form = null, + bool sendWithCookie = true, + bool saveCookie = true + ); + } +} \ No newline at end of file diff --git a/DigitalData.Core.Abstractions/Client/IHttpClientService.cs b/DigitalData.Core.Abstractions/Client/IHttpClientService.cs new file mode 100644 index 0000000..95973e5 --- /dev/null +++ b/DigitalData.Core.Abstractions/Client/IHttpClientService.cs @@ -0,0 +1,7 @@ +namespace DigitalData.Core.Abstractions.Client +{ + public interface IHttpClientService : IBaseHttpClientService + where TClientOptions : new() + { + } +} \ No newline at end of file diff --git a/DigitalData.Core.Client/BaseHttpClientService.cs b/DigitalData.Core.Client/BaseHttpClientService.cs new file mode 100644 index 0000000..0664e7d --- /dev/null +++ b/DigitalData.Core.Client/BaseHttpClientService.cs @@ -0,0 +1,67 @@ +using DigitalData.Core.Abstractions.Client; +using Microsoft.Extensions.Options; +using System.Diagnostics.CodeAnalysis; +using System.Net; + +namespace DigitalData.Core.Client +{ + public class BaseHttpClientService : IBaseHttpClientService + { + protected readonly HttpClient _client; + protected readonly CookieContainer _cookies; + + [StringSyntax("Uri")] + public string Uri { get; init; } + + public BaseHttpClientService(HttpClient client, CookieContainer cookieContainer, IOptions clientOptions) + { + _client = client; + _cookies = cookieContainer; + Uri = clientOptions.Value.Uri; + } + + public async Task FetchAsync( + string route = "", + HttpMethod? method = null, + HttpContent? body = null, + Dictionary? form = null, + bool sendWithCookie = true, + bool saveCookie = true + ) + { + // set default HTTP method as GET + method ??= HttpMethod.Get; + + // create URL + var requestUriStr = Uri + route; + var requestUri = new Uri(requestUriStr); + + var requestMessage = new HttpRequestMessage(method, requestUriStr); + + // Add cookie to request + if (sendWithCookie) + { + var cookieHeader = _cookies.GetCookieHeader(requestUri); + requestMessage.Headers.Add("Cookie", cookieHeader); + } + + // Add body content if provided + if (body != null && form != null) + throw new InvalidOperationException("Body content and form data cannot both be set."); + else if (body != null) + requestMessage.Content = body; + else if (form != null) + requestMessage.Content = new FormUrlEncodedContent(form); + + var response = await _client.SendAsync(requestMessage); + + // Add response cookies to cookies + if (saveCookie) + if (response.Headers.TryGetValues("Set-Cookie", out var cookies)) + foreach (var cookie in cookies) + _cookies.SetCookies(requestUri, cookie); + + return response; + } + } +} \ No newline at end of file diff --git a/DigitalData.Core.Client/DIExtensions.cs b/DigitalData.Core.Client/DIExtensions.cs new file mode 100644 index 0000000..e9c654c --- /dev/null +++ b/DigitalData.Core.Client/DIExtensions.cs @@ -0,0 +1,34 @@ +using DigitalData.Core.Abstractions.Client; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; +using System.Net; + +namespace DigitalData.Core.Client +{ + public static class DIExtensions + { + public static IServiceCollection AddHttpClientService(this IServiceCollection services, string uri) + { + services.TryAddSingleton(); + services.TryAddSingleton(); + services.AddSingleton(); + services.Configure(opt => opt.Uri = uri); + + return services; + } + + public static IServiceCollection AddHttpClientService(this IServiceCollection services, Action? clientOptions = null, bool setAsDefault = false) + where TClientOptions : HttpClientOptions, new() + { + services.TryAddSingleton(); + services.TryAddSingleton(); + services.AddSingleton, HttpClientService>(); + services.Configure(clientOptions ?? (_ => { })); + + if (setAsDefault) + services.AddSingleton>(); + + return services; + } + } +} \ No newline at end of file diff --git a/DigitalData.Core.Client/DigitalData.Core.Client.csproj b/DigitalData.Core.Client/DigitalData.Core.Client.csproj index 944e269..4827aae 100644 --- a/DigitalData.Core.Client/DigitalData.Core.Client.csproj +++ b/DigitalData.Core.Client/DigitalData.Core.Client.csproj @@ -18,14 +18,12 @@ - - True - \ - + + - + diff --git a/DigitalData.Core.Client/HttpClientOptions.cs b/DigitalData.Core.Client/HttpClientOptions.cs new file mode 100644 index 0000000..aa993d1 --- /dev/null +++ b/DigitalData.Core.Client/HttpClientOptions.cs @@ -0,0 +1,7 @@ +namespace DigitalData.Core.Client +{ + public class HttpClientOptions + { + public required string Uri { get; set; } + } +} diff --git a/DigitalData.Core.Client/HttpClientService.cs b/DigitalData.Core.Client/HttpClientService.cs new file mode 100644 index 0000000..cb00e43 --- /dev/null +++ b/DigitalData.Core.Client/HttpClientService.cs @@ -0,0 +1,14 @@ +using DigitalData.Core.Abstractions.Client; +using Microsoft.Extensions.Options; +using System.Net; + +namespace DigitalData.Core.Client +{ + public class HttpClientService : BaseHttpClientService, IHttpClientService, IBaseHttpClientService + where TClientOptions : HttpClientOptions, new() + { + public HttpClientService(HttpClient client, CookieContainer cookieContainer, IOptions clientOptions) : base(client, cookieContainer, clientOptions) + { + } + } +} \ No newline at end of file diff --git a/DigitalData.Core.Client/HttpExtensions.cs b/DigitalData.Core.Client/HttpExtensions.cs index 05ce43f..2501fa3 100644 --- a/DigitalData.Core.Client/HttpExtensions.cs +++ b/DigitalData.Core.Client/HttpExtensions.cs @@ -1,6 +1,5 @@ using Newtonsoft.Json; using System.Net.Http.Json; -using System.Threading.Tasks; namespace DigitalData.Core.Client {