PUBLICAR JsonObject con HttpClient desde la API web

288

Estoy tratando de publicar un JsonObjectuso HttpClientde la API web. No estoy muy seguro de cómo hacer esto y no puedo encontrar mucho en el camino del código de muestra.

Esto es lo que tengo hasta ahora:

var myObject = (dynamic)new JsonObject();
myObject.Data = "some data";
myObject.Data2 = "some more data";

HttpClient httpClient = new HttpClient("myurl");
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

HttpResponseMessage response = httpClient.Post("", ???);

Creo que necesito lanzar mi JsonObjectcomo un StreamContentpero estoy colgado en ese paso.

marca
fuente

Respuestas:

440

Con la nueva versión de HttpClienty sin el WebApipaquete sería:

var content = new StringContent(jsonObject.ToString(), Encoding.UTF8, "application/json");
var result = client.PostAsync(url, content).Result;

O si lo quieres async:

var result = await client.PostAsync(url, content);
pomber
fuente
3
Ese sobrecargado constructor de StringContent hizo el truco por mí.
Capitán Kenpachi
23
Piénselo dos veces antes de llamar a Result en un método Async a través de blog.stephencleary.com/2012/07/dont-block-on-async-code.html
Ruchira
2
Para cualquiera que estuviese tentado a tirar esto de la misma forma usingque yo: aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong
maxshuty
Sin embargo, puse una usingvuelta a la StringContentcreación.
bcr
Usando esta respuesta, recibí una respuesta de "400 Solicitud incorrecta" de una API en la que estaba PUBLICANDO mi solicitud JSON (Visual Studio 2017, .NET 4.6.2). Además de var content = new StringContent(jsonObject.ToString(), Encoding.UTF8, "application/json")que tuve que configurar content.Headers.ContentType = new MediaTypeHeaderValue("application/json");. Vea la respuesta a continuación para más detalles.
anthls
161

La forma más fácil es usar a StringContent, con la representación JSON de su objeto JSON.

httpClient.Post(
    "",
    new StringContent(
        myObject.ToString(),
        Encoding.UTF8,
        "application/json"));
carlosfigueira
fuente
14
Tome nota sobre el tipo de contenido. Lo dejé fuera y me puse a depurar durante mucho más tiempo del que me gustaría.
Zapnologica
¿No deberías descartar la instancia de StringContent?
Phil Haselden
63

Dependiendo de su versión .NET, también podría usar el HttpClientExtensions.PostAsJsonAsyncmétodo.

https://msdn.microsoft.com/en-us/library/system.net.http.httpclientextensions.postasjsonasync.aspx

usuario3285954
fuente
44
Ahora se encuentra en Microsoft.AspNet.Client.WebApi nuget
jle
2
Lo acabo de instalar desde Microsoft.AspNet.WebApi.Client
Adriaan Davel el
Esto resolvió mi problema. Estuve jugando durante un (largo) mientras pasaba una clase de C # que contenía algunas propiedades que eran Listas usando client.PostAsync, client.SendAsync ... Obtuve resultados muy mixtos. Si la matriz estuviera vacía, mi solución API la recogería, pero si la matriz tuviera un elemento, el método del controlador no podría modelar el JSON. Gracias por esto. Me parece que PostAsJsonAsync convierte de manera más confiable un objeto complejo de C # a JSON.
Franklin Tarter
¿Hay un paquete nuget para esto? Odio cuando transfiero el proyecto a una nueva máquina, y esta referencia siempre falta.
Zapnologica
Buscando esto o algo más? nuget.org/packages/Microsoft.AspNet.WebApi.Client
user3285954
51

Si usa Newtonsoft.Json:

using Newtonsoft.Json;
using System.Net.Http;
using System.Text;

public static class Extensions
{
    public static StringContent AsJson(this object o)
        => new StringContent(JsonConvert.SerializeObject(o), Encoding.UTF8, "application/json");
}

Ejemplo:

var httpClient = new HttpClient();
var url = "https://www.duolingo.com/2016-04-13/login?fields=";
var data = new { identifier = "username", password = "password" };
var result = await httpClient.PostAsync(url, data.AsJson())
Matthew Steven Monkan
fuente
esto no es específico del núcleo asp.net, en realidad es genérico hasta 4.5.6
danatcofo
JsonConvert.SerializeObjectproblemas con DateTimes ISO 8601 Tipo: Local o UTC ... hackered.co.uk/articles/…
Kiquenet
21

No tengo suficiente reputación para agregar un comentario sobre la respuesta de pomber, así que estoy publicando otra respuesta. Utilizando el enfoque de pomber, recibí una respuesta de "400 solicitudes incorrectas" de una API en la que estaba PUBLICANDO mi solicitud JSON (Visual Studio 2017, .NET 4.6.2). Finalmente, el problema se rastreó hasta que el encabezado "Content-Type" producido por StringContent () era incorrecto (consulte https://github.com/dotnet/corefx/issues/7864 ).

tl; dr

Use la respuesta de pomber con una línea adicional para establecer correctamente el encabezado de la solicitud:

var content = new StringContent(jsonObject.ToString(), Encoding.UTF8, "application/json");
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
var result = client.PostAsync(url, content).Result;
anthls
fuente
Gracias Anthls. var content = new StringContent (jsonObject.ToString (), Encoding.UTF8, "application / json") no fue suficiente. Necesita content.Headers.ContentType = new MediaTypeHeaderValue ("application / json"); Gracias por salvar mi cordura.
Gail Foad
1
Esto funcionó muy bien. ¿Alguna razón por la cual "application / json" debe establecerse dos veces, una en el constructor y otra a través de la propiedad? ¿Es un error?
Festus Martingale
@FestusMartingale: ¡buena pregunta! Según mi lectura de la cuestión de github (vinculada en la respuesta), probablemente no sea necesario pasar "application/json"al StringContentconstructor, ya que se establece explícitamente en la content.Headers.ContentTypepropiedad resultante . Sin embargo, no he probado esto en código.
anthls
Parece que el servidor no admite la cadena de tipo de contenido completo. Cuando usa el constructor sin anular ContentType, establece el valor como application/json; charset=utf-8.
Bertm13
2

el código sobre él en vbnet:

dim FeToSend as new (object--> define class)

Dim client As New HttpClient
Dim content = New StringContent(FeToSend.ToString(), Encoding.UTF8,"application/json")
content.Headers.ContentType = New MediaTypeHeaderValue( "application/json" )
Dim risp = client.PostAsync(Chiamata, content).Result

msgbox(risp.tostring)

Espero que esto ayude

Stefano Ronchese
fuente