Come effettuare correttamente una richiesta GET web http


112

sono ancora nuovo su c # e sto cercando di creare un'applicazione per questa pagina che mi dirà quando ricevo una notifica (risposta, commento, ecc ..). Ma per ora sto solo cercando di fare una semplice chiamata all'API che otterrà i dati dell'utente.

Sto usando Visual Studio Express 2012 per creare l'applicazione C #, dove (per ora) inserisci il tuo ID utente, quindi l'applicazione farà la richiesta con l'ID utente e mostrerà le statistiche di questo ID utente.

ecco il codice dove sto cercando di fare la richiesta:

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 classe è un oggetto e vi si accede dal form semplicemente analizzando l'ID utente ed effettuando la richiesta.

Ho provato molti degli esempi che ho cercato su Google, ma non ho idea del motivo per cui ricevo in tutti i modi questo messaggio " ".

sono nuovo in questo tipo di algoritmo, se qualcuno può condividere un libro o un tutorial che mostra come fare questo tipo di cose (spiegando ogni passaggio), lo apprezzerei

Risposte:


247

I server a volte comprimono le loro risposte per risparmiare sulla larghezza di banda, quando ciò accade, è necessario decomprimere la risposta prima di tentare di leggerla. Fortunatamente, il framework .NET può farlo automaticamente, tuttavia, dobbiamo attivare l'impostazione.

Ecco un esempio di come potresti ottenerlo.

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

OTTENERE

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

OTTIENI asincrono

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 il parametro methodnell'evento in cui si desidera utilizzare altri metodi HTTP come 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 il parametro methodnel caso in cui desideri utilizzare altri metodi HTTP come 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();
    }
}

4
fyi potresti voler mostrare un esempio di come analizzare la htmlstringa +1per il codice pulito tra l'altro ..
MethodMan

grazie, non sapevo della decompressione, sono uno sviluppatore php / nodejs e questa è la prima volta che inizio a sviluppare app desktop.
Oscar Reyes

Benvenuto, potresti dare un'occhiata a "Newtonsoft.Json" per deserializzare la risposta JSON che hai recuperato.
Aydin

c'è qualche possibilità per la versione asincrona
ahmad molaie

2
@ahmadmolaie li ha aggiunti, così come come fare le richieste POST
Aydin

39

Un altro modo è usare "HttpClient" in questo modo:

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 vs HttpWebRequest

Aggiornamento del 22 giugno 2020: non è consigliabile utilizzare httpclient in un blocco "using" in quanto potrebbe causare l'esaurimento della porta.

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

Se si utilizza .Net Core 2.1+, valutare l'utilizzo di IHttpClientFactory e l' inserimento in questo modo nel codice di avvio.

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

 services.AddHttpClient<XApiClient>().ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler
        {
            AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
        }).AddPolicyHandler(request => timeout);

1
Grazie! Molto utile per me. Ho appena modificato un po 'racchiudendo la risposta e il contenuto
nell'istruzione

5
Per aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong , non racchiudere mai HttpClient in un'istruzione using.
sfors dice reintegrare Monica il

4
@sfors Mai dire mai. Guarda il codice. L' HttpClientistanza viene utilizzata esattamente una volta per tutta la durata del programma e viene eliminata appena prima della chiusura del programma. Questo è completamente corretto e appropriato.
Todd Menier

Non sono sicuro di come sia possibile contestare quell'articolo e altri su come creare correttamente un'istanza di HttpClient. Utilizzando una variabile statica privata, che non viene eliminata. Per questo motivo, come citato in quell'articolo: (riguardo al non usare dispose) ... "Ma HttpClient è diverso. Sebbene implementi l'interfaccia IDisposable è in realtà un oggetto condiviso. Ciò significa che sotto le copertine è rientrante) e thread sicuro. Invece di creare una nuova istanza di HttpClient per ogni esecuzione, dovresti condividere una singola istanza di HttpClient per l'intera durata dell'applicazione. "
sfors dice reintegrare Monica il

Mi rendo conto che il mio commento è in ritardo di 2 anni, ma Todd non ha contestato l'articolo. Todd stava semplicemente dicendo che, dato l'esempio di programma completo, un singolo HttpClient viene utilizzato per la vita dell'applicazione.
John

4

Il modo più semplice per me

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

O

 var bytes = web.DownloadData(url);

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

5
il codice non dispone gli oggetti; potrebbe essere una perdita di memoria. Necessita di dichiarazioni.
StarTrekRedneck

Non puoi assegnare <null> a una variabile tipizzata in modo implicito!
Luca Ziegler

È solo dichiarare null. So che. Rimuovo null.
Manish sharma
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.