Get the raw request that is sent with HttpClient and HttpRequestMessage - .net-core

In my C# code running .NET 6 (Azure Function) I am sending an HttpRequestMessage using HttpClient. It doesn't work but it should work, so I want to get the raw request that I am sending, including the header, so I can compare with the documentation and see the differences.
In the past I have used Fiddler but it doesn't work for me now, probably because of some security settings on my laptop. So I am looking for a solution within the world of Visual Studio 2022 or .NET 6 where I can get the raw request out for troubleshooting purposes.
This question is not really about code, but here is my code anyway.
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, "https://myendpoint.com/rest/something");
var apiToken = "AOU9FrasdgasdfagtHJNV";
request.Headers.Add("Authorization", "Basic " + apiToken);
var message = new
{
sender = "Hey",
message = "Hello world",
recipients = new[] { new { id = 12345678} }
};
request.Content = new StringContent(JsonSerializer.Serialize(message), Encoding.UTF8, "application/json");
request.Headers.Add("Accept", "application/json, text/javascript");
HttpResponseMessage response = await httpClient.SendAsync(request);
When SendAsync is invoked, I wish to know what exactly is sent, both header and content.

If you cannot use any proxy solution (like Fiddler) then I can see 2 options. One is described in comments in your question to use DelegatingHandler. You can read more about this in documentation. What is interesting is that HttpClient supports logging out of the box which is described in this section https://learn.microsoft.com/en-us/aspnet/core/fundamentals/http-requests?view=aspnetcore-6.0#logging of the article which describes DelegatingHandlers
If you are worried that something will manipulate the outgoing request then you can implement option 2. This is to create temporary asp.net core application with .UseHttpLogging() middleware plugged in into pipeline as described here https://learn.microsoft.com/en-us/aspnet/core/fundamentals/http-logging/?view=aspnetcore-6.0 That way you will know exactly how your request looks like from application which is being requested point of view. Now if you will point your azure function to you temporary app - you should see what gets send
Hope it helps

Related

HttpClient on ASP.NET Core application times out when connecting to service on localhost

I have a XML-RPC server (using XML-RPC.net) running as a .NET console application. I'm trying to connect to it via my ASP.NET Core (2.1.1) web app but the client keeps timing out. Postman also returns a response immediately without issues.
Here is how I'm calling it:
HttpClient client = _clientFactory.CreateClient();
client.Timeout = TimeSpan.FromSeconds(10);
var httpRequest = new HttpRequestMessage(HttpMethod.Post, instance.ServiceUrl);
var stringContent = new ByteArrayContent(Encoding.UTF8.GetBytes(request.ToString()));
httpRequest.Content = stringContent;
httpRequest.Content.Headers.ContentType = MediaTypeHeaderValue.Parse("text/xml");
var httpResponse = await client.SendAsync(httpRequest);
var response = await httpResponse.Content.ReadAsByteArrayAsync();
I can see that the request was made successfully as the console app returns a response. Fiddler shows there was a 200 response but await client.SendAsync(httpRequest); times-out!
The request usually completes in under 10ms so the timeout value is just for debugging, if I leave it out it would take 60s. The response returns XML.
I've tried rewriting this to use StringContent and using PostAsync, same issue. I also attempted to rewrite this using WebClient but it returned The remote server returned an error: (100) Continue. not sure if that's relevant.
Been stuck on this for a whie, anyone know what could be happening?
OK I did some googling and it looks like I needed this line:
client.DefaultRequestHeaders.ExpectContinue = true;
It was definitely related to 100 status code returned not being handled properly.
Found it here:
https://social.msdn.microsoft.com/Forums/en-US/042016f0-d70e-42f9-9924-5febeb2bea86/excluding-the-quotexpect-100continuequot-header-from-httpwebrequest-posts?forum=winappswithcsharp

Xamarin Form not able to invoke the Http URL

