Here is a solution that does not require ridicule. You implement all three components of WebRequest : IWebRequestCreate WebRequest and WebResponse . See below. My example generates unsuccessful requests (throwing a WebException ), but should be able to adapt it to send "real" responses:
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) { } }
You must create a subclass of HttpWebResponse , because you cannot create it otherwise.
The GetException() part (in the GetException() method) provides values that you cannot override, for example. StatusCode , and this is where our best friend SerializaionInfo comes in! Here you specify values that you cannot override. Obviously, override the parts ( HttpWebResponse ) that you can to go the rest of the way.
How did I get the "names" in all these calls to AddValue() ? From exception messages! It was nice enough to tell me everything in turn, until I made it happy.
Now the compiler will complain about the "obsolete", but it still works, including the .NET Framework version 4.
Here is an example (walkthrough) for reference:
[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; } }