Вот пример, в котором может быть полезен указатель на элементы данных:
#include <iostream>
#include <list>
#include <string>
template <typename Container, typename T, typename DataPtr>
typename Container::value_type searchByDataMember (const Container& container, const T& t, DataPtr ptr) {
for (const typename Container::value_type& x : container) {
if (x->*ptr == t)
return x;
}
return typename Container::value_type{};
}
struct Object {
int ID, value;
std::string name;
Object (int i, int v, const std::string& n) : ID(i), value(v), name(n) {}
};
std::list<Object*> objects { new Object(5,6,"Sam"), new Object(11,7,"Mark"), new Object(9,12,"Rob"),
new Object(2,11,"Tom"), new Object(15,16,"John") };
int main() {
const Object* object = searchByDataMember (objects, 11, &Object::value);
std::cout << object->name << '\n'; // Tom
}
Пробовал. ResponseHeaders не включают код состояния.
Если я не ошибаюсь, WebClient
способен абстрагировать несколько различных запросов одним вызовом метода (например, правильно обрабатывать 100 ответов, перенаправлений и т. П.) ). Я подозреваю, что, не используя HttpWebRequest
и HttpWebResponse
, отдельный код состояния может быть недоступен.
Мне приходит в голову, что если вас не интересуют промежуточные коды состояния, вы можете смело предположить, окончательный код состояния находится в диапазоне 2xx (успешный), в противном случае вызов не будет успешным.
Код статуса, к сожалению, отсутствует в словаре ResponseHeaders
.
Другой способ:
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;
}
}
Это то, что я использую для расширения функциональности 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
}
Есть способ сделать это, используя отражение. Он работает с .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;
}
Вы можете проверить, имеет ли ошибка тип 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..
}
На всякий случай кому-то еще нужна версия 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()
Вы должны использовать
if (e.Status == WebExceptionStatus.ProtocolError)
{
HttpWebResponse response = (HttpWebResponse)ex.Response;
if (response.StatusCode == HttpStatusCode.NotFound)
System.Diagnostics.Debug.WriteLine("Not found!");
}
Вы должны иметь возможность использовать вызов «client.ResponseHeaders [..]», см. ссылку для примеров возврата материала из ответа
Вы можете попробовать этот код, чтобы получить код состояния HTTP из WebException или из OpenReadCompletedEventArgs.Error. Он также работает в Silverlight, потому что SL не имеет определения 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;
}
Ответ Эрика не работает на Windows Phone как есть. Следующее:
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;
}
}
}
По крайней мере, при использовании OpenReadAsync
; для других методов xxxAsync
рекомендуется тщательное тестирование. Структура вызывает GetWebResponse где-то вдоль пути кода; все, что нужно сделать, это захват и кэширование объекта ответа.
В этом фрагменте резервный код составляет 200, потому что истинные ошибки HTTP - 500, 404 и т. д. - все равно являются исключениями. Цель этого трюка - захватить коды без ошибок, в моем конкретном случае 304 (не изменено). Таким образом, резерв предполагает, что если код состояния каким-то образом недоступен, по крайней мере, он является ошибочным.