diff --git a/DigitalData.Core.Abstractions/Client/IBaseHttpClientService.cs b/DigitalData.Core.Abstractions/Client/IBaseHttpClientService.cs index 756e94e..ee53441 100644 --- a/DigitalData.Core.Abstractions/Client/IBaseHttpClientService.cs +++ b/DigitalData.Core.Abstractions/Client/IBaseHttpClientService.cs @@ -6,12 +6,12 @@ namespace DigitalData.Core.Abstractions.Client { string Uri { get; init; } - CookieCollection GetCookies(string route = ""); + CookieCollection GetCookies(string path = ""); Task FetchAsync( string? scheme = null, int? port = null, - string? path = null, + string path = "", Dictionary? queryParams = null, HttpMethod? method = null, HttpContent? body = null, diff --git a/DigitalData.Core.Abstractions/Client/IHttpClientOptions.cs b/DigitalData.Core.Abstractions/Client/IHttpClientOptions.cs index 9e00475..ba6a311 100644 --- a/DigitalData.Core.Abstractions/Client/IHttpClientOptions.cs +++ b/DigitalData.Core.Abstractions/Client/IHttpClientOptions.cs @@ -3,5 +3,7 @@ public interface IHttpClientOptions { public string Uri { get; set; } + + public string Path { get; set; } } } \ No newline at end of file diff --git a/DigitalData.Core.Client/BaseHttpClientService.cs b/DigitalData.Core.Client/BaseHttpClientService.cs index ee45d4d..b5926a3 100644 --- a/DigitalData.Core.Client/BaseHttpClientService.cs +++ b/DigitalData.Core.Client/BaseHttpClientService.cs @@ -9,24 +9,27 @@ namespace DigitalData.Core.Client public class BaseHttpClientService : IBaseHttpClientService { protected readonly HttpClient _client; - protected readonly CookieContainer _cookies; + protected readonly CookieContainer _cookies; [StringSyntax("Uri")] public string Uri { get; init; } + public string Path { get; init; } = string.Empty; + public BaseHttpClientService(HttpClient client, CookieContainer cookieContainer, IOptions clientOptions) { _client = client; _cookies = cookieContainer; - Uri = clientOptions.Value.Uri; + Uri = clientOptions.Value.Uri.Trim(URI_TRIM_CHARS); + Path = clientOptions.Value.Path.Trim(URI_TRIM_CHARS); } - public CookieCollection GetCookies(string route = "") => _cookies.GetCookies(uri: new Uri(Uri + route)); + public CookieCollection GetCookies(string path = "") => _cookies.GetCookies(uri: new Uri(UriCombine(Uri, path, path.Trim(URI_TRIM_CHARS)))); public async Task FetchAsync( string? scheme = null, int? port = null, - string? path = null, + string path = "", Dictionary? queryParams = null, HttpMethod? method = null, HttpContent? body = null, @@ -41,11 +44,11 @@ namespace DigitalData.Core.Client // create URL var uriBuilder = new UriBuilder(Uri); - if(scheme is not null) + if (scheme is not null) uriBuilder.Scheme = scheme; if (port is int portInt) uriBuilder.Port = portInt; - uriBuilder.Path = path; + uriBuilder.Path = UriCombine(Path, path.Trim(URI_TRIM_CHARS)); // Add query parameters if provided if (queryParams?.Count > 0) @@ -92,5 +95,9 @@ namespace DigitalData.Core.Client return response; } + + internal static readonly char[] URI_TRIM_CHARS = { '\\', '/', ' ' }; + + internal static string UriCombine(params string[] paths) => System.IO.Path.Combine(paths).Replace("\\", "/"); } } \ No newline at end of file diff --git a/DigitalData.Core.Client/DIExtensions.cs b/DigitalData.Core.Client/DIExtensions.cs index 0d90794..8291df2 100644 --- a/DigitalData.Core.Client/DIExtensions.cs +++ b/DigitalData.Core.Client/DIExtensions.cs @@ -7,12 +7,16 @@ namespace DigitalData.Core.Client { public static class DIExtensions { - public static IServiceCollection AddHttpClientService(this IServiceCollection services, string uri) + public static IServiceCollection AddHttpClientService(this IServiceCollection services, string uri, string path = "") { services.TryAddSingleton(); services.TryAddSingleton(); services.AddSingleton(); - services.Configure(opt => opt.Uri = uri); + services.Configure(opt => + { + opt.Uri = uri; + opt.Path = path; + }); return services; } @@ -22,11 +26,11 @@ namespace DigitalData.Core.Client { services.TryAddSingleton(); services.TryAddSingleton(); - services.AddSingleton, HttpClientService>(); + services.TryAddSingleton, HttpClientService>(); services.Configure(clientOptions ?? (_ => { })); if (setAsDefaultBase) - services.AddSingleton>(); + services.TryAddSingleton>(); return services; } diff --git a/DigitalData.Core.Client/HttpClientOptions.cs b/DigitalData.Core.Client/HttpClientOptions.cs index 3be116f..b138b59 100644 --- a/DigitalData.Core.Client/HttpClientOptions.cs +++ b/DigitalData.Core.Client/HttpClientOptions.cs @@ -5,5 +5,7 @@ namespace DigitalData.Core.Client public class HttpClientOptions : IHttpClientOptions { public string Uri { get; set; } = string.Empty; + + public string Path { get; set; } = string.Empty; } } \ No newline at end of file diff --git a/DigitalData.Core.Tests/Client/BaseHttpClientServiceTest.cs b/DigitalData.Core.Tests/Client/BaseHttpClientServiceTest.cs index c3388d8..f7e7b3d 100644 --- a/DigitalData.Core.Tests/Client/BaseHttpClientServiceTest.cs +++ b/DigitalData.Core.Tests/Client/BaseHttpClientServiceTest.cs @@ -14,7 +14,7 @@ namespace DigitalData.Core.Tests.Client public void SetUp() { _serviceProvider = new ServiceCollection() - .AddHttpClientService("https://jsonplaceholder.typicode.com/todos") + .AddHttpClientService("https://jsonplaceholder.typicode.com", "todos") .BuildServiceProvider(); _service = _serviceProvider.GetRequiredService(); @@ -24,7 +24,7 @@ namespace DigitalData.Core.Tests.Client public async Task FetchJsonAsync_ShouldReturnJsonResponse() { // Act - var expectedUserId = (int) await _service.FetchAsync("/1", sendWithCookie: false, saveCookie: false) + var expectedUserId = (int) await _service.FetchAsync(path: "/1", sendWithCookie: false, saveCookie: false) .ThenAsync(res => res.Json()) .ThenAsync(todo => todo.userId);