Nicholas Petersen
Nicholas Petersen

Reputation: 9558

View Raw Headers that will be sent/received in HttpResponseMessage / HttpRequestMessage (System.Net.Http, WebAPI)

It can be extremely beneficial to visually see the raw list of Http Headers that will actually be sent or received in WebAPI's HttpResponseMessage / HttpRequestMessage types. I mean just a plain old string, with each header on a new line, exactly what is generated or received.

But unfortunately, it does not look like either of these types allows you to just see what actually gets generated. Instead, there are properties scattered everywhere. Some in the raw HttpResponseMessage / HttpRequestMessage types themselves, some in the response/request.Content.Headers (the two do not repeat, the latter is for ones not already covered as properties, typically for custom headers), ... and maybe Cookies somewhere gets a stash of its own headers. And visually getting to see those lists of Header collections is a pain as well, i.e. you end up with a bunch of iterating code for each such collection ... more mess.

But in the actual response / request sent / received, there is no such division, and it is simple to see all Http headers. So am I missing it somewhere? Is there actually a simple and intuitive property somewhere in these that simply returns the raw headers string? Certainly the response already received the headers and just parsed them ... is that raw string hidden somewhere?

(BTW, I know about Fiddler... and that is entirely unsatisfactory. If I am having to deal with low-level messing of Http headers, then it makes good sense to be able to view them with the programmatic type I am using to generate and receive them with. But worse off, I still can't get localhost to work with Fiddler (on Win8), which invalidates its use for many debugging scenarios where all I want to do is see the stinking headers that will be generated.)

Upvotes: 8

Views: 6877

Answers (3)

Michael Logutov
Michael Logutov

Reputation: 2569

It seems that HttpRequestMessage.ToString does returns raw values (well, techincally they are not original, but very close to one since it's been using parsers delimeters to join them back). Unfortunately methods that's been used to construct result of ToString are private. So to resolve the same task I had to parse the result of ToString:

var values = new JObject();

foreach (var raw_header in request.Headers
                                   .ToString()
                                   .Split(new[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries))
{
    var index = raw_header.IndexOf(':');
    if (index <= 0)
        continue;

    var key = raw_header.Substring(0, index);
    var value = index + 1 >= raw_header.Length ? string.Empty : raw_header.Substring(index + 1).TrimStart(' ');

    values.Add(new JProperty(key, value));
}

Upvotes: 0

arni
arni

Reputation: 2397

I did not find a way to get the raw value of request headers, but this code seems to return all the header values (not in original order):

request.Headers.ToString() + request.Content.Headers.ToString()

Upvotes: 4

Dror
Dror

Reputation: 1466

Here is the code I use in order to be able to catch the Request and Response headers:

*This is taken from a Windows Forms app so: txtReceived and txtSent are simple multiline TextBoxes on a WindowsForms form. and the cursor is the Form's cursor. *

    private HttpClient PrepareHttpClient()
    {
        var client = new HttpClient();

        client.DefaultRequestHeaders.Accept.Add(
            new MediaTypeWithQualityHeaderValue("application/xml"));

        return client;
    }

    private string SendGetRequest(string url)
    {
        //Please be patient ...
        this.Cursor = Cursors.WaitCursor;

        var client = PrepareHttpClient();
        txtSent.Text = url;
        var taskReult = client.GetAsync(new Uri(url));
        HttpResponseMessage httpResponse = taskReult.Result;

        Stream st = httpResponse.Content.ReadAsStreamAsync().Result;
        StreamReader reader = new StreamReader(st);
        string content = reader.ReadToEnd();

        //Reset the cursor shape
        this.Cursor = Cursors.Default;

        txtReceived.Text = FormatResponse(httpResponse, content);

        //For GET we expect a response of 200 OK
        if (httpResponse.StatusCode == HttpStatusCode.OK)
        {
            return content;
        }

        throw new ApplicationException(content);
    }
    /// <summary>
    /// Post to the server using JSON
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="url">The server uri</param>
    /// <param name="e">The object to POST</param>
    /// <returns></returns>
    private string SendPostRequest<T>(string url, T e)
    {
        this.Cursor = Cursors.WaitCursor;
        HttpClient client = new HttpClient();

        // Create the JSON formatter.
        MediaTypeFormatter jsonFormatter = new JsonMediaTypeFormatter();

        // Use the JSON formatter to create the content of the request body.
        HttpContent content = new ObjectContent<T>(e, jsonFormatter);
        Stream st = content.ReadAsStreamAsync().Result;
        StreamReader reader = new StreamReader(st);
        string s = reader.ReadToEnd();


        // Send the request.
        var taskResult = client.PostAsync(url, content);

        //Note: We could simply perform the following line and save some time
        //but then we will not have access to the post content:
        //var taskResult = client.PostAsJsonAsync<T>(url, e);

        HttpResponseMessage httpResponse = taskResult.Result;
        this.Cursor = Cursors.Default;

        txtSent.Text = FormatRequest(httpResponse.RequestMessage, s);

        st = httpResponse.Content.ReadAsStreamAsync().Result;
        reader = new StreamReader(st);
        string responseContent = reader.ReadToEnd();
        txtReceived.Text = FormatResponse(httpResponse, responseContent);

        //For POST we expect a response of 201 Created
        if (httpResponse.StatusCode == HttpStatusCode.Created)
        {
            return responseContent;
        }

        throw new ApplicationException(responseContent);
    }

    /// <summary>
    /// PUT to the server using JSON
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="url"></param>
    /// <param name="e"></param>
    /// <returns></returns>
    private string SendPutRequest<T>(string url, T e)
    {
        this.Cursor = Cursors.WaitCursor;
        HttpClient client = new HttpClient();

        // Create the JSON formatter.
        MediaTypeFormatter jsonFormatter = new JsonMediaTypeFormatter();

        // Use the JSON formatter to create the content of the request body.
        HttpContent content = new ObjectContent<T>(e, jsonFormatter);
        Stream st = content.ReadAsStreamAsync().Result;
        StreamReader reader = new StreamReader(st);
        string s = reader.ReadToEnd();

        // Send the request.
        var taskResult = client.PutAsync(url, content);

        //Note: We could simply perform the following line and save some time
        //but then we will not have access to the post content:
        //var taskResult = client.PutAsJsonAsync<T>(url, e);

        HttpResponseMessage httpResponse = taskResult.Result;

        txtSent.Text = FormatRequest(httpResponse.RequestMessage, s);

        st = httpResponse.Content.ReadAsStreamAsync().Result;
        reader = new StreamReader(st);
        string responseContent = reader.ReadToEnd();
        this.Cursor = Cursors.Default;
        txtReceived.Text = FormatResponse(httpResponse, responseContent);

        //For PUT we expect a response of 200 OK
        if (httpResponse.StatusCode == HttpStatusCode.OK)
        {
            return responseContent;
        }

        throw new ApplicationException(responseContent);
    }

    private string FormatRequest(HttpRequestMessage request, string content)
    {
        return
            string.Format("{0} {1} HTTP/{2}\r\n{3}\r\n{4}",
                request.Method,
                request.RequestUri,
                request.Version,
                request.Headers,
                content);
    }

    private string FormatResponse(HttpResponseMessage result, string content)
    {
        return
            string.Format("HTTP/{0} {1} {2}\r\n{3}\r\n{4}",
                result.Version,
                (int)result.StatusCode,
                result.ReasonPhrase,
                result.Headers,
                content);
    }

Upvotes: -1

Related Questions