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
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
.
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..
}
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;
}
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;
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é.
Tu devrais utiliser
if (e.Status == WebExceptionStatus.ProtocolError)
{
HttpWebResponse response = (HttpWebResponse)ex.Response;
if (response.StatusCode == HttpStatusCode.NotFound)
System.Diagnostics.Debug.WriteLine("Not found!");
}
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()
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
}