Senden von GET / POST-Anforderungen in .NET

101121
sDima

Ich habe eine RequestsExtensions-Klasse mit zwei Funktionen zum Senden von GET / POST-Anforderungen.

using System;
using System.Net;
using System.Text;

    public static class RequestsExtensions
    {
        /// <summary>
        /// Sending POST request.
        /// </summary>
        /// <param name="Url">Request Url.</param>
        /// <param name="Data">Data for request.</param>
        /// <returns>Response body.</returns>
        public static string HTTP_POST(string Url, string Data)
        {
            string Out = String.Empty;
            System.Net.WebRequest req = System.Net.WebRequest.Create(Url);
            try
            {
                req.Method = "POST";
                req.Timeout = 100000;
                req.ContentType = "application/x-www-form-urlencoded";
                byte[] sentData = Encoding.UTF8.GetBytes(Data);
                req.ContentLength = sentData.Length;
                using (System.IO.Stream sendStream = req.GetRequestStream())
                {
                    sendStream.Write(sentData, 0, sentData.Length);
                    sendStream.Close();
                }
                System.Net.WebResponse res = req.GetResponse();
                System.IO.Stream ReceiveStream = res.GetResponseStream();
                using (System.IO.StreamReader sr = new System.IO.StreamReader(ReceiveStream, Encoding.UTF8))
                {
                    Char[] read = new Char[256];
                    int count = sr.Read(read, 0, 256);

                    while (count > 0)
                    {
                        String str = new String(read, 0, count);
                        Out += str;
                        count = sr.Read(read, 0, 256);
                    }
                }
            }
            catch (ArgumentException ex)
            {
                Out = string.Format("HTTP_ERROR :: The second HttpWebRequest object has raised an Argument Exception as 'Connection' Property is set to 'Close' :: {0}", ex.Message);
            }
            catch (WebException ex)
            {
                Out = string.Format("HTTP_ERROR :: WebException raised! :: {0}", ex.Message);
            }
            catch (Exception ex)
            {
                Out = string.Format("HTTP_ERROR :: Exception raised! :: {0}", ex.Message);
            }

            return Out;
        }

        /// <summary>
        /// Sending GET request.
        /// </summary>
        /// <param name="Url">Request Url.</param>
        /// <param name="Data">Data for request.</param>
        /// <returns>Response body.</returns>
        public static string HTTP_GET(string Url, string Data)
        {
            string Out = String.Empty;
            System.Net.WebRequest req = System.Net.WebRequest.Create(Url + (string.IsNullOrEmpty(Data) ? "" : "?" + Data));
            try
            {
                System.Net.WebResponse resp = req.GetResponse();
                using (System.IO.Stream stream = resp.GetResponseStream())
                {
                    using (System.IO.StreamReader sr = new System.IO.StreamReader(stream))
                    {
                        Out = sr.ReadToEnd();
                        sr.Close();
                    }
                }
            }
            catch (ArgumentException ex)
            {
                Out = string.Format("HTTP_ERROR :: The second HttpWebRequest object has raised an Argument Exception as 'Connection' Property is set to 'Close' :: {0}", ex.Message);
            }
            catch (WebException ex)
            {
                Out = string.Format("HTTP_ERROR :: WebException raised! :: {0}", ex.Message);
            }
            catch (Exception ex)
            {
                Out = string.Format("HTTP_ERROR :: Exception raised! :: {0}", ex.Message);
            }

            return Out;
        }
    }

Sehen Sie eine Verbesserung / ein Problem?

Antworten
8

4 Antworten auf die Frage

8
ChrisWue

First off your methods are not extension methods as the name RequestsExtensions would indicate. Not sure if this intentional or. If you want to make them true extension methods then I'd consider passing the Url parameter as Uri rather than as string.

