We help IT Professionals succeed at work.

C# HTTPrequest - how to get the whole request and whole response.

N M
N M used Ask the Experts™
on
I have the below small console program to consume a restAPI.
I have difficulty to see *what exactly* am I sending (the WHOLE request) and *what exactly* am I getting back as a response (the WHOLE response).
I have tried many Console.WriteLines with various arguments, but seems I have not managed to have a concrete results (WHOLE request and WHOLE response).

Could you help me please? The whole code below.

using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using Newtonsoft.Json;


namespace TEST_API
{
    public partial class ConsentHeaders
    {
        [JsonProperty("CL-ID")]
        public string CL_ID { get; set; }

        [JsonProperty("X-ID")]
        public string X_ID { get; set; }

        [JsonProperty("P-Token")]
        public string P_Token { get; set; }
    }

    public partial class access
    {
        [JsonProperty("aP2")]
        public string aP2 { get; set; } = "allAccounts";

        [JsonProperty("aAcc")] 
        public string aAcc { get; set; } = "allAccounts";
    }

    public partial class ConsentBody
    {
        [JsonProperty("access")]
        public access access { get; internal set; }

        [JsonProperty("combinedServiceIndicator")]
        public Boolean combinedServiceIndicator { get; set; } = false;

        [JsonProperty("frequencyPerDay")]
        public int frequencyPerDay { get; set; } = 4;

        [JsonProperty("recurringIndicator")]
        public Boolean recurringIndicator { get; set; } = false;

        [JsonProperty("validUntil")]
        public string validUntil { get; set; } = "2019-12-31";
    }


    class Program
    {
        private static void Main()
        {
            ConsentHeaders cust_consent_headers = new ConsentHeaders
            {
                X_ID = "d587612Xq99",
                CL_ID = "8010aFQ9127",
                P_Token = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ",
            };

            ConsentBody cust_consent = new ConsentBody //{ };

            // You may choose to edit/update any value, otherwise defaults will be used.
                
                {
                    access = new access
                    {
                        aP2 = "allAccounts",
                        aAcc = "allAccounts"
                    },
                    combinedServiceIndicator = false,
                    frequencyPerDay = 4,
                    recurringIndicator = false,
                    validUntil = "2019-12-31"
                };
            
            System.Uri URL = new System.Uri("http://MyService:8001/some/api/do/something");

            CreateConsentAsync(URL, cust_consent_headers, cust_consent).GetAwaiter().GetResult();
        }

        static HttpClient client = new HttpClient();

        static async Task CreateConsentAsync(Uri HTTPaddress, ConsentHeaders cconsentHeaders, ConsentBody cconsent)
        {
            try
            {
                client.BaseAddress = HTTPaddress;
                client.DefaultRequestHeaders.Accept.Clear();
                client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("*/*"));
                client.DefaultRequestHeaders.Add("Connection", "keep-alive");
                client.DefaultRequestHeaders.Add("Cache-Control", "no-cache");

                client.DefaultRequestHeaders.Add("CL-ID", cconsentHeaders.CL_ID);
                client.DefaultRequestHeaders.Add("X-ID", cconsentHeaders.X_ID);
                client.DefaultRequestHeaders.Add("P-Token", cconsentHeaders.P_Token);

                HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, client.BaseAddress);

                request.Content = new StringContent(JsonConvert.SerializeObject(cconsent, Formatting.Indented), System.Text.Encoding.UTF8, "application/json");

                    
                await client.SendAsync(request).ContinueWith(responseTask => { Console.WriteLine("Response: {0}", responseTask.Result);});
            }
            catch (Exception e)
            {
                Console.WriteLine("Error in " + e.TargetSite + "\r\n" + e.Message);
            }
            Console.ReadLine();
        }
    }
}

Open in new window

Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®
N MConsultant

Author

Commented:
*Note: if you spot any bug, kindly respond, I'm new on this. Thank you very much.

Commented:
You can use tracing to capture the raw request and response. I built a library to make it a very simple process:

https://github.com/jhilgeman/HttpRawTraceListener

Commented:
On a side note, an even easier way is to install and use Fiddler. That program simply examines HTTP network activity on your computer (across all apps, not just your program). My library I mentioned above is if you need to access the request/response from within code.
N MConsultant

Author

Commented:
Thank you, I will try it, but seems complicated, I was just looking to have all the request in a string and all the response in a string. I will make an efrort to follow your advice - thank you!

