[c#] 웹 클라이언트에서 상태 코드를 얻는 방법은 무엇입니까?

WebClient클래스를 사용하여 웹 양식에 일부 데이터를 게시하고 있습니다. 양식 제출의 응답 상태 코드를 받고 싶습니다. 지금까지 예외가있는 경우 상태 코드를 얻는 방법을 알아 냈습니다.

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

그러나 양식이 성공적으로 제출되고 예외가 발생하지 않으면 상태 코드 (200,301,302, …)를 알 수 없습니다.

예외가 발생하지 않을 때 상태 코드를 얻을 수있는 방법이 있습니까?

추신 : httpwebrequest / httpwebresponse를 사용하지 않는 것을 선호합니다.



답변

그것을 시도했습니다. ResponseHeaders에는 상태 코드가 포함되지 않습니다.

내가 착각하지 않았다면 WebClient은 (는) 단일 메서드 호출에서 여러 개의 개별 요청을 추상화 할 수 있습니다 (예 : 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!");
}


답변

이것이 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
            }