Other things I noticed:

  1. The use of a magic number here: req.Timeout = 100000; - This should be a parameter (maybe with a default value) you can pass in.

  2. Your naming convention is a bit weird. Standard naming convention for methods in C# is PascalCase. Also local variables are normally camelCase (your Out variable is not while other variables like req are).

  3. In HTTP_POST you use a block-wise read to get the response while in HTTP_GET you simply read to the end of the response stream - why the difference? The HTTP_GET version seems much simpler so why not do it the same way? In fact both those method get a response and read it and deal with the exceptions - this is duplicated code which you should move into a dedicated function which you can then call from both main methods like this:

    private static string GetResponse(System.Net.WebRequest request)
    {
        string result = "";
        try
        {
            System.Net.WebResponse resp = req.GetResponse();
            using (System.IO.Stream stream = resp.GetResponseStream())
            {
                using (System.IO.StreamReader sr = new System.IO.StreamReader(stream))
                {
                    result = sr.ReadToEnd();
                    sr.Close();
                }
            }
        }
        catch 
          ....
    
        return result;
    }
    
  4. The way you handle exceptions is less than ideal. The caller of your methods has no easy way to find out if the call actually succeeded or not - except for parsing the return value of the method.

    A better way to deal with it is to let exceptions bubble up to the caller and let the caller decide what to do (e.g. terminate the process, retry later, etc.). In addition you could log the exception (requires passing in some kind of logger)

    Alternatively you could make the return value an out parameter and return a bool indicating if the call was successful instead if you really want to hide the exceptions from the caller. In this case I'd rename the methods to something like TryHttpPost and TryHttpGet

Anmerkung: `sr.Close ();` ist nicht erforderlich, da sich der `StreamReader` in einem` using`-Block befindet. Jesse C. Slicer vor 5 Jahren 5
2
svick

When something goes wrong, your method should throw an exception, that's what they're for. It shouldn't just return an error message instead of the normal response. That way, the calling code can easily differentiate between success and error.

Wenn ein Benutzer beispielsweise eine E-Mail über das Kontaktformular sendet, verwende ich die HttpGet-Anforderung, um Informationen vom Geoip-Dienst abzurufen und diese dem E-Mail-Text hinzuzufügen. Wenn der Geoip-Dienst nicht verfügbar ist, löst diese Methode eine Ausnahme aus und der Benutzer kann keine E-Mails senden. sDima vor 5 Jahren 0
@sDima Diese Methode löst eine Ausnahme aus, und die Methode, die diese Methode aufruft, kann sie abfangen. svick vor 5 Jahren 1
2
Greg Burghardt

Wenn der einzige Zweck darin besteht, einen einfachen Wrapper um den Rumpf der HTTP-Antwort bereitzustellen, ist dies nicht so schlimm. Wenn Sie auf Dinge wie die Anforderungs- und Antwort-Header zugreifen müssen, kommt es zu Problemen.

Fehlerbehandlung ist eine ganz andere Sache. Ich würde empfehlen, alle Fehler abzufangen und die Ausnahmen erneut in Ihre eigenen Ausnahmeklassen umzuwandeln, um die Fehlerbehandlung für Clientcode zu vereinfachen:

public class RequestError : Exception
{
    ...
}

public class RequestNotFoundError : RequestError
{
    ...
}

public class RequestServerEror : RequestError
{

}

Der Client-Code wird viel klarer:

try
{
    RequestExtensions.HTTP_POST(...)
}
catch (RequestNotFoundError)
{
    // 404 Not Found
}
catch (RequestServerError)
{
    // 500 Internal Server Error
}
catch (RequestError)
{
    // Some sort of unhandled HTTP error
}
catch (Exception)
{
    // Gremlins, I suppose
}

Das Schwierigste beim Verwalten von HTTP-Anforderungen ist, dass es eine Million Möglichkeiten gibt, diese Dinge zu sterben. Jede Unterstützung, die Sie bei der Fehlerbehandlung geben können, wird von allen Anwendern dieser Klasse geschätzt.

0
dougajmcdonald

I'm not sure I'd totally approve of:

The second HttpWebRequest object has raised an Argument Exception as 'Connection' Property is set to 'Close'

How have you determined this? in my opinion the message could be incorrect and be an exception for a totally different reason.

Your other two catches are far more generic, which is likely better, also the latter two catch both end in an exclamation mark (which I don't like!(meta!)) but if you're going to do it, do keep it consistent across all three exceptions!