web-dev-qa-db-fra.com

Comment obtenir le code de statut de webclient?

J'utilise la classe WebClient pour publier des données dans un formulaire Web. J'aimerais obtenir le code de statut de réponse de la soumission du formulaire. Jusqu'à présent, j'ai découvert comment obtenir le code d'état s'il y a une exception.

Catch wex As WebException
        If TypeOf wex.Response Is HttpWebResponse Then
          msgbox(DirectCast(wex.Response, HttpWebResponse).StatusCode)
            End If

Cependant, si le formulaire est soumis avec succès et qu'aucune exception n'est levée, je ne saurai pas le code d'état (200,301,302, ...)

Existe-t-il un moyen d’obtenir le code d’état sans exception?

PS: je préfère ne pas utiliser httpwebrequest/httpwebresponse

83
julio

Je l'ai essayé. Les ResponseHeaders n'incluent pas de code d'état.

Si je ne me trompe pas, WebClient est capable d'abstraire plusieurs demandes distinctes en un seul appel de méthode (par exemple, en gérant correctement 100 réponses Continue, redirections, etc.). Je soupçonne que sans utiliser HttpWebRequest et HttpWebResponse, un code de statut distinct peut ne pas être disponible.

Il me semble que, si les codes d’état intermédiaires ne vous intéressent pas, vous pouvez sans risque supposer que le code d’état final se situe dans la plage 2xx (réussite), sinon l’appel échouera.

Le code d'état n'est malheureusement pas présent dans le dictionnaire ResponseHeaders.

21
kbrimington

Vous pouvez vérifier si l'erreur est de type WebException puis inspecter le code de réponse;

if (e.Error.GetType().Name == "WebException")
{
   WebException we = (WebException)e.Error;
   HttpWebResponse response = (System.Net.HttpWebResponse)we.Response;
   if (response.StatusCode==HttpStatusCode.NotFound)
      System.Diagnostics.Debug.WriteLine("Not found!");
}

ou

try
{
    // send request
}
catch (WebException e)
{
    // check e.Status as above etc..
}
81
Henrik Hartz

Il y a un moyen de le faire en utilisant la réflexion. Cela fonctionne avec .NET 4.0. Il accède à un champ privé et peut ne pas fonctionner dans d'autres versions de .NET sans modifications.

Je n'ai aucune idée pourquoi Microsoft n'a pas exposé ce champ avec une propriété.

private static int GetStatusCode(WebClient client, out string statusDescription)
{
    FieldInfo responseField = client.GetType().GetField("m_WebResponse", BindingFlags.Instance | BindingFlags.NonPublic);

    if (responseField != null)
    {
        HttpWebResponse response = responseField.GetValue(client) as HttpWebResponse;

        if (response != null)
        {
            statusDescription = response.StatusDescription;
            return (int)response.StatusCode;
        }
    }

    statusDescription = null;
    return 0;
}
29
Dmitry S.

Si vous utilisez .Net 4.0 (ou moins):

class BetterWebClient : WebClient
{
        private WebRequest _Request = null;

        protected override WebRequest GetWebRequest(Uri address)
        {
            this._Request = base.GetWebRequest(address);

            if (this._Request is HttpWebRequest)
            {
                ((HttpWebRequest)this._Request).AllowAutoRedirect = false;
            }

            return this._Request;
        } 

