4

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.
Jon Schneider
  • 25,758
  • 23
  • 142
  • 170
  • What would you be testing if you would succeed? The HttpWebRequest? Or it's response? I am just asking because something doesn't feel right here. – Stefan Sep 01 '17 at 16:34
  • @Stefan The idea is I'd be testing that my custom code that sets the "body" parameter value onto the created HttpWebRequest. (I could create several unit test methods make sure my code properly handles various corner cases.) – Jon Schneider Sep 01 '17 at 16:35
  • How about adding a http listener into your code and making real http requests. – L.B Sep 01 '17 at 16:40
  • @L.B That might be the best option if there really is no way to read the body from the HttpWebRequest without actually submitting it. Care to submit your idea as an answer, with sample code? :-) – Jon Schneider Sep 01 '17 at 16:42

1 Answers1

1

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());

        }
    }
}
L.B
  • 114,136
  • 19
  • 178
  • 224