'HttpClient Modifies BaseAddress in Some Cases [duplicate]

On a basic level, I should be able to set an absolute BaseAddress on HttpClient and then send Http requests with a relative Uri. The expectation is that the relative Uri would append on to the base address to make the Http call. It does this in most cases. This example works fine.

Edit: see the bottom. This appears to be weird behavior in the way Uris are constructed.

var httpClient = new HttpClient() { BaseAddress = new Uri("http://restcountries.eu/rest/", UriKind.Absolute) };
var requestMessage = new HttpRequestMessage(HttpMethod.Get, new Uri("v2", UriKind.Relative));
var httpResponseMessage = await httpClient.SendAsync(requestMessage);
var json = await httpResponseMessage.Content.ReadAsStringAsync();

Fiddler url:

GET http://restcountries.eu/rest/v2 HTTP/1.1

I have a local API. When I run the equivalent on my local API, the call truncates part of the base address ("Api").

var httpClient = new HttpClient() { BaseAddress = new Uri($"http://localhost/JsonPerson/Api", UriKind.Absolute) };
var requestMessage = new HttpRequestMessage(HttpMethod.Get, new Uri("GetApiPerson", UriKind.Relative));
var httpResponseMessage = await httpClient.SendAsync(requestMessage);
var json = await httpResponseMessage.Content.ReadAsStringAsync();

Fiddler url:

GET http://localhost/JsonPerson/GetApiPerson HTTP/1.1

Why does is it remove "/Api" ?

This code hits the local API and works fine:

var httpClient = new HttpClient() { BaseAddress = new Uri($"http://localhost/JsonPerson/", UriKind.Absolute) };
var requestMessage = new HttpRequestMessage(HttpMethod.Get, new Uri("Api/GetApiPerson", UriKind.Relative));
var httpResponseMessage = await httpClient.SendAsync(requestMessage);
var json = await httpResponseMessage.Content.ReadAsStringAsync();

Fiddler url:

GET http://localhost/JsonPerson/Api/GetApiPerson HTTP/1.1

This is a bizarre problem and I can't figure out why I get these inconsistencies... Is it treating the uri differently for local and non local uris? What am I missing here?

This is .NET Core 3.1

Look at this code, and then have a look at the output. This is what HttpClient is doing behind the scenes.

using System;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    class Program
    {
        static async Task Main(string[] args)
        {
            var baseAddress = new Uri($"http://restcountries.eu/JsonPerson/Api", UriKind.Absolute);
            var resourceUri = new Uri($"GetApiPerson", UriKind.Relative);
            Console.WriteLine(new Uri(baseAddress, resourceUri));

            baseAddress = new Uri($"http://restcountries.eu/JsonPerson", UriKind.Absolute);
            resourceUri = new Uri($"Api/GetApiPerson", UriKind.Relative);
            Console.WriteLine(new Uri(baseAddress, resourceUri));

            baseAddress = new Uri($"http://restcountries.eu/rest/", UriKind.Absolute);
            resourceUri = new Uri($"v2", UriKind.Relative);
            Console.WriteLine(new Uri(baseAddress, resourceUri));
        }
    }
}

Output

http://restcountries.eu/JsonPerson/GetApiPerson

http://restcountries.eu/Api/GetApiPerson

http://restcountries.eu/rest/v2

It turns out that this thing seems to have something to do with it...

https://github.com/microsoft/referencesource/blob/f461f1986ca4027720656a0c77bede9963e20b7e/System/net/System/UriExt.cs#L742



Solution 1:[1]

Putting a slash on the end of the BaseAddress resolves the issue.

However, this kind of seems like a bug in Uri to me. I'm sure this trips up tonnes of people.

I created a library called Urls which addresses this issue. Urls are immutable and you don't have to construct them with strings.

RestClient.Net is a REST/HTTP client library that uses these urls. You can read more about the issue here.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1