Search code examples
c#.netsystem.net.httpwebrequest

Get body text from an HttpWebRequest object?


I have a (legacy) method in my codebase which generates and returns a ready-to-send HTTP POST message as a System.Net.HttpWebRequest object:

public HttpWebRequest GetHttpWebRequest(string body, string url, string contentType)
{
    HttpWebRequest request = HttpWebRequest.CreateHttp(url);
    request.Method = "POST";
    // (More setup stuff here...)

    using (var writer = new StreamWriter(request.GetRequestStream()))
    {
        writer.Write(body);
    }

    return request;
}

I'd like to write a unit test which verifies that the HttpWebRequest instance returned by this method actually does have the message body text that was passed in to the method in the body parameter.

Question: How can I get the body text of an HttpWebRequest object (without ever actually sending the HTTP request)?

Stuff I've tried so far:

  • new StreamReader(myHttpWebRequest.GetRequestStream()).ReadToEnd() - Fails at runtime with ArgumentException: Stream was not readable.
  • The HttpWebRequest class doesn't seem to have any property that would allow getting/reading the HTTP message body such as Body, Message, Text, etc.

Solution

  • I would write a http listener and make real http requests.

    Here is a sample server using WCF + the client code. Just call await TestClient.Test(); (You can also test the server with a browser like http://localhost:8088/TestServer/Dummy)

    using Newtonsoft.Json;
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Net.Http;
    using System.ServiceModel;
    using System.ServiceModel.Channels;
    using System.ServiceModel.Web;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace SO
    {
        [ServiceContract]
        public class TestServer
        {
            static WebServiceHost _host = null;
            public static Task Start()
            {
                var tcs = new TaskCompletionSource<object>();
    
                try
                {
                    _host = new WebServiceHost(typeof(TestServer), new Uri("http://0.0.0.0:8088/TestServer"));
                    _host.Opened += (s, e) => { tcs.TrySetResult(null); };
                    _host.Open();
    
                }
                catch(Exception ex)
                {
                    tcs.TrySetException(ex);
                }
    
                return tcs.Task;
            }
    
            //A method that accepts anything :)
            [OperationContract, WebInvoke(Method = "*", UriTemplate ="*")]
            public Message TestMethod(Stream stream )
            {
                var ctx = WebOperationContext.Current;
    
                var request  = ctx.IncomingRequest.UriTemplateMatch.RequestUri.ToString();
    
                var body = new StreamReader(stream).ReadToEnd();
    
                Console.WriteLine($"{ctx.IncomingRequest.Method} {request}{Environment.NewLine}{ctx.IncomingRequest.Headers.ToString()}BODY:{Environment.NewLine}{body}");
    
                return ctx.CreateTextResponse( JsonConvert.SerializeObject( new { status = "OK", data= "anything" }), "application/json", Encoding.UTF8);
            }
        }
    
        public class TestClient
        {
            public static async Task Test()
            {
                await TestServer.Start();
    
                var client = new HttpClient();
                var objToSend = new { name = "L", surname = "B" };
                var content = new StringContent( JsonConvert.SerializeObject(objToSend) );
                var response = await client.PostAsync("http://localhost:8088/TestServer/TestMethod?aaa=1&bbb=2", content);
                Console.WriteLine(response.StatusCode);
                Console.WriteLine(await response.Content.ReadAsStringAsync());
    
            }
        }
    }