Cómo realizar correctamente una solicitud http web GET

112

Todavía soy nuevo en C # y estoy intentando crear una aplicación para esta página que me dirá cuando reciba una notificación (respondida, comentada, etc.). Pero por ahora solo estoy tratando de hacer una simple llamada a la API que obtendrá los datos del usuario.

Estoy usando Visual Studio Express 2012 para construir la aplicación C #, donde (por ahora) ingresa su identificación de usuario, por lo que la aplicación hará la solicitud con la identificación de usuario y mostrará las estadísticas de esta identificación de usuario.

aquí está el código donde estoy tratando de hacer la solicitud:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
//Request library
using System.Net;
using System.IO;

namespace TestApplication
{
    class Connect
    {
        public string id;
        public string type;

        protected string api = "https://api.stackexchange.com/2.2/";
        protected string options = "?order=desc&sort=name&site=stackoverflow";

        public string request()
        {
            string totalUrl = this.join(id);

            return this.HttpGet(totalUrl);
        }

        protected string join(string s)
        {
            return api + type + "/" + s + options;
        }

        protected string get(string url)
        {
            try
            {
                string rt;

                WebRequest request = WebRequest.Create(url);

                WebResponse response = request.GetResponse();

                Stream dataStream = response.GetResponseStream();

                StreamReader reader = new StreamReader(dataStream);

                rt = reader.ReadToEnd();

                Console.WriteLine(rt);

                reader.Close();
                response.Close();

                return rt;
            }

            catch(Exception ex)
            {
                return "Error: " + ex.Message;
            }
        }
        public string HttpGet(string URI)
        {
            WebClient client = new WebClient();

            // Add a user agent header in case the 
            // requested URI contains a query.

            client.Headers.Add("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; .NET CLR 1.0.3705;)");

            Stream data = client.OpenRead(URI);
            StreamReader reader = new StreamReader(data);
            string s = reader.ReadToEnd();
            data.Close();
            reader.Close();

            return s;
        }
    }
}

la clase es un objeto y se accede a ella desde el formulario con solo analizar el ID de usuario y realizar la solicitud.

He intentado muchos de los ejemplos que he buscado en Google, pero no tengo ni idea de por qué estoy recibiendo este mensaje " ".

Soy nuevo en este tipo de algoritmo, si alguien puede compartir un libro o tutorial que muestre cómo hacer este tipo de cosas (explicando cada paso), lo agradecería.

Oscar Reyes
fuente

Respuestas:

247

Los servidores a veces comprimen sus respuestas para ahorrar ancho de banda, cuando esto sucede, es necesario descomprimir la respuesta antes de intentar leerla. Afortunadamente, .NET framework puede hacer esto automáticamente, sin embargo, tenemos que activar la configuración.

Aquí tienes un ejemplo de cómo podrías lograrlo.

string html = string.Empty;
string url = @"https://api.stackexchange.com/2.2/answers?order=desc&sort=activity&site=stackoverflow";

HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.AutomaticDecompression = DecompressionMethods.GZip;

using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
using (Stream stream = response.GetResponseStream())
using (StreamReader reader = new StreamReader(stream))
{
    html = reader.ReadToEnd();
}

Console.WriteLine(html);

OBTENER

public string Get(string uri)
{
    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
    request.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;

    using(HttpWebResponse response = (HttpWebResponse)request.GetResponse())
    using(Stream stream = response.GetResponseStream())
    using(StreamReader reader = new StreamReader(stream))
    {
        return reader.ReadToEnd();
    }
}

OBTENER asíncrono

public async Task<string> GetAsync(string uri)
{
    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
    request.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;

    using(HttpWebResponse response = (HttpWebResponse)await request.GetResponseAsync())
    using(Stream stream = response.GetResponseStream())
    using(StreamReader reader = new StreamReader(stream))
    {
        return await reader.ReadToEndAsync();
    }
}

POST
Contiene el parámetro methoden caso de que desee utilizar otros métodos HTTP como PUT, DELETE, ETC

public string Post(string uri, string data, string contentType, string method = "POST")
{
    byte[] dataBytes = Encoding.UTF8.GetBytes(data);

    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
    request.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
    request.ContentLength = dataBytes.Length;
    request.ContentType = contentType;
    request.Method = method;

    using(Stream requestBody = request.GetRequestStream())
    {
        requestBody.Write(dataBytes, 0, dataBytes.Length);
    }

    using(HttpWebResponse response = (HttpWebResponse)request.GetResponse())
    using(Stream stream = response.GetResponseStream())
    using(StreamReader reader = new StreamReader(stream))
    {
        return reader.ReadToEnd();
    }
}

    

POST async
Contiene el parámetro methoden caso de que desee utilizar otros métodos HTTP como PUT, DELETE, ETC