I am new to Xamarin Cross-Flatform technology (C#). I am developing one small application where I need to call the http url, get the json data, parse it and display it on the screen.
I am using System.Net.Http for achieving the http call.But request is not reaching to http url
Regards,
Amit Joshi
You can use RestSharp for making http calls.
It is very easy to use.
Code sample:
using RestSharp;
var client = new RestClient ("http://rxnav.nlm.nih.gov/REST/RxTerms/rxcui/");
var request = new RestRequest (String.Format ("{0}/allinfo", "198440"));
client.ExecuteAsync (request, response => {
Console.WriteLine (response.Content);
});
RestSharp Examples

Can I take the SessionID returned from the SOAP API and use it in a URL Access call to SSRS?

Two things; first is I keep getting a 401 exception on the last line. I had thought that re-using the session would allow me to not only NOT have to resend the credentials but would also let me access the report by URL. It does neither...
Second, what do I do with the response once I have it to display it in the browser for the User?
This is what I have so far but I am unsure where to go with this from here....
var rs = new ReportExecutionService.ReportExecutionService();
rs.Credentials = new System.Net.NetworkCredential("UserID", "Pswd", "myDomain");
var execInfo = rs.LoadReport("/Nav Reports/OpenSalesOrderByCustomer", null);
var format = "HTML4";
string requestUri = string.Format(
#"https://reports.myServer.com/ReportServer/?{0}&rs:SessionId={1}&rs:Format={2}",
execInfo.ReportPath,
execInfo.ExecutionID,
format
);
WebRequest request = WebRequest.Create(requestUri);
request.UseDefaultCredentials = false;
request.Credentials = new System.Net.NetworkCredential("UserID", "Pswd", "myDomain");
var response = request.GetResponse();
For Background info -->
I am trying to setup Remote Report processing with SSRS on my asp.net web forms app. I would simply use the Report Viewer control but it's hideous looking and not acceptable to our user base. The URL Access returns a much better looking and formatted report and is acceptable but I have to pass Security Credentials. I would use SOAP API except it returns a non-styled html 'blob' and also removes the Toolbar functionality that we want to use.
So, I seem to be left with figuring out a way to use the SOAP API to authenticate a session and then somehow use that to use URL Access.
Just call the SOAP API, get the bytes, and return those bytes to the user with appropriate headers, content-type: application/pdf, content-disposition:attachment;filename=report.pdf. You don't need to do multiple calls to the report server.

Do I need to do something special in the ASP.NET MVC app to read a Json response from a Web API 2 application?

Is there something special I need to define in an ASP.NET MVC application to read an incoming response from a ASP.NET Web API?
From my MVC app, I make a request to an ASP.NET Web API using System.Net.HttpClient. The API receives the request and processes it fine and returns a valid response. However, the MVC application, it appears, never gets the response. I have a break point on the line that makes the request. The flow of control never comes back after executing that line. The MVC app just keeps waiting and times-out after a very long time.
However, I can confirm that the API returns a valid Json response. I have tried composing this request in Chrome Postman and see that the API returns a valid response.
Here's the code from my MVC app that makes the request to the Web API:
public async Task<R> PostAsJsonAsync<T, R>(string uri, T value)
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(_baseUri);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var response = await client.PostAsJsonAsync(uri, value);
if (response.IsSuccessStatusCode) return await response.Content.ReadAsAsync<R>();
else return default(R);
}
}
In the past, i.e. before Web API 2, I've had MVC apps talk to the Web API without any problem. I don't know if I am missing something that has been introduced in Web API 2.
I have a feeling you are getting a deadlock. Are you using .Result anywhere? You should be using async all the way. I mean your MVC action method should also be async method and they should await and not use .Result. Read this log post by Stephen Cleary for more info. http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html

SignalR wth gzip compression

Having some problem developing a SignalR client for a Hub hosted in asp.net website with gzip compression enabled. Since we are using IIS compression, the response from SignalR also gets compressed, but, the client does not understand the response and we get a Json parsing error on the client side.
SignalR internally uses HttpWebRequest to make make http requests and HttpWebRequest can be configured to automatically decompress the response using AutomaticDecompression property. So, if somehow I can get hold of the HttpWebRequest object used by SignalR to make the request, I should be able to set the enable automatic decompression.
I thought I should be able to get access to the HttpWebRequest by providing HubConnection.Start with my custom implementation of IHttpClient, IHttpClient.GetAsync takes a prepareRequest action which I thought should give me access to the HttpWebRequest, but, HttpHelper.GetAsync wraps the HttpWebRequest with HttpWebRequestWrapper before passing to prepareRequest and HttpWebRequestWrapper does not provide access to HttpWebRequest.
HttpHelper class is internal so can't use it as well, so, I am not exactly sure how to enable automatic decompression with SignalR.
I can expose the HttpWebRequest in HttpWebRequestWrapper, but, would prefer a simpler solution if one exists. Any thougths?
I am using SignalR version 0.5.1.10822
My auto decompression HttpClient:
public class HttpClientWithAutoDecompression : IHttpClient
{
readonly DefaultHttpClient _httpClient = new DefaultHttpClient();
private readonly DecompressionMethods _decompressionMethods;
public HttpClientWithAutoDecompression(DecompressionMethods decompressionMethods)
{
_decompressionMethods = decompressionMethods;
}
public Task<IResponse> GetAsync(string url, Action<IRequest> prepareRequest)
{
Task<IResponse> task = _httpClient.GetAsync(url,
request =>
{
[ERROR: request is actually HttpRequestWrapper and
does not expose HttpWebRequest]** ]
var httpWebRequest = (HttpWebRequest) request;
httpWebRequest.AutomaticDecompression = _decompressionMethods;
prepareRequest(request);
});
return task.ContinueWith(response =>
{
Log.Debug(this, "Response: {0}", response.Result.ReadAsString());
return response.Result;
});
}
....
}
To the best of my knowledge GZip encoding and streaming do not mix. In the case of the forever frame transport the client wouldn't be able to decode any on the streaming content until the entire response, or at least a significant block of data, is received (due to the way the data is decoded). In the case of web sockets there is not support for encoding of any kind at this time, although there is apparently an extension to the specification for per message encoding being worked on.
That said, if you wanted to attempt to provide support for the LongPolling transport, the only way I can see this being possible is to provide your own SignalR IHttpClient implementation. You can see right now that the DefaultHttpClient class uses HttpHelper::GetAsync which creates the HttpWebRequest internally and you can never get your hands on that because you only have access to the IRequest which is HttpWebRequestWrapper at that point.
By creating your own IHttpClient you can take over the initial instantiation of the HttpWebRequest, set the AutomaticDecompression and then wrap that up yourself with the HttpWebRequestWrapper.

Resources