Perché HttpClient BaseAddress non funziona?

Si consideri il seguente codice, in cui BaseAddress definisce un percorso URI parziale.

 using (var handler = new HttpClientHandler()) using (var client = new HttpClient(handler)) { client.BaseAddress = new Uri("http://something.com/api"); var response = await client.GetAsync("/resource/7"); } 

Mi aspetto che esegua una richiesta GET su http://something.com/api/resource/7 . Ma non è così.

Dopo alcune ricerche, trovo questa domanda e risposta: HttpClient con BaseAddress . Il suggerimento è di posizionare / alla fine di BaseAddress .

 using (var handler = new HttpClientHandler()) using (var client = new HttpClient(handler)) { client.BaseAddress = new Uri("http://something.com/api/"); var response = await client.GetAsync("/resource/7"); } 

Ancora non funziona. Ecco la documentazione: HttpClient.BaseAddress Cosa sta succedendo qui?

Si scopre che, tra le quattro possibili permutazioni di includere o escludere il trailing o condurre le barre in avanti su BaseAddress e l’URI relativo passato al metodo GetAsync – o qualunque altro metodo di HttpClient – funziona solo una permutazione. È necessario posizionare una barra alla fine di BaseAddress e non si deve posizionare una barra all’inizio dell’URI relativo, come nell’esempio seguente.

 using (var handler = new HttpClientHandler()) using (var client = new HttpClient(handler)) { client.BaseAddress = new Uri("http://something.com/api/"); var response = await client.GetAsync("resource/7"); } 

Anche se ho risposto alla mia domanda, ho pensato di contribuire alla soluzione qui, poiché, ancora una volta, questo comportamento ostile non è documentato. Il mio collega e io abbiamo trascorso la maggior parte della giornata cercando di risolvere un problema che alla fine è stato causato da questa stranezza di HttpClient .

La risoluzione di riferimento è descritta da RFC 3986 Uniform Resource Identifier (URI): Sintassi generica . E questo è esattamente come dovrebbe funzionare. Per preservare il percorso dell’URI di base è necessario aggiungere una barra alla fine dell’URI di base e rimuovere la barra all’inizio dell’URI relativo.

Se l’URI di base contiene un percorso non vuoto, la procedura di unione elimina la sua ultima parte (dopo l’ultima / ). Sezione pertinente:

5.2.3. Unisci percorsi

Lo pseudocodice di cui sopra fa riferimento a una routine di “unione” per unire un riferimento di percorso relativo con il percorso dell’URI di base. Questo è realizzato come segue:

  • Se l’URI di base ha un componente di authorization definito e un percorso vuoto, restituisce una stringa composta da “/” concatenata con il percorso del riferimento; altrimenti

  • restituisce una stringa consistente nel componente del percorso del riferimento aggiunto a tutto tranne l’ultimo segmento del percorso dell’URI di base (ovvero, escludendo qualsiasi carattere dopo il “/” più a destra nel percorso URI di base o escludendo l’intero percorso URI di base se esso non contiene alcun carattere “/”).

Se l’URI relativo inizia con una barra, viene chiamato URI relativo del percorso assoluto. In questo caso, la procedura di unione ignora tutto il percorso URI di base. Per maggiori informazioni, consultare 5.2.2. Trasforma la sezione Riferimenti .

In alternativa, non utilizzare affatto BaseAddress . Metti l’intero URL in GetAsync ()