¿Por qué Content-Type es el dolor de cabeza de todo desarrollador C#?
\n\n¿Alguna vez ha enviado una solicitud POST a través de HttpClient en C# y el servidor le respondió con un misterioso error 415 (Unsupported Media Type)? Le suena, ¿verdad? La mayoría de las veces, el problema radica en un encabezado pequeño pero críticamente importante: Content-Type. Sin él, el servidor simplemente no sabe cómo interpretar sus datos: ¿son JSON, XML o un formulario normal?
En este artículo, analizaremos cómo establecer correctamente Content-Type para HttpClient en C#, veremos los errores más comunes que cometen los principiantes (y no solo ellos), y aprenderemos a enviar solicitudes para que el servidor lo entienda a la perfección. ¡Allá vamos!
\n\n¿Qué es Content-Type y para qué sirve?
\n\nContent-Type es un encabezado HTTP que indica al servidor en qué formato se envían los datos en el cuerpo de la solicitud (o respuesta). Si envía JSON, debe decir: application/json. Si es XML — application/xml. Si son datos de formulario — application/x-www-form-urlencoded.
En C#, HttpClient es una herramienta potente pero traicionera. Puede adivinar el formato por sí mismo, o puede que no. Y si intenta simplemente agregar el encabezado a través de DefaultRequestHeaders, le espera una sorpresa desagradable: Content-Type no es parte de los encabezados de solicitud predeterminados. Solo pertenece al cuerpo de la solicitud.
Error típico de principiante
\n\nvar client = new HttpClient();\nclient.DefaultRequestHeaders.Add("Content-Type", "application/json"); // ❌ ¡ERROR!\n\n\nEste código generará una excepción InvalidOperationException con el mensaje: "Misused header name. Make sure request headers are used with HttpRequestMessage, response ones with HttpResponseMessage, and content ones with HttpContent objects." Suena aterrador, pero la solución es simple: siga leyendo.
Tres formas de establecer Content-Type en C# HttpClient
\n\nForma 1: Usar StringContent (la más sencilla)
\n\nLa forma más popular y correcta es pasar el encabezado junto con el cuerpo de la solicitud a través de la clase StringContent.
using System;\nusing System.Net.Http;\nusing System.Text;\nusing System.Threading.Tasks;\n\nclass Program\n{\n static async Task Main()\n {\n var client = new HttpClient();\n var json = "{ \\"name\\": \\"PythonLib\\", \\"type\\": \\"education\\" }";\n \n // Creamos el contenido indicando explícitamente el Content-Type\n var content = new StringContent(json, Encoding.UTF8, "application/json");\n \n var response = await client.PostAsync("https://api.example.com/data", content);\n Console.WriteLine(await response.Content.ReadAsStringAsync());\n }\n}\n\n\nEn este ejemplo, Content-Type: application/json; charset=utf-8 se establece automáticamente. El segundo parámetro (Encoding.UTF8) define la codificación, el tercero el tipo de medio. ¡Voilà — el servidor está contento!
Forma 2: A través de ByteArrayContent (para avanzados)
\n\nSi trabaja con datos binarios o desea tener control total, use ByteArrayContent.
using System.Net.Http;\nusing System.Text;\n\nvar jsonBytes = Encoding.UTF8.GetBytes("{ \\"message\\": \\"Hello\\" }");\nvar content = new ByteArrayContent(jsonBytes);\ncontent.Headers.ContentType = new MediaTypeHeaderValue("application/json");\n\nvar response = await client.PostAsync("https://api.example.com/upload", content);\n\n\nAquí establecemos manualmente ContentType a través de la propiedad Headers. Esta forma es útil cuando necesita agregar encabezados adicionales (por ejemplo, Content-Encoding).
Forma 3: HttpRequestMessage + control total
\n\nA veces es necesario enviar una solicitud GET con cuerpo (sí, también se puede) o sobrescribir los encabezados a nivel de solicitud. Entonces en el bo