Pregunta ¿Cómo obtener el código de estado de webclient?


Estoy usando el WebClient clase para publicar algunos datos en un formulario web. Me gustaría obtener el código de estado de la respuesta del envío del formulario. Hasta ahora he descubierto cómo obtener el código de estado si hay una excepción

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

Sin embargo, si el formulario se envía correctamente y no se lanza ninguna excepción, no sabré el código de estado (200,301,302, ...)

¿Hay alguna forma de obtener el código de estado cuando no se lanzan excepciones?

PD: prefiero no usar httpwebrequest / httpwebresponse


75
2017-08-26 11:33


origen


Respuestas:


Probado. ResponseHeaders no incluye código de estado.

Si no me equivoco, WebClient es capaz de abstraer múltiples solicitudes distintas en una sola llamada a un método (por ejemplo, manejando correctamente 100 Continuar respuestas, redirecciones, y similares). Sospecho que sin usar HttpWebRequest y HttpWebResponse, un código de estado distinto puede no estar disponible.

Se me ocurre que, si no está interesado en códigos de estado intermedios, puede suponer con seguridad que el código de estado final está en el rango 2xx (correcto); de lo contrario, la llamada no sería exitosa.

El código de estado desafortunadamente no está presente en ResponseHeaders diccionario.


20
2017-08-26 11:43



Puede verificar si el error es de tipo WebException y luego inspeccionar el código de respuesta;

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

o

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

73
2018-02-09 15:37



Hay una manera de hacerlo usando la reflexión. Funciona con .NET 4.0. Accede a un campo privado y puede no funcionar en otras versiones de .NET sin modificaciones.

No tengo idea de por qué Microsoft no expuso este campo con una propiedad.

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

27
2018-06-24 15:56



De otra manera:

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

23
2017-08-31 06:26



La respuesta de Erik no funciona en Windows Phone como está. Lo siguiente hace:

class WebClientEx : WebClient
{
    private WebResponse m_Resp = null;

    protected override WebResponse GetWebResponse(WebRequest Req, IAsyncResult ar)
    {
        return m_Resp = base.GetWebResponse(Req, ar);
    }

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

Al menos lo hace cuando se usa OpenReadAsync; por otro xxxAsync métodos, una prueba cuidadosa sería muy recomendable. El marco llama a GetWebResponse en algún lugar a lo largo de la ruta del código; todo lo que uno necesita hacer es capturar y almacenar en caché el objeto de respuesta.

El código de reserva es 200 en este fragmento porque los errores genuinos HTTP - 500, 404, etc. - se informan como excepciones de todos modos. El objetivo de este truco es capturar códigos sin errores, en mi caso específico 304 (No modificado). Entonces, la alternativa asume que si el código de estado no está disponible, al menos no es erróneo.


6
2017-11-13 16:42



Deberías usar

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

2
2017-08-21 09:33



Solo en caso de que alguien más necesite una versión F # del hack descrito anteriormente.

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
2017-11-25 18:13



Esto es lo que uso para expandir la funcionalidad de WebClient. StatusCode y StatusDescription siempre contendrán el código / descripción de respuesta más reciente.

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

Por lo tanto, puedes hacer una publicación y obtener un resultado a través de:

            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
2017-10-03 22:03



Debería poder usar la llamada "client.ResponseHeaders [..]", vea esto enlazar para ejemplos de cómo obtener cosas de la respuesta


-1
2017-08-26 11:44