Comment faire correctement une requête GET Web http

112

je suis encore nouveau sur c # et j'essaye de créer une application pour cette page qui me dira quand je reçois une notification (répondu, commenté, etc.). Mais pour l'instant, j'essaie juste de faire un simple appel à l'API qui récupérera les données de l'utilisateur.

J'utilise Visual studio express 2012 pour créer l'application C #, où (pour le moment) vous entrez votre identifiant utilisateur, donc l'application fera la demande avec l'identifiant utilisateur et affichera les statistiques de cet identifiant utilisateur.

voici le code où j'essaye de faire la demande:

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 est un objet et on y accède à partir du formulaire en analysant simplement l'ID utilisateur et en effectuant la demande.

J'ai essayé de nombreux exemples que j'ai consultés sur Google, mais je ne sais pas pourquoi je reçois de toutes les manières ce message " ".

je suis nouveau dans ce genre d'algorithme, si quelqu'un peut partager un livre ou un tutoriel qui montre comment faire ce genre de choses (expliquant chaque étape), je l'apprécierais

Oscar Reyes
la source

Réponses:

247

Les serveurs compressent parfois leurs réponses pour économiser de la bande passante, lorsque cela se produit, vous devez décompresser la réponse avant d'essayer de la lire. Heureusement, le framework .NET peut le faire automatiquement, cependant, nous devons activer le paramètre.

Voici un exemple de la façon dont vous pourriez y parvenir.

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

AVOIR

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

GET async

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
Contient le paramètre methoddans le cas où vous souhaitez utiliser d'autres méthodes HTTP telles que 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
Contient le paramètre methoddans le cas où vous souhaitez utiliser d'autres méthodes HTTP telles que 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
la source
4
Pour info, vous voudrez peut-être montrer un exemple sur la façon d'analyser la htmlchaîne +1pour du code propre au fait ..
MethodMan
merci, je ne connaissais pas la décompression, je suis développeur php / nodejs et c'est la première fois que je commence à développer sur des applications de bureau.
Oscar Reyes
Bienvenue, vous voudrez peut-être jeter un œil à «Newtonsoft.Json» pour désérialiser la réponse JSON que vous récupérez.
Aydin
y a-t-il une chance de version asynchrone
ahmad molaie
2
@ahmadmolaie Les a ajoutés, ainsi que comment faire des requêtes POST
Aydin
39

Une autre façon consiste à utiliser 'HttpClient' comme ceci:

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

Mise à jour du 22 juin 2020: il n'est pas recommandé d'utiliser httpclient dans un bloc `` using '' car cela pourrait entraîner l'épuisement du port.

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 vous utilisez .Net Core 2.1+, pensez à utiliser IHttpClientFactory et à injecter comme ceci dans votre code de démarrage.

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

 services.AddHttpClient<XApiClient>().ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler
        {
            AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
        }).AddPolicyHandler(request => timeout);
CREUSER
la source
1
Je vous remercie! Très utile pour moi. Je viens de modifier un peu en insérant la réponse et le contenu dans l'instruction "using":
codely
5
Par aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong , n'enveloppez jamais le HttpClient dans une instruction using.
sfors dit de réintégrer Monica
4
@sfors Ne dites jamais jamais. Regardez le code. L' HttpClientinstance est utilisée exactement une fois pendant la durée de vie du programme et est supprimée juste avant la fin du programme. C'est tout à fait correct et approprié.
Todd Menier
Je ne sais pas comment vous pouvez contester cet article et d'autres sur la façon de créer correctement une instance de HttpClient. Utilisation d'une variable statique privée, qui n'est pas supprimée. Pour cette raison, comme cité dans cet article: (concernant ne pas utiliser de disposer) ... "Mais HttpClient est différent. Bien qu'il implémente l'interface IDisposable, il s'agit en fait d'un objet partagé. Cela signifie que sous les couvertures, il est réentrant) et thread au lieu de créer une nouvelle instance de HttpClient pour chaque exécution, vous devez partager une seule instance de HttpClient pendant toute la durée de vie de l'application. "
sfors dit de réintégrer Monica
Je me rends compte que mon commentaire est 2 ans trop tard, mais Todd ne contestait pas l'article. Todd disait simplement que, étant donné l'exemple de programme complet, un seul HttpClient est utilisé pour la durée de vie de l'application.
John
4

Le moyen le plus simple à mon avis

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

OU

 var bytes = web.DownloadData(url);
Сергей Кислинский
la source
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();
    }
}
Manish Sharma
la source
5
le code ne supprime pas les objets; pourrait être une fuite de mémoire. Besoin d'utiliser des déclarations.
StarTrekRedneck
Vous ne pouvez pas affecter <null> à une variable typée implicitement!
Luca Ziegler
Il ne déclare que null.Je sais que.Je supprime null.
Manish sharma