WebClient
クラスを使用して、データをWebフォームに投稿しています。フォーム送信の応答ステータスコードを取得したいと思います。これまでのところ、例外がある場合にステータスコードを取得する方法を見つけました
Catch wex As WebException
If TypeOf wex.Response Is HttpWebResponse Then
msgbox(DirectCast(wex.Response, HttpWebResponse).StatusCode)
End If
ただし、フォームが正常に送信され、例外がスローされない場合、ステータスコード(200,301,302、...)がわかりません
例外がスローされていないときにステータスコードを取得する方法はありますか?
PS:httpwebrequest/httpwebresponseを使用したくない
それを試してみました。 ResponseHeadersにはステータスコードは含まれません。
間違っていない場合、WebClient
は、1つのメソッド呼び出しで複数の異なるリクエストを抽象化することができます(たとえば、100個のContinue応答、リダイレクトなどを正しく処理します)。 HttpWebRequest
とHttpWebResponse
を使用しないと、別個のステータスコードが利用できない可能性があります。
中間ステータスコードに興味がない場合は、最終ステータスコードが2xx(成功)の範囲にあると安全に想定できます。そうでなければ、呼び出しは成功しません。
残念ながら、ステータスコードはResponseHeaders
辞書にありません。
エラーのタイプがWebException
かどうかを確認してから、応答コードを検査できます。
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!");
}
または
try
{
// send request
}
catch (WebException e)
{
// check e.Status as above etc..
}
リフレクションを使用してそれを行う方法があります。 .NET 4.0で動作します。プライベートフィールドにアクセスし、変更しないと.NETの他のバージョンでは機能しない場合があります。
Microsoftがこのフィールドをプロパティで公開しなかった理由がわかりません。
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;
}
.Net 4.0(またはそれ以下)を使用している場合:
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;
}
}
.Net 4.5.X以降を使用している場合は、 HttpClient に切り替えます。
var response = await client.GetAsync("http://www.contoso.com/");
var statusCode = response.StatusCode;
Erikの答えはそのままWindows Phoneでは機能しません。以下は:
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;
}
}
}
少なくともOpenReadAsync
を使用する場合はそうです。他のxxxAsync
メソッドについては、慎重なテストを強くお勧めします。フレームワークは、コードパスのどこかでGetWebResponseを呼び出します。必要なのは、応答オブジェクトをキャプチャしてキャッシュすることだけです。
このスニペットでは、フォールバックコードは200です。これは、純粋なHTTPエラー(500、404など)が例外として報告されるためです。このトリックの目的は、非エラーコードをキャプチャすることです。私の特定のケースでは、304(変更なし)です。そのため、フォールバックでは、ステータスコードが何らかの理由で利用できない場合、少なくともエラーコードではないと想定します。
あなたが使用する必要があります
if (e.Status == WebExceptionStatus.ProtocolError)
{
HttpWebResponse response = (HttpWebResponse)ex.Response;
if (response.StatusCode == HttpStatusCode.NotFound)
System.Diagnostics.Debug.WriteLine("Not found!");
}
他の誰かが上記のハックのF#バージョンを必要とする場合に備えて。
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()
これは、WebClient機能を拡張するために使用するものです。 StatusCodeとStatusDescriptionには常に最新の応答コード/説明が含まれます。
/// <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; }
}
したがって、投稿して結果を取得できます:
byte[] response = null;
using (WebClientCert client = new WebClientCert())
{
response = client.UploadValues(postUri, PostFields);
HttpStatusCode code = client.StatusCode;
string description = client.StatusDescription;
//Use this information
}