c# - headers - ¿Cómo obtener el código de estado de webclient?
webclient get c# (10)
Estoy usando la clase WebClient
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
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;
}
}
Debería poder utilizar la llamada "client.ResponseHeaders [..]", consulte este link para ver ejemplos de cómo recuperar algo de la respuesta
Deberías usar
if (e.Status == WebExceptionStatus.ProtocolError)
{
HttpWebResponse response = (HttpWebResponse)ex.Response;
if (response.StatusCode == HttpStatusCode.NotFound)
System.Diagnostics.Debug.WriteLine("Not found!");
}
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
}
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;
}
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
; para otros métodos xxxAsync
, se recomienda encarecidamente realizar pruebas cuidadosas. 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.
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 respuestas de Continuar, 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.
Desafortunadamente, el código de estado no está presente en el diccionario ResponseHeaders
.
Puede probar este código para obtener el código de estado HTTP de WebException o de OpenReadCompletedEventArgs.Error. También funciona en Silverlight porque SL no tiene definido WebExceptionStatus.ProtocolError.
HttpStatusCode GetHttpStatusCode(System.Exception err)
{
if (err is WebException)
{
WebException we = (WebException)err;
if (we.Response is HttpWebResponse)
{
HttpWebResponse response = (HttpWebResponse)we.Response;
return response.StatusCode;
}
}
return 0;
}
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..
}
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..com")
let sr = new StreamReader(st)
let res = sr.ReadToEnd()
wc.StatusCode
sr.Close()
st.Close()