diff --git a/src/clients/dotnet/Bitip.Client.Tests/TestConfiguration.cs b/src/clients/dotnet/Bitip.Client.Tests/TestConfiguration.cs
index 8d5af56..1a18635 100644
--- a/src/clients/dotnet/Bitip.Client.Tests/TestConfiguration.cs
+++ b/src/clients/dotnet/Bitip.Client.Tests/TestConfiguration.cs
@@ -15,7 +15,7 @@ namespace Bitip.Client.Tests
///
/// Real Bitip API base URL for integration tests.
///
- public const string RealApiBaseUrl = "http://localhost:5172/api/";
+ public const string RealApiBaseUrl = "http://localhost:5172";
///
/// Real API key for integration tests.
diff --git a/src/clients/dotnet/Bitip.Client/Helpers/UriNormalizer.cs b/src/clients/dotnet/Bitip.Client/Helpers/UriNormalizer.cs
index 242b2d1..1dd3671 100644
--- a/src/clients/dotnet/Bitip.Client/Helpers/UriNormalizer.cs
+++ b/src/clients/dotnet/Bitip.Client/Helpers/UriNormalizer.cs
@@ -1,6 +1,7 @@
// Copyright (c) 2025 Tudor Stanciu
using System;
+using System.Linq;
namespace Bitip.Client.Helpers
{
@@ -13,5 +14,47 @@ namespace Bitip.Client.Helpers
var address = trimmed.EndsWith("/") ? trimmed : $"{trimmed}/";
return new Uri(address);
}
+
+ public static Uri EnsureTrailingSlash(string url, string suffix)
+ {
+ if (url is null) throw new ArgumentNullException(nameof(url));
+ if (url is null) throw new ArgumentNullException(nameof(url));
+ if (string.IsNullOrWhiteSpace(suffix)) return EnsureTrailingSlash(url);
+
+ var normalizedSuffix = suffix.Trim('/');
+ if (normalizedSuffix.Length == 0) return EnsureTrailingSlash(url);
+
+ // Get last non-empty segment from the url
+ var parts = url.Split('/', StringSplitOptions.RemoveEmptyEntries);
+ var lastSegment = parts.Length == 0 ? string.Empty : parts.Last();
+
+ if (!string.Equals(lastSegment, normalizedSuffix, StringComparison.OrdinalIgnoreCase))
+ {
+ url = PathCombine(url, normalizedSuffix);
+ }
+
+ return EnsureTrailingSlash(url);
+ }
+
+ ///
+ /// Combines multiple URL segments into a single path, ensuring proper slashes.
+ ///
+ public static string PathCombine(params string[] segments) // Move it to Netmash
+ {
+ var parts = segments
+ .Where(s => !string.IsNullOrEmpty(s))
+ .Select(s => s.Trim())
+ .ToArray();
+ if (parts.Length == 0) return string.Empty;
+ if (parts.Length == 1) return parts[0];
+
+ var result = parts[0].TrimEnd('/');
+ for (int i = 1; i < parts.Length; i++)
+ {
+ var seg = parts[i].Trim('/');
+ if (seg.Length > 0) result += "/" + seg;
+ }
+ return result;
+ }
}
}
diff --git a/src/clients/dotnet/Bitip.Client/Services/BitipClient.cs b/src/clients/dotnet/Bitip.Client/Services/BitipClient.cs
index f08e0e6..20d4b9a 100644
--- a/src/clients/dotnet/Bitip.Client/Services/BitipClient.cs
+++ b/src/clients/dotnet/Bitip.Client/Services/BitipClient.cs
@@ -22,7 +22,7 @@ namespace Bitip.Client.Services
public BitipClient(HttpClient httpClient, IOptions options)
{
- httpClient.BaseAddress = UriNormalizer.EnsureTrailingSlash(options.Value.BaseUrl);
+ httpClient.BaseAddress = UriNormalizer.EnsureTrailingSlash(options.Value.BaseUrl, "/api");
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
httpClient.DefaultRequestHeaders.Add(ApiKeys.HttpHeader, options.Value.ApiKey);