Вот решение, которое не требует насмешек. Вы реализуете все три компонента WebRequest
: IWebRequestCreate
WebRequest
и WebResponse
. Увидеть ниже. Мой пример генерирует ошибочные запросы (с помощью WebException
), но должен иметь возможность адаптировать его для отправки «реальных» ответов:
class WebRequestFailedCreate : IWebRequestCreate {
HttpStatusCode status;
String statusDescription;
public WebRequestFailedCreate(HttpStatusCode hsc, String sd) {
status = hsc;
statusDescription = sd;
}
#region IWebRequestCreate Members
public WebRequest Create(Uri uri) {
return new WebRequestFailed(uri, status, statusDescription);
}
#endregion
}
class WebRequestFailed : WebRequest {
HttpStatusCode status;
String statusDescription;
Uri itemUri;
public WebRequestFailed(Uri uri, HttpStatusCode status, String statusDescription) {
this.itemUri = uri;
this.status = status;
this.statusDescription = statusDescription;
}
WebException GetException() {
SerializationInfo si = new SerializationInfo(typeof(HttpWebResponse), new System.Runtime.Serialization.FormatterConverter());
StreamingContext sc = new StreamingContext();
WebHeaderCollection headers = new WebHeaderCollection();
si.AddValue("m_HttpResponseHeaders", headers);
si.AddValue("m_Uri", itemUri);
si.AddValue("m_Certificate", null);
si.AddValue("m_Version", HttpVersion.Version11);
si.AddValue("m_StatusCode", status);
si.AddValue("m_ContentLength", 0);
si.AddValue("m_Verb", "GET");
si.AddValue("m_StatusDescription", statusDescription);
si.AddValue("m_MediaType", null);
WebResponseFailed wr = new WebResponseFailed(si, sc);
Exception inner = new Exception(statusDescription);
return new WebException("This request failed", inner, WebExceptionStatus.ProtocolError, wr);
}
public override WebResponse GetResponse() {
throw GetException();
}
public override IAsyncResult BeginGetResponse(AsyncCallback callback, object state) {
Task<WebResponse> f = Task<WebResponse>.Factory.StartNew (
_ =>
{
throw GetException();
},
state
);
if (callback != null) f.ContinueWith((res) => callback(f));
return f;
}
public override WebResponse EndGetResponse(IAsyncResult asyncResult) {
return ((Task<WebResponse>)asyncResult).Result;
}
}
class WebResponseFailed : HttpWebResponse {
public WebResponseFailed(SerializationInfo serializationInfo, StreamingContext streamingContext)
: base(serializationInfo, streamingContext) {
}
}
Вы должны создать HttpWebResponse
подкласс, потому что иначе вы не можете создать его.
Сложная часть (в методе GetException()
) подает значения, которые вы не можете переопределить, например, StatusCode
и вот где наш лучший друг SerializaionInfo
входит! Здесь вы можете указать значения, которые вы не можете переопределить. Очевидно, переопределите те части (из HttpWebResponse
), которые вы можете, чтобы получить оставшуюся часть пути.
Как я получил «имена» во всех этих AddValue()
звонках? Из сообщений об исключениях! Было достаточно приятно рассказать мне все по очереди, пока я не осчастливил его.
Теперь компилятор будет жаловаться на «устаревшее», но это, тем не менее, работает, включая .NET Framework версии 4.
Вот (проходной) тестовый пример для справки:
[TestMethod, ExpectedException(typeof(WebException))]
public void WebRequestFailedThrowsWebException() {
string TestURIProtocol = TestContext.TestName;
var ResourcesBaseURL = TestURIProtocol + "://resources/";
var ContainerBaseURL = ResourcesBaseURL + "container" + "/";
WebRequest.RegisterPrefix(TestURIProtocol, new WebRequestFailedCreate(HttpStatusCode.InternalServerError, "This request failed on purpose."));
WebRequest wr = WebRequest.Create(ContainerBaseURL);
try {
WebResponse wrsp = wr.GetResponse();
using (wrsp) {
Assert.Fail("WebRequest.GetResponse() Should not have succeeded.");
}
}
catch (WebException we) {
Assert.IsInstanceOfType(we.Response, typeof(HttpWebResponse));
Assert.AreEqual(HttpStatusCode.InternalServerError, (we.Response as HttpWebResponse).StatusCode, "Status Code failed");
throw we;
}
}