Recibir datos JSON de la solicitud HTTP

91

Tengo una solicitud web que funciona correctamente, pero solo devuelve el estado OK, pero necesito el objeto que estoy solicitando que regrese. No estoy seguro de cómo obtener el valor json que estoy solicitando. Soy nuevo en el uso del objeto HttpClient, ¿hay alguna propiedad que me esté perdiendo? Realmente necesito el objeto que regresa. Gracias por cualquier ayuda

Hacer la llamada - funciona bien devuelve el estado 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;

El método api get

//Cut out alot of code but you get the idea
public string Get()
{
    return JsonConvert.SerializeObject(returnedPhoto);
}
usuario516883
fuente
¿Está preguntando cómo obtener el contenido de la respuesta cuando se usa la clase .NET 4.5 HttpClient?
Panagiotis Kanavos

Respuestas:

162

Si se refiere a System.Net.HttpClient en .NET 4.5, puede obtener el contenido devuelto por GetAsync utilizando la propiedad HttpResponseMessage.Content como un objeto derivado de HttpContent . Luego, puede leer el contenido en una cadena mediante el método HttpContent.ReadAsStringAsync o como una secuencia mediante el método ReadAsStreamAsync .

La documentación de la clase HttpClient incluye este ejemplo:

  HttpClient client = new HttpClient();
  HttpResponseMessage response = await client.GetAsync("http://www.contoso.com/");
  response.EnsureSuccessStatusCode();
  string responseBody = await response.Content.ReadAsStringAsync();
Panagiotis Kanavos
fuente
3
No lo he probado, pero la documentación de SecureSuccessStatusCode dice "Si el contenido no es nulo, este método también llamará a Dispose para liberar recursos administrados y no administrados". por lo que es posible que desee leer el contenido primero. msdn.microsoft.com/en-us/library/…
Ryan Williams
4
No hay razón para esto. Como lo demuestra Reflector, GuaranteSuccessStatusCode se eliminará SOLO si el código de estado no es correcto, justo antes de lanzar una excepción. Otro caso más en el que el texto de la documentación es un poco confuso.
Panagiotis Kanavos
1
¿Por qué no solo client.GetStringAsync(...)? ¿No fue eso en 2012. Ambos lanzarían una excepción si la respuesta no fuera 200correcta?
Simon_Weaver
1
@Simon_Weaver porque esa no era la pregunta: el OP preguntó cómo leer la cadena de la respuesta. No hay diferencias. No puede inspeccionar la respuesta con lo GetStringAsyncque significa que no sabe cuál fue el mensaje de respuesta. Probablemente no desee lanzar si se devuelve una respuesta 3xx. Probablemente desee volver a intentarlo sin lanzar si se devuelve un error de limitación.
Panagiotis Kanavos
1
@Simon_Weaver hay muchas formas de hacer esa llamada, ¿por qué no GetAsync<T>? ¿O GetStreamAsync y pasar la secuencia a Json.NET, evitando la cadena temporal? Nuevamente, puede ser preferible usar GetAsyncprimero y luego acceder al objeto de contenido
Panagiotis Kanavos
40

Sobre la base de la respuesta de @Panagiotis Kanavos , aquí hay un método de trabajo como ejemplo que también devolverá la respuesta como un objeto en lugar de una cadena:

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;
}

Tenga en cuenta que esto es solo un ejemplo y que probablemente le gustaría usarlo HttpClientcomo una instancia compartida en lugar de usarlo en una cláusula de uso.

Wouter Vanherck
fuente
Tenga cuidado de que httpclient no se deshaga de esa manera con la declaración de uso
rogue39nin
Dado que await regresa inmediatamente, ¿es posible que if (response != null)se ejecute antes de que se complete la llamada posterior?
Nishant
7

Creo que el camino más corto es:

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.
fuente
7
Solo pensé en agregar que ReadAsAsync es un método de extensión. deberá utilizar System.Net.Http.Formatting para .net 4+ y Microsoft.AspNet.WebApi.Client para .net core. para que esto funcione.
Squbly
0

Lo que hago normalmente, similar a responder uno:

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;
    }

Donde 'modelo' es su clase de modelo C #.

James Heffer
fuente
0

Funciona bien para mí de la siguiente manera:

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
fuente