POSTANDO JsonObject com HttpClient da API da Web

288

Eu estou tentando postar uma JsonObjectutilização HttpClientda Web API. Não tenho muita certeza de como proceder e não consigo encontrar muita coisa no código de exemplo.

Aqui está o que eu tenho até agora:

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("", ???);

Eu acho que preciso interpretar o meu JsonObjectcomo um, StreamContentmas estou ficando preso nesse passo.

Marca
fonte

Respostas:

440

Com a nova versão HttpCliente sem o WebApipacote, seria:

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

Ou se você quiser async:

var result = await client.PostAsync(url, content);
pomber
fonte
3
Esse construtor StringContent sobrecarregado fez o truque para mim.
Capitão Kenpachi
23
Pense duas vezes antes de chamar resultado em um método assíncrono que blog.stephencleary.com/2012/07/dont-block-on-async-code.html
Ruchira
2
Para quem estava tentado a jogar isso em um usingcomo se eu fosse: aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong
maxshuty
Eu coloquei uma usingvolta em torno da StringContentcriação.
bcr
Usando esta resposta, recebi uma resposta "400 Solicitação inválida" de uma API para a qual estava postando minha solicitação JSON (Visual Studio 2017, .NET 4.6.2). Além de var content = new StringContent(jsonObject.ToString(), Encoding.UTF8, "application/json")eu ter que definir content.Headers.ContentType = new MediaTypeHeaderValue("application/json");. Veja a resposta abaixo para mais detalhes.
anthls
161

A maneira mais fácil é usar a StringContent, com a representação JSON do seu objeto JSON.

httpClient.Post(
    "",
    new StringContent(
        myObject.ToString(),
        Encoding.UTF8,
        "application/json"));
carlosfigueira
fonte
14
Tome nota do tipo de conteúdo. Eu o deixei de fora e me depurei por muito mais tempo do que gostaria.
Zapnologica
Você não deve descartar a instância StringContent?
Phil Haselden
63

Dependendo da sua versão do .NET, você também pode usar o HttpClientExtensions.PostAsJsonAsyncmétodo

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

user3285954
fonte
4
Agora encontrado em Microsoft.AspNet.Client.WebApi NuGet
jle
2
Acabei de instalar-lo de Microsoft.AspNet.WebApi.Client
Adriaan Davel
Isso resolveu meu problema. Eu estava brincando por um tempo (longo) ao passar uma classe C # que continha algumas propriedades que eram Listas usando client.PostAsync, client.SendAsync .. Eu estava obtendo resultados muito variados. Se a matriz estivesse vazia, minha solução de API iria buscá-la, mas se a matriz tivesse um item, o método do controlador não poderia modelar a ligação do JSON. Obrigado por isso. Parece-me que PostAsJsonAsync converte com mais confiabilidade um objeto C # complexo em JSON.
Franklin Tarter
Existe um pacote de pepitas para isso? Eu odeio quando transfiro o projeto para uma nova máquina, e essa referência está sempre ausente.
Zapnologica
Procurando isso ou algo mais? nuget.org/packages/Microsoft.AspNet.WebApi.Client
user3285954
51

Se estiver usando o 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");
}

Exemplo:

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
fonte
isto não é específico do núcleo asp.net, o seu baixo realmente genérica para sequer 4.5.6
danatcofo
JsonConvert.SerializeObjectproblemas usando o DateTimes ISO 8601 Tipo: Local ou UTC ... hackered.co.uk/articles/…
Kiquenet
21

Não tenho reputação suficiente para adicionar um comentário à resposta do pomber, por isso estou postando outra resposta. Usando a abordagem do pomber, recebi uma resposta "400 Bad Request" de uma API para a qual estava postando minha solicitação JSON (Visual Studio 2017, .NET 4.6.2). Eventualmente, o problema foi rastreado até o cabeçalho "Content-Type" produzido por StringContent () estar incorreto (consulte https://github.com/dotnet/corefx/issues/7864 ).

tl; dr

Use a resposta do pomber com uma linha extra para definir corretamente o cabeçalho na solicitação:

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
fonte
Obrigado, anthls. var content = new StringContent (jsonObject.ToString (), Encoding.UTF8, "application / json") não foi suficiente. Ele precisa content.Headers.ContentType = new MediaTypeHeaderValue ("application / json"); Obrigado por salvar minha sanidade.
Gail Foad
1
Isso funcionou muito bem. Alguma razão pela qual "application / json" precisa ser definido duas vezes, um no construtor e uma vez através da propriedade? Isso é um bug?
Festus Martingale
@FestusMartingale: boa pergunta! De minha leitura da questão github (ligada na resposta) a passagem de "application/json"no StringContentconstrutor provavelmente não é necessária, uma vez que está sendo explicitamente definido na resultando content.Headers.ContentTypepropriedade. No entanto, não testei isso no código.
Anthls 12/02/19
Parece que o servidor não suporta a cadeia de caracteres completa do tipo de conteúdo. Quando você usa o construtor sem substituir o ContentType, ele define o valor como application/json; charset=utf-8.
Bertm13 3/03
2

o código sobre ele no 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 esta ajuda

Stefano Ronchese
fonte