Come si imposta l’intestazione Content-Type per una richiesta HttpClient?

Sto cercando di impostare l’intestazione Content-Type di un object HttpClient come richiesto da un’API che sto chiamando.

Ho provato ad impostare il Content-Type come di seguito:

 using (var httpClient = new HttpClient()) { httpClient.BaseAddress = new Uri("http://example.com/"); httpClient.DefaultRequestHeaders.Add("Accept", "application/json"); httpClient.DefaultRequestHeaders.Add("Content-Type", "application/json"); // ... } 

Mi permette di aggiungere l’intestazione Accept , ma quando provo ad aggiungere Content-Type getta la seguente eccezione:

Nome dell’intestazione misused. Assicurati che le intestazioni di richiesta vengano utilizzate con HttpRequestMessage , le intestazioni di risposta con HttpResponseMessage e le intestazioni di contenuto con oggetti HttpContent .

Come posso impostare l’intestazione Content-Type in una richiesta HttpClient ?

Il tipo di contenuto è un’intestazione del contenuto, non della richiesta, motivo per cui questo non funziona. AddWithoutValidation come suggerito da Robert Levy potrebbe funzionare, ma puoi anche impostare il tipo di contenuto quando crei il contenuto della richiesta stessa (nota che lo snippet di codice aggiunge “application / json” in due punti, per le intestazioni Accept e Content-Type):

 HttpClient client = new HttpClient(); client.BaseAddress = new Uri("http://example.com/"); client.DefaultRequestHeaders .Accept .Add(new MediaTypeWithQualityHeaderValue("application/json"));//ACCEPT header HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, "relativeAddress"); request.Content = new StringContent("{\"name\":\"John Doe\",\"age\":33}", Encoding.UTF8, "application/json");//CONTENT-TYPE header client.SendAsync(request) .ContinueWith(responseTask => { Console.WriteLine("Response: {0}", responseTask.Result); }); 

Per coloro che non hanno visto il commento di John alla soluzione di Carlos …

 req.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream"); 

Se non ti dispiace una dipendenza da una piccola biblioteca, Flurl.Http [la divulgazione: io sono l’autore] rende questo super-semplice. Il suo metodo PostJsonAsync si occupa sia della serializzazione del contenuto che dell’impostazione dell’intestazione del content-type , e ReceiveJson deserializza la risposta. Se è richiesta l’intestazione di accept , dovrai impostarla tu stesso, ma Flurl fornisce un modo abbastanza semplice per farlo:

 using Flurl.Http; var result = await "http://example.com/" .WithHeader("Accept", "application/json") .PostJsonAsync(new { ... }) .ReceiveJson(); 

Flurl usa HttpClient e Json.NET sotto il cofano, ed è un PCL quindi funzionerà su una varietà di piattaforms.

 PM> Install-Package Flurl.Http 

prova ad usare TryAddWithoutValidation

  var client = new HttpClient(); client.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "application/json; charset=utf-8"); 

Chiama AddWithoutValidation anziché Add (vedi questo link MSDN ).

In alternativa, suppongo che l’API che stai usando richieda realmente questo solo per le richieste POST o PUT (non per le richieste GET ordinarie). In tal caso, quando chiami HttpClient.PostAsync e passi in un HttpContent , imposta questo nella proprietà Headers di quell’object HttpContent .

.Net cerca di forzare l’utente a rispettare determinati standard, vale a dire che l’intestazione Content-Type può essere specificata solo su richieste con contenuto (ad esempio POST , PUT , ecc.). Pertanto, come altri hanno indicato, il modo preferito per impostare l’intestazione Content-Type è attraverso la proprietà HttpContent.Headers.ContentType .

Detto questo, alcune API (come ad esempio LiquidFiles Api , a partire dal 2016-12-19) richiedono l’impostazione dell’intestazione Content-Type per una richiesta GET . .Net non consentirà l’impostazione di questa intestazione sulla richiesta stessa – anche utilizzando TryAddWithoutValidation . Inoltre, non è ansible specificare un Content per la richiesta, anche se è di lunghezza zero. L’unico modo in cui potevo aggirare questo era ricorrere alla riflessione. Il codice (nel caso ce ne sia bisogno qualcun altro) lo è

 var field = typeof(System.Net.Http.Headers.HttpRequestHeaders) .GetField("invalidHeaders", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static) ?? typeof(System.Net.Http.Headers.HttpRequestHeaders) .GetField("s_invalidHeaders", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static); if (field != null) { var invalidFields = (HashSet)field.GetValue(null); invalidFields.Remove("Content-Type"); } _client.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "text/xml"); 

Modificare:

Come notato nei commenti, questo campo ha nomi diversi nelle diverse versioni della dll. Nel codice sorgente su GitHub , il campo è attualmente denominato s_invalidHeaders . L’esempio è stato modificato per tener conto di ciò secondo il suggerimento di @David Thompson.

Alcune informazioni aggiuntive su .NET Core (dopo aver letto il post di Erdomke sull’impostazione di un campo privato per fornire il tipo di contenuto su una richiesta che non ha contenuto) …

Dopo aver eseguito il debug del mio codice, non riesco a vedere il campo privato da impostare tramite la riflessione, quindi ho pensato di provare a ricreare il problema.

Ho provato il seguente codice usando .Net 4.6:

 HttpRequestMessage httpRequest = new HttpRequestMessage(HttpMethod.Get, @"myUrl"); httpRequest.Content = new StringContent(string.Empty, Encoding.UTF8, "application/json"); HttpClient client = new HttpClient(); Task response = client.SendAsync(httpRequest); //I know I should have used async/await here! var result = response.Result; 

E, come previsto, ottengo un’eccezione aggregata con il contenuto "Cannot send a content-body with this verb-type."

Tuttavia, se faccio la stessa cosa con .NET Core (1.1) – Non ottengo un’eccezione. La mia richiesta è stata soddisfacentemente soddisfatta dalla mia applicazione server e il tipo di contenuto è stato rilevato.

Sono rimasto piacevolmente sorpreso da questo, e spero che aiuti qualcuno!

Ok, non è HTTPClient ma se puoi usarlo, WebClient è abbastanza semplice:

 using (var client = new System.Net.WebClient()) { client.Headers.Add("Accept", "application/json"); client.Headers.Add("Content-Type", "application/json; charset=utf-8"); client.DownloadString(...); } 
 var content = new HttpContent(); content.Headers.ContentType = new MediaTypeHeaderValue("application/json"); content.Headers.ContentType.Parameters.Add(new NameValueHeaderValue("charset", "utf-8")); content.Headers.ContentType.Parameters.Add(new NameValueHeaderValue("IEEE754Compatible", "true")); 

È tutto ciò di cui hai bisogno.