Commented:
I was just looking to have all the request in a string and all the response in a string.
That's ultimately what my library does.

The bigger question is what your goal is. If it's just to examine and debug, then Fiddler is the simplest approach. You can be up and running in minutes.

If you need it as a string because you want to do something extra with the data, then that is what my library is for. Make sure you look at the example. It's very simple to set up.
N MConsultant

Author

Commented:
Thank you, I just copied the code inside the same namespace, added System.IO and now thinking how to use it to get the whole request and response.. Thank you

Commented:
I'm not sure what you mean by copying the code into your namespace. It's intended to be a drop-in file (you cannot remove the copyright or header).

Just save the file as-is into your project and then in your solution explorer, right-click the file and Include it to make it part of your project. Then just use the example usage code. The example shows you how to get the full request and response.
N MConsultant

Author

Commented:
I will do so (no I didnt remove the copyright, no need to pretend is my code). Just trying to see how to get the full string response.. I will follow your advice here.
N MConsultant

Author

Commented:
Still trying to have the request, I was wondering if there is any simpler solution; kindly advise.

I have added this namespace, in different file, and all is good.
I am inside my code, in the static async Task CreateConsentAsync and inside the 'try' right after my 'await client.SendAsync' I put the trace listener.
Here is that part:

            try
            {
                client.BaseAddress = HTTPaddress;
                client.DefaultRequestHeaders.Accept.Clear();
                client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("*/*"));
                client.DefaultRequestHeaders.Add("Connection", "keep-alive");
                client.DefaultRequestHeaders.Add("Cache-Control", "no-cache");

                client.DefaultRequestHeaders.Add("... etc.



                HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, client.BaseAddress);

                request.Content = new StringContent(JsonConvert.SerializeObject(cconsent, Formatting.Indented), System.Text.Encoding.UTF8, "application/json");

                Console.WriteLine(client.DefaultRequestHeaders);
                Console.WriteLine(JsonConvert.SerializeObject(cconsent, Formatting.Indented));

                await client.SendAsync(request).ContinueWith(responseTask => { Console.WriteLine("Response: {0}", responseTask.Result); });


                System.Diagnostics.HttpRawTraceListener.Initialize();

                System.Diagnostics.HttpRawTraceListener.FinishedCommunication += System.Diagnostics.HttpRawTraceListener_FinishedCommunication;

                private void HttpRawTraceListener_FinishedCommunication(object sender, System.Diagnostics.CommunicationEventArgs e)
                {
                    Console.WriteLine("Raw Request: " + e.Communication.RequestString);
                    Console.WriteLine("Raw Response: " + e.Communication.ResponseString); 
                }


            }
            catch (Exception e)
            {
                Console.WriteLine("Error in " + e.TargetSite + "\r\n" + e.Message);
            }
            Console.ReadLine();
        }

Open in new window