        public HttpStatusCode StatusCode()
        {
            HttpStatusCode result;

            if (this._Request == null)
            {
                throw (new InvalidOperationException("Unable to retrieve the status 
                       code, maybe you haven't made a request yet."));
            }

            HttpWebResponse response = base.GetWebResponse(this._Request) 
                                       as HttpWebResponse;

            if (response != null)
            {
                result = response.StatusCode;
            }
            else
            {
                throw (new InvalidOperationException("Unable to retrieve the status 
                       code, maybe you haven't made a request yet."));
            }

            return result;
        }
    }

Si vous utilisez .Net 4.5.X ou une version plus récente, passez à HttpClient :

var response = await client.GetAsync("http://www.contoso.com/");
var statusCode = response.StatusCode;
28
Erik Philips

La réponse d'Erik ne fonctionne pas telle quelle sur Windows Phone. Ce qui suit:

class WebClientEx : WebClient
{
    private WebResponse m_Resp = null;

    protected override WebResponse GetWebResponse(WebRequest Req, IAsyncResult ar)
    {
        try
        {
            this.m_Resp = base.GetWebResponse(request);
        }
        catch (WebException ex)
        {
            if (this.m_Resp == null)
                this.m_Resp = ex.Response;
        }
        return this.m_Resp;
    }

    public HttpStatusCode StatusCode
    {
        get
        {
            if (m_Resp != null && m_Resp is HttpWebResponse)
                return (m_Resp as HttpWebResponse).StatusCode;
            else
                return HttpStatusCode.OK;
        }
    }
}

Au moins c'est le cas lorsque vous utilisez OpenReadAsync; pour les autres méthodes xxxAsync, des tests minutieux seraient fortement recommandés. La structure appelle GetWebResponse quelque part le long du chemin du code; il suffit de capturer et de mettre en cache l'objet de réponse.

Le code de secours est 200 dans cet extrait car les erreurs HTTP authentiques - 500, 404, etc. - sont néanmoins signalées comme des exceptions. Le but de cette astuce est de capturer des codes non-erreurs, dans mon cas spécifique 304 (non modifié). La solution de remplacement suppose donc que si le code de statut est indisponible, il s'agit au moins d'un code non erroné.

9
Seva Alekseyev

Tu devrais utiliser

if (e.Status == WebExceptionStatus.ProtocolError)
{
   HttpWebResponse response = (HttpWebResponse)ex.Response;             
   if (response.StatusCode == HttpStatusCode.NotFound)
      System.Diagnostics.Debug.WriteLine("Not found!");
}
3
LeMoussel

Juste au cas où quelqu'un aurait besoin d'une version F # du hack décrit ci-dessus.

open System
open System.IO
open System.Net

type WebClientEx() =
     inherit WebClient ()
     [<DefaultValue>] val mutable m_Resp : WebResponse

     override x.GetWebResponse (req: WebRequest ) =
        x.m_Resp <- base.GetWebResponse(req)
        (req :?> HttpWebRequest).AllowAutoRedirect <- false;
        x.m_Resp

     override x.GetWebResponse (req: WebRequest , ar: IAsyncResult  ) =
        x.m_Resp <- base.GetWebResponse(req, ar)
        (req :?> HttpWebRequest).AllowAutoRedirect <- false;
        x.m_Resp

     member x.StatusCode with get() : HttpStatusCode = 
            if not (obj.ReferenceEquals (x.m_Resp, null)) && x.m_Resp.GetType() = typeof<HttpWebResponse> then
                (x.m_Resp :?> HttpWebResponse).StatusCode
            else
                HttpStatusCode.OK

let wc = new WebClientEx()
let st = wc.OpenRead("http://www.stackoverflow.com")
let sr = new StreamReader(st)
let res = sr.ReadToEnd()
wc.StatusCode
sr.Close()
st.Close()
1
jpe

C'est ce que j'utilise pour développer les fonctionnalités de WebClient. StatusCode et StatusDescription contiendront toujours le code/description de réponse le plus récent.

                /// <summary>
                /// An expanded web client that allows certificate auth and 
                /// the retrieval of status' for successful requests
                /// </summary>
                public class WebClientCert : WebClient
                {
                    private X509Certificate2 _cert;
                    public WebClientCert(X509Certificate2 cert) : base() { _cert = cert; }
                    protected override WebRequest GetWebRequest(Uri address)
                    {
                        HttpWebRequest request = (HttpWebRequest)base.GetWebRequest(address);
                        if (_cert != null) { request.ClientCertificates.Add(_cert); }
                        return request;
                    }
                    protected override WebResponse GetWebResponse(WebRequest request)
                    {
                        WebResponse response = null;
                        response = base.GetWebResponse(request);
                        HttpWebResponse baseResponse = response as HttpWebResponse;
                        StatusCode = baseResponse.StatusCode;
                        StatusDescription = baseResponse.StatusDescription;
                        return response;
                    }
                    /// <summary>
                    /// The most recent response statusCode
                    /// </summary>
                    public HttpStatusCode StatusCode { get; set; }
                    /// <summary>
                    /// The most recent response statusDescription
                    /// </summary>
                    public string StatusDescription { get; set; }
                }

Ainsi, vous pouvez publier un message et obtenir un résultat via:

            byte[] response = null;
            using (WebClientCert client = new WebClientCert())
            {
                response = client.UploadValues(postUri, PostFields);
                HttpStatusCode code = client.StatusCode;
                string description = client.StatusDescription;
                //Use this information
            }
1
DFTR