¿Cómo se establece el encabezado Content-Type para una solicitud de HttpClient?

Estoy tratando de establecer el encabezado Content-Type de un objeto HttpClient como lo requiere una API a la que estoy llamando.

Intenté configurar el tipo de Content-Type como a continuación:

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

Me permite agregar el encabezado Accept pero cuando bash agregar Content-Type arroja la siguiente excepción:

Nombre del encabezado mal usado. Asegúrese de que los encabezados de solicitud se utilicen con HttpRequestMessage , los encabezados de respuesta con HttpResponseMessage y los encabezados de contenido con los objetos HttpContent .

¿Cómo puedo configurar el encabezado Content-Type en una solicitud de HttpClient ?

El tipo de contenido es un encabezado del contenido, no de la solicitud, razón por la cual está fallando. AddWithoutValidation tal como lo sugirió Robert Levy puede funcionar, pero también puede establecer el tipo de contenido cuando crea el contenido de la solicitud (observe que el fragmento de código agrega “application / json” en dos lugares para los encabezados Accept y 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); }); 

Para aquellos que no vieron a Johns comentar a la solución de Carlos …

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

Si no te importa una pequeña dependencia de la biblioteca, Flurl.Http [revelación: soy el autor] hace que esto sea súper simple. Su método PostJsonAsync se encarga de serializar el contenido y configurar el encabezado de content-type , y ReceiveJson deserializa la respuesta. Si se requiere el encabezado de accept , tendrá que configurarlo usted mismo, pero Flurl proporciona una forma bastante limpia de hacerlo también:

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

Flurl usa HttpClient y Json.NET bajo el capó, y es una PCL, por lo que funcionará en una variedad de plataformas.

 PM> Install-Package Flurl.Http 

intente utilizar TryAddWithoutValidation

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

Llame a AddWithoutValidation lugar de Add (consulte este enlace de MSDN ).

Alternativamente, supongo que la API que está utilizando realmente solo requiere esto para solicitudes POST o PUT (no solicitudes GET ordinarias). En ese caso, cuando llama a HttpClient.PostAsync y pasa un HttpContent , HttpContent en la propiedad Headers de ese objeto HttpContent .

.Net intenta obligarlo a obedecer ciertos estándares, a saber, que el encabezado Content-Type solo se puede especificar en las solicitudes que tienen contenido (por ejemplo, POST , PUT , etc.). Por lo tanto, como han indicado otros, la forma preferida de establecer el encabezado Content-Type es a través de la propiedad HttpContent.Headers.ContentType .

Dicho esto, ciertas API (como LiquidFiles Api , desde 2016-12-19) requieren establecer el encabezado Content-Type para una solicitud GET . .Net no permitirá establecer este encabezado en la solicitud en sí, incluso utilizando TryAddWithoutValidation . Además, no puede especificar un Content para la solicitud, incluso si es de longitud cero. La única forma en que podía evitarlo era recurrir a la reflexión. El código (en caso de que otros lo necesiten) es

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

Editar:

Como se señaló en los comentarios, este campo tiene diferentes nombres en diferentes versiones de la dll. En el código fuente en GitHub , el campo actualmente se llama s_invalidHeaders . El ejemplo ha sido modificado para dar cuenta de esto según la sugerencia de @David Thompson.

Alguna información adicional sobre .NET Core (después de leer la publicación de erdomke sobre la configuración de un campo privado para suministrar el tipo de contenido en una solicitud que no tiene contenido) …

Después de depurar mi código, no puedo ver el campo privado para establecer a través de la reflexión, así que pensé en intentar recrear el problema.

He intentado el siguiente código 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; 

Y, como esperaba, obtengo una excepción agregada con el contenido "Cannot send a content-body with this verb-type."

Sin embargo, si hago lo mismo con .NET Core (1.1), no obtengo una excepción. Mi solicitud fue respondida muy feliz por mi aplicación de servidor, y el tipo de contenido fue recogido.

Me sorprendió gratamente, ¡y espero que ayude a alguien!

Ok, no es HTTPClient, pero si puedes usarlo, WebClient es bastante fácil:

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

Es todo lo que necesitas.