Comment définissez-vous l’en-tête Content-Type pour une requête HttpClient?

J’essaie de définir l’en Content-Type tête Content-Type d’un object HttpClient comme requirejs par une API que HttpClient .

J’ai essayé de définir le type de Content-Type comme ci-dessous:

 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"); // ... } 

Cela me permet d’append l’en-tête Accept mais lorsque j’essaie d’append Content-Type il génère l’exception suivante:

Nom d’en-tête mal utilisé. Assurez-vous que les en-têtes de requête sont utilisés avec HttpRequestMessage , les en-têtes de réponse avec HttpResponseMessage et les en-têtes de contenu avec des objects HttpContent .

Comment puis-je définir l’en Content-Type tête Content-Type dans une requête HttpClient ?

Le type de contenu est un en-tête du contenu et non de la demande, ce qui explique son échec. AddWithoutValidation comme suggéré par Robert Levy, peut fonctionner, mais vous pouvez également définir le type de contenu lors de la création du contenu de la requête (notez que l’extrait de code ajoute “application / json” dans deux emplacements pour les en-têtes Accept et 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 SsortingngContent("{\"name\":\"John Doe\",\"age\":33}", Encoding.UTF8, "application/json");//CONTENT-TYPE header client.SendAsync(request) .ContinueWith(responseTask => { Console.WriteLine("Response: {0}", responseTask.Result); }); 

Pour ceux qui n’ont pas vu Johns commenter carlos solution …

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

Si cela ne vous dérange pas une petite dépendance à la bibliothèque, Flurl.Http [divulgation: je suis l’auteur] rend cette tâche très simple. Sa méthode PostJsonAsync prend en charge à la fois la sérialisation du contenu et la définition de l’ content-type tête content-type , et ReceiveJson désérialise la réponse. Si l’en-tête d’ accept est requirejs, vous devez le définir vous-même, mais Flurl offre une méthode assez simple pour le faire:

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

Flurl utilise HttpClient et Json.NET sous le capot, et il s’agit d’une PCL qui fonctionnera sur diverses plates-formes.

 PM> Install-Package Flurl.Http 

essayez d’utiliser TryAddWithoutValidation

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

Appelez AddWithoutValidation au lieu de Add (voir ce lien MSDN ).

Sinon, je suppose que l’API que vous utilisez n’a besoin que de cela pour les requêtes POST ou PUT (pas les requêtes GET ordinaires). Dans ce cas, lorsque vous appelez HttpClient.PostAsync et que vous transmettez un HttpContent , définissez-le sur la propriété Headers de cet object HttpContent .

.Net essaie de vous forcer à respecter certaines normes, à savoir que l’en Content-Type tête Content-Type ne peut être spécifié que pour les requêtes qui ont du contenu (par exemple, POST , PUT , etc.). Par conséquent, comme d’autres l’ont indiqué, la méthode préférée pour définir l’en Content-Type tête Content-Type passe par la propriété HttpContent.Headers.ContentType .

Cela étant dit, certaines API (telles que LiquidFiles Api , à partir du 19/12/2016) nécessitent de définir l’en Content-Type tête Content-Type pour une requête GET . .Net ne permettra pas de définir cet en-tête sur la demande elle-même – même en utilisant TryAddWithoutValidation . De plus, vous ne pouvez pas spécifier un Content pour la demande, même s’il est de longueur nulle. La seule façon de contourner cela était de recourir à la reflection. Le code (au cas où une autre en aurait besoin) est

 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"); 

Modifier:

Comme indiqué dans les commentaires, ce champ a des noms différents dans les différentes versions de la DLL. Dans le code source sur GitHub , le champ est actuellement nommé s_invalidHeaders . L’exemple a été modifié pour en tenir compte selon la suggestion de @David Thompson.

Quelques informations supplémentaires sur .NET Core (après avoir lu la publication d’erdomke sur la définition d’un champ privé pour fournir le type de contenu sur une requête sans contenu) …

Après avoir débogué mon code, je ne peux pas voir le champ privé définir via la reflection – alors j’ai pensé essayer de recréer le problème.

J’ai essayé le code suivant en utilisant .Net 4.6:

 HttpRequestMessage httpRequest = new HttpRequestMessage(HttpMethod.Get, @"myUrl"); httpRequest.Content = new SsortingngContent(ssortingng.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; 

Et, comme prévu, je reçois une exception globale avec le contenu "Cannot send a content-body with this verb-type."

Cependant, si je fais la même chose avec .NET Core (1.1) – je ne reçois pas d’exception. Ma demande de serveur a été très satisfaisante, et le type de contenu a été choisi.

Cela m’a agréablement surpris et j’espère que cela aidera quelqu’un!

Ok, ce n’est pas HTTPClient mais si vous pouvez l’utiliser, WebClient est assez simple:

 using (var client = new System.Net.WebClient()) { client.Headers.Add("Accept", "application/json"); client.Headers.Add("Content-Type", "application/json; charset=utf-8"); client.DownloadSsortingng(...); } 
 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")); 

C’est tout ce dont vous avez besoin.