Logging request/response messages when using HttpClient
An example of how you could do this:
Some notes:
LoggingHandler
intercepts the request before it handles it toHttpClientHandler
which finally writes to the wire.PostAsJsonAsync
extension internally creates anObjectContent
and whenReadAsStringAsync()
is called in theLoggingHandler
, it causes the formatter
insideObjectContent
to serialize the object and that's the reason you are seeing the content in json.
Logging handler:
public class LoggingHandler : DelegatingHandler
{
public LoggingHandler(HttpMessageHandler innerHandler)
: base(innerHandler)
{
}
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
Console.WriteLine("Request:");
Console.WriteLine(request.ToString());
if (request.Content != null)
{
Console.WriteLine(await request.Content.ReadAsStringAsync());
}
Console.WriteLine();
HttpResponseMessage response = await base.SendAsync(request, cancellationToken);
Console.WriteLine("Response:");
Console.WriteLine(response.ToString());
if (response.Content != null)
{
Console.WriteLine(await response.Content.ReadAsStringAsync());
}
Console.WriteLine();
return response;
}
}
Chain the above LoggingHandler with HttpClient:
HttpClient client = new HttpClient(new LoggingHandler(new HttpClientHandler()));
HttpResponseMessage response = client.PostAsJsonAsync(baseAddress + "/api/values", "Hello, World!").Result;
Output:
Request:
Method: POST, RequestUri: 'http://kirandesktop:9095/api/values', Version: 1.1, Content: System.Net.Http.ObjectContent`1[
[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], Headers:
{
Content-Type: application/json; charset=utf-8
}
"Hello, World!"
Response:
StatusCode: 200, ReasonPhrase: 'OK', Version: 1.1, Content: System.Net.Http.StreamContent, Headers:
{
Date: Fri, 20 Sep 2013 20:21:26 GMT
Server: Microsoft-HTTPAPI/2.0
Content-Length: 15
Content-Type: application/json; charset=utf-8
}
"Hello, World!"
Reducing HttpClient log verbosity
I managed to exclude these logs using Serilog
, which I was already using in the application.
When setting up the LoggerConfiguration, you can apply "filters", like so:
Log.Logger = new LoggerConfiguration()
.Filter.ByExcluding("SourceContext like '%System.Net.Http.HttpClient%' and @l = 'Information'")
.CreateLogger();
Logging requests, responses and exceptions of WebClient
For calling web service and if you use .Net 4.5, it's easier if you use HttpClient
.
You can create LoggingHandler
like this:
public class LoggingHandler : DelegatingHandler
{
public LoggingHandler()
: this(new HttpClientHandler())
{ }
public LoggingHandler(HttpMessageHandler innerHandler)
: base(innerHandler)
{ }
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var activityId = Guid.NewGuid();
using (new Tracer("Service Call", activityId))
{
var entry = new LogEntry { Severity = TraceEventType.Verbose, Title = "Request" };
if (Logger.ShouldLog(entry))
{
entry.Message = request.ToString();
if (request.Content != null)
{
entry.Message += Environment.NewLine;
entry.Message += await request.Content
.ReadAsStringAsync()
.ConfigureAwait(false);
}
Logger.Write(entry);
}
var response = await base.SendAsync(request, cancellationToken).ConfigureAwait(false);
entry = new LogEntry { Severity = TraceEventType.Verbose, Title = "Response" };
if (Logger.ShouldLog(entry))
{
entry.Message = response.ToString();
if (response.Content != null)
entry.Message += await response.Content
.ReadAsStringAsync()
.ConfigureAwait(false);
Logger.Write(entry);
}
return response;
}
}
}
And then create HttpClient:
//hook all http request and response
var hc = new HttpClient(new LoggingHandler());
Documentation for HttpClient
class:
https://msdn.microsoft.com/en-us/library/system.net.http.httpclient%28v=vs.118%29.aspx
Comparing HttpClient
and WebClient
Need help deciding between HttpClient and WebClient
ASP.NET Core 3.1 HttpClient to log only warnings and errors
You can configure Logging in .NET Core through the Appsettings file. You should find a section in the appsettings.json
file along the lines
{
"Logging": {
"Debug": {
"LogLevel": {
"Default": "Information"
}
}
}
}
You can add an additional Log Level filter to specify the minimum log level required to log.
{
"Logging": {
"Debug": {
"LogLevel": {
"Default": "Information",
"System.Net.Http.HttpClient": "Debug"
}
}
}
}
Documentation for Logging with filters in .NET Core can be found here.
Documemtation for Logging with filters in the IHttpClientFactory library can be found here. This documentation also includes examples of log filtering with a named HttpClient.
Get the raw request that is sent with HttpClient and HttpRequestMessage
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 Topics
Memory Allocation: Stack VS Heap
How to Enable Nuget Package Restore in Visual Studio
How to Get an Oauth 2.0 Authentication Token in C#
How to Get More Than 1000 Records from a Directorysearcher
Checking If a Bit Is Set or Not
C# Rsa Encryption/Decryption with Transmission
The Name 'Configurationmanager' Does Not Exist in the Current Context
Setting Canvas Properties in an Itemscontrol Datatemplate
How to Delete Cookies from Windows.Form
Windows Forms Splash Screen - Show a Form While Loading Main Form
Visual Studio "Could Not Copy" .... During Build
Linq Select Distinct with Anonymous Types
Advantages of Cache VS Session
How to Create a Hashcode in .Net (C#) for a String That Is Safe to Store in a Database