So stellen Sie eine http web GET-Anfrage ordnungsgemäß

111

Ich bin noch neu in c # und ich versuche, eine Anwendung für diese Seite zu erstellen, die mir sagt, wann ich eine Benachrichtigung erhalte (beantwortet, kommentiert usw.). Aber im Moment versuche ich nur, die API einfach anzurufen, um die Daten des Benutzers zu erhalten.

Ich verwende Visual Studio Express 2012, um die C # -Anwendung zu erstellen, in der Sie (vorerst) Ihre Benutzer-ID eingeben, sodass die Anwendung die Anforderung mit der Benutzer-ID stellt und die Statistiken dieser Benutzer-ID anzeigt.

Hier ist der Code, in dem ich versuche, die Anfrage zu stellen:

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

Die Klasse ist ein Objekt, auf das über das Formular zugegriffen wird, indem einfach die Benutzer-ID analysiert und die Anforderung gestellt wird.

Ich habe viele der Beispiele ausprobiert, die ich mir bei Google angesehen habe, aber keine Ahnung, warum ich diese Nachricht " " auf alle Arten erhalte.

Ich bin neu in dieser Art von Algorithmus. Wenn jemand ein Buch oder ein Tutorial teilen kann, das zeigt, wie man solche Dinge macht (jeden Schritt erklärt), würde ich es begrüßen

Oscar Reyes
quelle

Antworten:

246

Server komprimieren manchmal ihre Antworten, um Bandbreite zu sparen. In diesem Fall müssen Sie die Antwort dekomprimieren, bevor Sie versuchen, sie zu lesen. Glücklicherweise kann das .NET Framework dies automatisch tun, wir müssen jedoch die Einstellung aktivieren.

Hier ist ein Beispiel, wie Sie dies erreichen können.

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

BEKOMMEN

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
Enthält den Parameter methodfür den Fall, dass Sie andere HTTP-Methoden wie PUT, DELETE, ETC verwenden möchten

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
Enthält den Parameter methodfür den Fall, dass Sie andere HTTP-Methoden wie PUT, DELETE, ETC verwenden möchten

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
quelle
4
Zu Ihrer Information möchten Sie vielleicht ein Beispiel zeigen, wie man die htmlZeichenfolge +1für sauberen Code im
Übrigen
danke, ich wusste nichts über das Dekomprimieren, ich bin ein PHP / NodeJS-Entwickler und dies ist das erste Mal, dass ich mit der Entwicklung auf Desktop-Apps beginne.
Oscar Reyes
Willkommen, vielleicht möchten Sie einen Blick auf 'Newtonsoft.Json' werfen, um die JSON-Antwort, die Sie abrufen, zu deserialisieren.
Aydin
Gibt
2
@ahmadmolaie Hinzugefügt, sowie wie POST-Anfragen zu tun
Aydin
38

Eine andere Möglichkeit ist die Verwendung von 'HttpClient' wie folgt:

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

Update 22. Juni 2020: Es wird nicht empfohlen, httpclient in einem "using" -Block zu verwenden, da dies zu einer Erschöpfung des Ports führen kann.

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

Wenn Sie .Net Core 2.1+ verwenden, sollten Sie IHttpClientFactory verwenden und wie folgt in Ihren Startcode einfügen.

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

 services.AddHttpClient<XApiClient>().ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler
        {
            AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
        }).AddPolicyHandler(request => timeout);
GRABEN
quelle
1
Danke dir! Sehr nützlich für mich. Ich habe nur ein wenig geändert, indem ich die Antwort und den Inhalt in die "using"
-Anweisung aufgenommen habe
5
Per aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong , nie die Httpclient in einer using - Anweisung wickeln.
Sfors sagt, Monica
4
@sfors Sag niemals nie. Schauen Sie sich den Code an. Die HttpClientInstanz wird genau einmal für die Lebensdauer des Programms verwendet und kurz vor dem Beenden des Programms entsorgt. Das ist völlig richtig und angemessen.
Todd Menier
Ich bin nicht sicher, wie Sie diesen Artikel und andere darüber bestreiten können, wie eine Instanz des HttpClient ordnungsgemäß erstellt wird. Verwenden einer privaten statischen Variablen, die nicht entsorgt wird. Aus diesem Grund, wie in diesem Artikel zitiert: (bezüglich der Nichtverwendung von dispose) ... "Aber HttpClient ist anders. Obwohl es die IDisposable-Schnittstelle implementiert, ist es tatsächlich ein gemeinsam genutztes Objekt. Dies bedeutet, dass es unter den Deckblättern wiedereintrittsfähig ist) und Thread sicher. Anstatt für jede Ausführung eine neue Instanz von HttpClient zu erstellen, sollten Sie eine einzelne Instanz von HttpClient für die gesamte Lebensdauer der Anwendung freigeben. "
Sfors sagt wieder Monica
Mir ist klar, dass mein Kommentar 2 Jahre zu spät ist, aber Todd hat den Artikel nicht bestritten. Todd sagte lediglich, dass angesichts des vollständigen Programmbeispiels ein einzelner HttpClient für die Lebensdauer der Anwendung verwendet wird.
John
4

Einfachster Weg für meine Meinung

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

ODER

 var bytes = web.DownloadData(url);
Сергей Кислинский
quelle
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();
    }
}
Manischer Sharma
quelle
5
Code entsorgt keine Objekte; könnte ein Speicherverlust sein. Benötigt Anweisungen.
StarTrekRedneck
Sie können einer implizit typisierten Variablen nicht <null> zuweisen!
Luca Ziegler
Es ist nur null zu deklarieren. Ich weiß, dass ich null entferne.
Manish Sharma