feat: Implementierung von BaseHttpClientService und DIExtensions für HTTP-Client-Dienste

- Hinzugefügt: `BaseHttpClientService` zur Handhabung von HTTP-Anfragen mit Cookie-Verwaltung.
- Implementiert: `HttpClientService<TClientOptions>`, 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.
This commit is contained in:
Developer 02 2024-06-26 13:38:08 +02:00
parent 5e26545036
commit ba94f4689a
8 changed files with 148 additions and 6 deletions

View File

@ -0,0 +1,16 @@
namespace DigitalData.Core.Abstractions.Client
{
public interface IBaseHttpClientService
{
public string Uri { get; init; }
Task<HttpResponseMessage> FetchAsync(
string route = "",
HttpMethod? method = null,
HttpContent? body = null,
Dictionary<string, string>? form = null,
bool sendWithCookie = true,
bool saveCookie = true
);
}
}

View File

@ -0,0 +1,7 @@
namespace DigitalData.Core.Abstractions.Client
{
public interface IHttpClientService<TClientOptions> : IBaseHttpClientService
where TClientOptions : new()
{
}
}

View File

@ -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<HttpClientOptions> clientOptions)
{
_client = client;
_cookies = cookieContainer;
Uri = clientOptions.Value.Uri;
}
public async Task<HttpResponseMessage> FetchAsync(
string route = "",
HttpMethod? method = null,
HttpContent? body = null,
Dictionary<string, string>? 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;
}
}
}

View File

@ -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<HttpClient>();
services.TryAddSingleton<CookieContainer>();
services.AddSingleton<IBaseHttpClientService, BaseHttpClientService>();
services.Configure<HttpClientOptions>(opt => opt.Uri = uri);
return services;
}
public static IServiceCollection AddHttpClientService<TClientOptions>(this IServiceCollection services, Action<TClientOptions>? clientOptions = null, bool setAsDefault = false)
where TClientOptions : HttpClientOptions, new()
{
services.TryAddSingleton<HttpClient>();
services.TryAddSingleton<CookieContainer>();
services.AddSingleton<IHttpClientService<TClientOptions>, HttpClientService<TClientOptions>>();
services.Configure(clientOptions ?? (_ => { }));
if (setAsDefault)
services.AddSingleton<IBaseHttpClientService, HttpClientService<TClientOptions>>();
return services;
}
}
}

View File

@ -18,14 +18,12 @@
</PropertyGroup>
<ItemGroup>
<None Include="..\DigitalData.Core.Abstractions\Assets\icon.png">
<Pack>True</Pack>
<PackagePath>\</PackagePath>
</None>
<PackageReference Include="Microsoft.Extensions.Options" Version="7.0.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<ProjectReference Include="..\DigitalData.Core.Abstractions\DigitalData.Core.Abstractions.csproj" />
</ItemGroup>
<ItemGroup>

View File

@ -0,0 +1,7 @@
namespace DigitalData.Core.Client
{
public class HttpClientOptions
{
public required string Uri { get; set; }
}
}

View File

@ -0,0 +1,14 @@
using DigitalData.Core.Abstractions.Client;
using Microsoft.Extensions.Options;
using System.Net;
namespace DigitalData.Core.Client
{
public class HttpClientService<TClientOptions> : BaseHttpClientService, IHttpClientService<TClientOptions>, IBaseHttpClientService
where TClientOptions : HttpClientOptions, new()
{
public HttpClientService(HttpClient client, CookieContainer cookieContainer, IOptions<TClientOptions> clientOptions) : base(client, cookieContainer, clientOptions)
{
}
}
}

View File

@ -1,6 +1,5 @@
using Newtonsoft.Json;
using System.Net.Http.Json;
using System.Threading.Tasks;
namespace DigitalData.Core.Client
{