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 {