2012-05-21 392 views
414

estoy tratando de establecer la cabecera Content-Type de un objeto HttpClient como es requerido por una API que estoy llamando.¿Cómo se configura el encabezado Content-Type para una solicitud de HttpClient?

He intentado establecer el 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 añadir la cabecera Accept pero cuando intento agregar Content-Type que arroja la siguiente excepción:

nombre de encabezado de un mal uso. Asegúrese de que los encabezados de solicitud se utilizan con HttpRequestMessage, encabezados de respuesta con HttpResponseMessage y encabezados de contenido con HttpContent objetos.

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

Respuesta

513

El tipo de contenido es una cabecera del contenido, no de la solicitud, por lo que este está fallando. AddWithoutValidation según lo sugerido por Robert Levy puede funcionar, pero también puede establecer el tipo de contenido al crear el contenido de solicitud mismo (tenga en cuenta que el fragmento de código agrega "aplicación/json" en dos lugares para los encabezados Aceptar y Contenido):

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); 
     }); 
+18

Alternativamente, 'Response.Content.Headers' funcionará la mayor parte del tiempo. –

+2

@AshishJain La mayoría de las respuestas SO que he visto que envuelven 'Response.Content.Headers' para ASP.Net Web API tampoco han funcionado, pero se puede configurar fácilmente usando' HttpContext.Current.Response.ContentType' if necesitas. – jerhewet

+4

@jerhewet lo usé de la siguiente manera que funcionó para mí. var content = new StringContent (data, Encoding.UTF8, "application/json"); –

14

Llamada AddWithoutValidation en lugar de Add (mira this MSDN link).

Alternativamente, supongo que la API está utilizando realmente sólo requiere esto para peticiones POST o PUT (no peticiones GET ordinarias). En ese caso, cuando se llama HttpClient.PostAsync y pasas en un HttpContent, ajuste este en la propiedad de ese HeadersHttpContent objeto.

+1

AddWithoutValidation arroja el mismo error – mynameiscoffey

+0

no funciona .... –

+0

no funciona me da un 'Nombre de 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 objetos HttpContent. ' –

91

para aquellos que no vieron Johns comentario a carlos solución ...

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

Hacía la diferencia descargando un pdf. Desde el teléfono, intentó descargar un HTML. Después de convertir la extensión, el archivo normalmente estaba codificado. –

+0

Tuve que tirar.ToString() al final, pero sí, esto funcionó para la implementación de un servicio WCF. –

33

Si no te importa una pequeña dependencia de la biblioteca, Flurl.Http [divulgación: soy el autor] hace que este súper-simple. Su método PostJsonAsync se encarga de serializar tanto el contenido y la configuración de la cabecera content-type y ReceiveJson deserializa la respuesta. Si se requiere la cabecera accept tendrá que establecer que usted mismo, pero Flurl proporciona una forma muy limpia para hacer eso también:

using Flurl.Http; 

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

Flurl utiliza HttpClient y Json.NET bajo el capó, y es un modo PCL Funcionará en una variedad de plataformas.

PM> Install-Package Flurl.Http 
+0

¿Cómo enviar si el contenido es application/x-www-form-urlencoded? –

+0

@Vlado use 'PostUrlEncodedAsync'. http://tmenier.github.io/Flurl/fluent-http/ –

21

intenta utilizar TryAddWithoutValidation

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

no funciona .... –

+0

no funciona me da un 'Nombre de 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 objetos HttpContent. ' –

11

.Net intenta obligar a obedecer ciertas normas, a saber, que la cabecera Content-Type sólo se puede especificar en las solicitudes que tienen contenido (por ejemplo POST, PUT , etc.) Por lo tanto, como otros han indicado, la forma preferida para establecer la cabecera Content-Type es a través de la propiedad HttpContent.Headers.ContentType.

Dicho esto, ciertas APIs (como el LiquidFiles Api, como de 12.19.2016) requiere el establecimiento de la cabecera Content-Type para una solicitud GET. .Net no permitirá establecer este encabezado en la solicitud en sí, incluso usando 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 alguna otra persona lo necesita) 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<string>)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 source code on 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.

+0

No funciona con .Net Framework versión 4.0, System.Net.Http versión 2.2.29.0 pero funciona con 2.0.0.0 – prem

+0

Este campo ahora es s_invalidHeaders, por lo que si utiliza lo siguiente se garantiza la compatibilidad: 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); –

+0

Agregó una respuesta relacionada con esto para .NET Core 1.1 – Jay

9

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

Después de la depuración de 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 probado el siguiente código utilizando .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<HttpResponseMessage> response = client.SendAsync(httpRequest); //I know I should have used async/await here! 
var result = response.Result; 

Y, como era de esperar, me sale una excepción agregada con el contenido "Cannot send a content-body with this verb-type."

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

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

+1

Gracias, Jay - No utiliza core, y usará la respuesta de erdomke. Aprecio saber que se han intentado todas las avenidas razonables :). –

+0

funciona bien en .NET Core de hecho, gracias! –

+0

no funciona .net 4 ({"No se puede enviar un cuerpo de contenido con este tipo de verbo".}) –

Cuestiones relacionadas