Używam WebClient
klasy do wysyłania danych do formularza internetowego. Chciałbym otrzymać kod statusu odpowiedzi przesłanego formularza. Do tej pory dowiedziałem się, jak uzyskać kod statusu, jeśli jest wyjątek
Catch wex As WebException
If TypeOf wex.Response Is HttpWebResponse Then
msgbox(DirectCast(wex.Response, HttpWebResponse).StatusCode)
End If
Jeśli jednak formularz zostanie przesłany pomyślnie i nie zostanie zgłoszony żaden wyjątek, nie będę znać kodu statusu (200,301,302, ...)
Czy istnieje sposób uzyskania kodu stanu, gdy nie ma żadnych wyjątków?
PS: Wolę nie używać httpwebrequest / httpwebresponse
Możesz sprawdzić, czy błąd jest rodzaju,
WebException
a następnie sprawdzić kod odpowiedzi;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!"); }
lub
try { // send request } catch (WebException e) { // check e.Status as above etc.. }
źródło
Jest na to sposób za pomocą refleksji. Działa z .NET 4.0. Uzyskuje dostęp do pola prywatnego i może nie działać w innych wersjach .NET bez modyfikacji.
Nie mam pojęcia, dlaczego Microsoft nie ujawnił tego pola z właściwością.
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; }
źródło
Jeśli używasz .Net 4.0 (lub mniej):
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; } }
Jeśli używasz .Net 4.5.X lub nowszego, przełącz się na HttpClient :
var response = await client.GetAsync("http://www.contoso.com/"); var statusCode = response.StatusCode;
źródło
Odpowiedź Erika nie działa na Windows Phone, tak jak jest. Następujące czynności:
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; } } }
Przynajmniej tak się dzieje podczas używania
OpenReadAsync
; w przypadku innychxxxAsync
metod wysoce zalecane byłoby dokładne przetestowanie. Framework wywołuje GetWebResponse gdzieś na ścieżce kodu; wszystko, co trzeba zrobić, to przechwycić i buforować obiekt odpowiedzi.Kod rezerwowy to 200 w tym fragmencie, ponieważ prawdziwe błędy HTTP - 500, 404 itd. - i tak są zgłaszane jako wyjątki. Celem tej sztuczki jest wychwycenie kodów innych niż błędy, w moim konkretnym przypadku 304 (bez modyfikacji). Tak więc rezerwa zakłada, że jeśli kod statusu jest w jakiś sposób niedostępny, to przynajmniej nie jest błędny.
źródło
Powinieneś użyć
if (e.Status == WebExceptionStatus.ProtocolError) { HttpWebResponse response = (HttpWebResponse)ex.Response; if (response.StatusCode == HttpStatusCode.NotFound) System.Diagnostics.Debug.WriteLine("Not found!"); }
źródło
However if the form is submitted successfully and no exception is thrown...
To jest to, czego używam do rozszerzania funkcjonalności WebClient. StatusCode i StatusDescription zawsze będą zawierać najnowszy kod / opis odpowiedzi.
/// <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; } }
W ten sposób możesz napisać post i uzyskać wynik poprzez:
byte[] response = null; using (WebClientCert client = new WebClientCert()) { response = client.UploadValues(postUri, PostFields); HttpStatusCode code = client.StatusCode; string description = client.StatusDescription; //Use this information }
źródło
Na wypadek, gdyby ktoś inny potrzebował wersji F # wyżej opisanego hackowania.
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()
źródło
Powinieneś być w stanie użyć wywołania „client.ResponseHeaders [..]”, zobacz ten link, aby zapoznać się z przykładami odzyskiwania zawartości z odpowiedzi
źródło
Możesz wypróbować ten kod, aby uzyskać kod stanu HTTP z WebException lub z OpenReadCompletedEventArgs.Error. Działa również w Silverlight, ponieważ SL nie ma zdefiniowanego 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; }
źródło