So, I have error on the "System.Diagnostics.HttpRawTraceListener_FinishedCommunication" that says it does not recognise the namespace ("does not exist in System.Diagnostics namespace, are you missing an assembly or reference?" - but I am not). And in private void HttpRawTraceListener_FinishedCommunication does not accept the "private" (throws error "the modifier 'private' is not valid for this item".

Apologies, couldn't debug so I revert code to previous stage.

Commented:
You are not putting the code in the right place. These two lines:
System.Diagnostics.HttpRawTraceListener.Initialize();
System.Diagnostics.HttpRawTraceListener.FinishedCommunication += System.Diagnostics.HttpRawTraceListener_FinishedCommunication;

Open in new window

...need to only run once, so put them into your startup code.

The second part is an event handler method so it needs to go outside your current method.

To be honest, I'm concerned that you don't know C# syntax. This is not something you should try to do by cutting and pasting code snippets from the internet. It is more involved than that because of the way that .NET handles tracing. So at minimum you should understand event handlers and static vs. non-static code. Otherwise this won't make sense (and there is no simpler way to get the full request and response in every situation - both successful and failed requests).
N MConsultant

Author

Commented:
Dear sir,

Indeed I am trying to have a steep learn curve to walk, but I am trying. After all, this is the reason I am asking the help from the experts here.. both solving a problem and learning through this.
I am taking your advice quite seriously, however, still the code didn't compile.. Well, I will keep trying..
You may look my effort and error messages in the comment before yours.
Thank you for the comments, and I appreciate your time.
N MConsultant

Author

Commented:
So, for the POST indeed this would reveal the Post request:
Console.WriteLine("POST Request: " + "\r\n" + client.DefaultRequestHeaders + "\r\n" + JsonConvert.SerializeObject(cconsent, Formatting.Indented) + "\r\n");

and for the response, instead of using the
responseTask.Result
we can use
responseTask.Result.Content.ReadAsStringAsync().Result


static async Task CreateConsentAsync(Uri HTTPaddress, ConsentHeaders cconsentHeaders, ConsentBody cconsent)
{
	HttpClient client = new HttpClient();

	try
	{
		client.BaseAddress = HTTPaddress;
		client.DefaultRequestHeaders.Accept.Clear();
		client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("*/*"));
		client.DefaultRequestHeaders.Add("Connection", "keep-alive");
		client.DefaultRequestHeaders.Add("Cache-Control", "no-cache");
		//add more headears here as per your needs..
		client.DefaultRequestHeaders.Add("my header", yourValue);
		//...

		HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, client.BaseAddress);

		request.Content = new StringContent(JsonConvert.SerializeObject(cconsent, Formatting.Indented), System.Text.Encoding.UTF8, "application/json");

		Console.WriteLine("POST Request: " + "\r\n" + client.DefaultRequestHeaders + "\r\n" + JsonConvert.SerializeObject(cconsent, Formatting.Indented) + "\r\n");

		await client.SendAsync(request).ContinueWith(responseTask => {Console.WriteLine("Response:\r\n{0}", responseTask.Result.Content.ReadAsStringAsync().Result);});

		Console.ReadLine();
	}
	catch (Exception e)
	{
		Console.WriteLine("Error in " + e.TargetSite + "\r\n" + e.Message);
		Console.ReadLine();
	}
}

Open in new window

N MConsultant

Author

Commented:
Any better (as simple as possible) solutions, to get the whole POST message and the whole Request sent back, are welcome. Thank you.
Commented:
That solution will not give you the true, full request and response.

1. That does not show you the final set of headers (including any custom ones).

2. It will not give you the response headers.

3. It will not give you the response body if the HTTP response code is non-200.

As I stated earlier, my solution works and will provide you with the full, final, accurate result for both request and response. You simply need to fix where you are putting the event handler code.

....
class Program
    {
        private static void Main()
        {
System.Diagnostics.HttpRawTraceListener.Initialize();
System.Diagnostics.HttpRawTraceListener.FinishedCommunication += System.Diagnostics.HttpRawTraceListener_FinishedCommunication;

... Rest of code for Main() ...
        }



static async Task CreateConsentAsync(Uri HTTPaddress, ConsentHeaders cconsentHeaders, ConsentBody cconsent)
{
	HttpClient client = new HttpClient();

	try
	{
		client.BaseAddress = HTTPaddress;
		client.DefaultRequestHeaders.Accept.Clear();
		client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("*/*"));
		client.DefaultRequestHeaders.Add("Connection", "keep-alive");
		client.DefaultRequestHeaders.Add("Cache-Control", "no-cache");
		//add more headears here as per your needs..
		client.DefaultRequestHeaders.Add("my header", yourValue);
		//...

		HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, client.BaseAddress);

		request.Content = new StringContent(JsonConvert.SerializeObject(cconsent, Formatting.Indented), System.Text.Encoding.UTF8, "application/json");

		Console.WriteLine("POST Request: " + "\r\n" + client.DefaultRequestHeaders + "\r\n" + JsonConvert.SerializeObject(cconsent, Formatting.Indented) + "\r\n");

		await client.SendAsync(request).ContinueWith(responseTask => {Console.WriteLine("Response:\r\n{0}", responseTask.Result.Content.ReadAsStringAsync().Result);});

		Console.ReadLine();
	}
	catch (Exception e)
	{
		Console.WriteLine("Error in " + e.TargetSite + "\r\n" + e.Message);
		Console.ReadLine();
	}
}

public static void HttpRawTraceListener_FinishedCommunication(object sender, System.Diagnostics.CommunicationEventArgs e)
                {
                    Console.WriteLine("Raw Request: " + e.Communication.RequestString);
                    Console.WriteLine("Raw Response: " + e.Communication.ResponseString); 
                }

Open in new window

N MConsultant

Author

Commented:
Thank you very much!