Recebendo dados JSON de volta da solicitação HTTP

97

Tenho uma solicitação da Web que está funcionando corretamente, mas está apenas retornando o status OK, mas preciso que o objeto que estou pedindo para retornar. Não tenho certeza de como obter o valor json que estou solicitando. Eu sou novo no uso do objeto HttpClient, há uma propriedade que estou perdendo? Eu realmente preciso do objeto de retorno. Obrigado por qualquer ajuda

Fazendo a chamada - corre bem retorna o status OK.

HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Accept
  .Add(new MediaTypeWithQualityHeaderValue("application/json"));
var responseMsg = client.GetAsync(string.Format("http://localhost:5057/api/Photo")).Result;

O método api get

//Cut out alot of code but you get the idea
public string Get()
{
    return JsonConvert.SerializeObject(returnedPhoto);
}
user516883
fonte
Você está perguntando como obter o conteúdo da resposta ao usar a classe .NET 4.5 HttpClient?
Panagiotis Kanavos

Respostas:

168

Se você estiver se referindo ao System.Net.HttpClient no .NET 4.5, poderá obter o conteúdo retornado por GetAsync usando a propriedade HttpResponseMessage.Content como um objeto derivado de HttpContent . Você pode então ler o conteúdo em uma string usando o método HttpContent.ReadAsStringAsync ou como um fluxo usando o método ReadAsStreamAsync .

A documentação da classe HttpClient inclui este exemplo:

  HttpClient client = new HttpClient();
  HttpResponseMessage response = await client.GetAsync("http://www.contoso.com/");
  response.EnsureSuccessStatusCode();
  string responseBody = await response.Content.ReadAsStringAsync();
Panagiotis Kanavos
fonte
3
Não testei isso, mas a documentação de EnsureSuccessStatusCode diz "Se o conteúdo não for nulo, este método também chamará Dispose para liberar recursos gerenciados e não gerenciados." então você pode querer ler o conteúdo primeiro. msdn.microsoft.com/en-us/library/…
Ryan Williams
4
Não há razão para isso. Conforme evidenciado pelo Reflector, o VerifySuccessStatusCode descartará SOMENTE se o código de status não for bem-sucedido, antes de lançar uma exceção. Mais um caso em que o texto da documentação é um pouco confuso.
Panagiotis Kanavos
1
Por que não apenas client.GetStringAsync(...)? Isso não existia em 2012. Ambos lançariam uma exceção se a resposta não fosse 200correta?
Simon_Weaver
1
@Simon_Weaver porque essa não era a questão - o OP perguntou como ler a string da resposta. Não são as diferenças. Você não pode inspecionar a resposta, o GetStringAsyncque significa que você não sabe qual foi a mensagem de resposta. Você provavelmente não deseja lançar se uma resposta 3xx for retornada. Você provavelmente deseja tentar novamente sem lançar se um erro de limitação for retornado.
Panagiotis Kanavos
1
@Simon_Weaver, existem várias maneiras de fazer essa ligação - por que não GetAsync<T>? Ou GetStreamAsync e passar o stream para Json.NET, evitando a string temporária? Novamente, pode ser preferível usar GetAsyncprimeiro e depois acessar o objeto de conteúdo
Panagiotis Kanavos
43

Com base na resposta de @Panagiotis Kanavos , aqui está um método de trabalho como exemplo que também retornará a resposta como um objeto em vez de uma string:

using System.Text;
using System.Net.Http;
using System.Threading.Tasks;
using Newtonsoft.Json; // Nuget Package

public static async Task<object> PostCallAPI(string url, object jsonObject)
{
    try
    {
        using (HttpClient client = new HttpClient())
        {
            var content = new StringContent(jsonObject.ToString(), Encoding.UTF8, "application/json");
            var response = await client.PostAsync(url, content);
            if (response != null)
            {
                var jsonString = await response.Content.ReadAsStringAsync();
                return JsonConvert.DeserializeObject<object>(jsonString);
            }
        }
    }
    catch (Exception ex)
    {
        myCustomLogger.LogException(ex);
    }
    return null;
}

Lembre-se de que este é apenas um exemplo e que você provavelmente gostaria de usar HttpClientcomo uma instância compartilhada em vez de usá-la em uma cláusula de uso.

Wouter Vanherck
fonte
Cuidado, o httpclient não descarta assim com a
instrução de
Visto que o await retorna imediatamente, é possível que if (response != null)seja executado antes que a pós-chamada seja concluída?
Nishant
Não vejo diferença, embora você tenha dito "retornar a resposta como um objeto em vez de uma string.", Se for esse o caso, por que você está fazendo uma etapa manual extra usando JsonConvert.DeserializedObject (), ou seja, você está converter string em objeto no cliente após ter sido recebido (como uma string).
joedotnot
8

Acho que o caminho mais curto é:

var client = new HttpClient();
string reqUrl = $"http://myhost.mydomain.com/api/products/{ProdId}";
var prodResp = await client.GetAsync(reqUrl);
if (!prodResp.IsSuccessStatusCode){
    FailRequirement();
}
var prods = await prodResp.Content.ReadAsAsync<Products>();
Greg Z.
fonte
8
Pensei apenas em adicionar que ReadAsAsync é um método de extensão. você precisará usar System.Net.Http.Formatting para .net 4+ e Microsoft.AspNet.WebApi.Client para .net core. para fazer isso funcionar.
Squably
0

O que eu normalmente faço, semelhante a uma resposta:

var response = await httpClient.GetAsync(completeURL); // http://192.168.0.1:915/api/Controller/Object

if (response.IsSuccessStatusCode == true)
    {
        string res = await response.Content.ReadAsStringAsync();
        var content = Json.Deserialize<Model>(res);

// do whatever you need with the JSON which is in 'content'
// ex: int id = content.Id;

        Navigate();
        return true;
    }
    else
    {
        await JSRuntime.Current.InvokeAsync<string>("alert", "Warning, the credentials you have entered are incorrect.");
        return false;
    }

Onde 'modelo' é sua classe de modelo C #.

James Heffer
fonte
0

Está funcionando bem para mim da seguinte maneira -

public async Task<object> TestMethod(TestModel model)
    {
        try
        {
            var apicallObject = new
            {
                Id= model.Id,
                name= model.Name
            };

            if (apicallObject != null)
            {
                var bodyContent = JsonConvert.SerializeObject(apicallObject);
                using (HttpClient client = new HttpClient())
                {
                    var content = new StringContent(bodyContent.ToString(), Encoding.UTF8, "application/json");
                    content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
                    client.DefaultRequestHeaders.Add("access-token", _token); // _token = access token
                    var response = await client.PostAsync(_url, content); // _url =api endpoint url
                    if (response != null)
                    {
                        var jsonString = await response.Content.ReadAsStringAsync();

                        try
                        {
                            var result = JsonConvert.DeserializeObject<TestModel2>(jsonString); // TestModel2 = deserialize object
                        }
                        catch (Exception e){
                            //msg
                            throw e;
                        }
                    }
                }
            }
        }
        catch (Exception ex)
        {
            throw ex;
        }
        return null;
    }
bulbul bd
fonte