public async Task<string> PostAsync(string uri, string data, string contentType, string method = "POST")
{
    byte[] dataBytes = Encoding.UTF8.GetBytes(data);

    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
    request.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
    request.ContentLength = dataBytes.Length;
    request.ContentType = contentType;
    request.Method = method;

    using(Stream requestBody = request.GetRequestStream())
    {
        await requestBody.WriteAsync(dataBytes, 0, dataBytes.Length);
    }

    using(HttpWebResponse response = (HttpWebResponse)await request.GetResponseAsync())
    using(Stream stream = response.GetResponseStream())
    using(StreamReader reader = new StreamReader(stream))
    {
        return await reader.ReadToEndAsync();
    }
}
Aydin
fuente
4
Para su información, es posible que desee mostrar un ejemplo de cómo analizar la htmlcadena +1para un código limpio por cierto ..
MethodMan
gracias, no sabía nada sobre la descompresión, soy desarrollador de php / nodejs y esta es la primera vez que empiezo a desarrollar aplicaciones de escritorio.
Oscar Reyes
Bienvenido, es posible que desee echar un vistazo a 'Newtonsoft.Json' para deserializar la respuesta JSON que recupera.
Aydin
¿Hay alguna posibilidad de versión asincrónica
Ahmad Molaie
2
@ahmadmolaie Los agregó, así como también cómo hacer solicitudes POST
Aydin
38

Otra forma es usar 'HttpClient' así:

using System;
using System.Net;
using System.Net.Http;

namespace Test
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Making API Call...");
            using (var client = new HttpClient(new HttpClientHandler { AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate }))
            {
                client.BaseAddress = new Uri("https://api.stackexchange.com/2.2/");
                HttpResponseMessage response = client.GetAsync("answers?order=desc&sort=activity&site=stackoverflow").Result;
                response.EnsureSuccessStatusCode();
                string result = response.Content.ReadAsStringAsync().Result;
                Console.WriteLine("Result: " + result);
            }
            Console.ReadLine();
        }
    }
}

HttpClient frente a HttpWebRequest

Actualización del 22 de junio de 2020: no se recomienda usar httpclient en un bloque de 'uso' ya que podría causar el agotamiento del puerto.

private static HttpClient client = null;
    
ContructorMethod()
{
   if(client == null)
   {
        HttpClientHandler handler = new HttpClientHandler()
        {
            AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
        };        
        client = new HttpClient(handler);
   }
   client.BaseAddress = new Uri("https://api.stackexchange.com/2.2/");
   HttpResponseMessage response = client.GetAsync("answers?order=desc&sort=activity&site=stackoverflow").Result;
   response.EnsureSuccessStatusCode();
   string result = response.Content.ReadAsStringAsync().Result;
            Console.WriteLine("Result: " + result);           
 }

Si usa .Net Core 2.1+, considere usar IHttpClientFactory e inyectar así en su código de inicio.

 var timeout = Policy.TimeoutAsync<HttpResponseMessage>(
            TimeSpan.FromSeconds(60));

 services.AddHttpClient<XApiClient>().ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler
        {
            AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
        }).AddPolicyHandler(request => timeout);
CAVAR
fuente
1
¡Gracias! Muy útil para mi. Acabo de modificar un poco al incluir la respuesta y el contenido en la declaración "using":
codificado
5
Según aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong , nunca envuelva el HttpClient en una declaración de uso.
sfors dice reinstalar a Monica
4
@sfors Nunca digas nunca. Mira el código. La HttpClientinstancia se utiliza exactamente una vez durante la vida del programa y se elimina justo antes de que el programa salga. Eso es completamente correcto y apropiado.
Todd Menier
No estoy seguro de cómo puede disputar ese artículo y otros sobre cómo crear correctamente una instancia de HttpClient. Usando una variable estática privada, que no se elimina. Debido a esto, como se cita en ese artículo: (con respecto a no usar dispose) ... "Pero HttpClient es diferente. Aunque implementa la interfaz IDisposable, en realidad es un objeto compartido. Esto significa que bajo las sábanas es reentrante) e hilo seguro. En lugar de crear una nueva instancia de HttpClient para cada ejecución, debe compartir una única instancia de HttpClient durante toda la vida útil de la aplicación ".
sfors dice reinstalar a Monica
Me doy cuenta de que mi comentario llegó 2 años tarde, pero Todd no estaba refutando el artículo. Todd simplemente estaba diciendo que dado el ejemplo completo del programa, se usa un solo HttpClient durante la vida útil de la aplicación.
John
4

La forma más sencilla de mi opinión.

  var web = new WebClient();
  var url = $"{hostname}/LoadDataSync?systemID={systemId}";
  var responseString = web.DownloadString(url);

O

 var bytes = web.DownloadData(url);
Сергей Кислинский
fuente
3
var request = (HttpWebRequest)WebRequest.Create("sendrequesturl");
var response = (HttpWebResponse)request.GetResponse();
string responseString;
using (var stream = response.GetResponseStream())
{
    using (var reader = new StreamReader(stream))
    {
        responseString = reader.ReadToEnd();
    }
}
Sharma manish
fuente
5
el código no elimina objetos; podría ser una pérdida de memoria. Necesita usar declaraciones.
StarTrekRedneck
¡No puede asignar <nulo> a una variable escrita implícitamente!
Luca Ziegler
Es solo declarar nulo. Sé que elimino nulo.
Manish Sharma