Announcing HttpClientDiagnostics


2 minute read - suggest an edit

HttpClientDiagnostics is a cross platform, portable class library that provides tracing/logging telemetry of Microsoft.Net.HttpClient requests. In the spirit of “applications decide the logging framework, libraries should play nice” this package does not require any external dependencies or abstractions like Common.Logging. Logging all happens automatically, behind the scenes, without you needing to know how or care how to wire this up thanks to the amazing LibLog. It’s like magic! Its the future.

Supported Platforms

  • .NET 4.5
  • Mono
  • Xamarin.iOS
  • Xamarin.Android
  • Xamarin.Mac
  • UWP

Installation

Installation is done via NuGet:

Install-Package HttpClientDiagnostics

Usage

HttpClient client = new HttpClient(new HttpClientDiagnosticsHandler(new HttpClientHandler()));
HttpResponseMessage response = await client.GetStringAsync("https://api.duckduckgo.com/?q=apple&format=json");

Which will automatically yield in your application logs:

2016-05-04 18:45:19.291 +10:00 [Debug] Request: Method: GET, RequestUri: 'https://api.duckduckgo.com/?q=apple&format=json', Version: 1.1, Content: <null>, Headers:
{
}
2016-05-04 18:45:21.264 +10:00 [Debug] Response: StatusCode: 200, ReasonPhrase: 'OK', Version: 1.1, Content: System.Net.Http.StreamContent, Headers:
{
  Connection: keep-alive
  Strict-Transport-Security: max-age=0
  X-DuckDuckGo-Locale: en_US
  Cache-Control: max-age=1
  Date: Wed, 04 May 2016 08:45:21 GMT
  Server: nginx
  Content-Length: 23528
  Content-Type: application/x-javascript
  Expires: Wed, 04 May 2016 08:45:22 GMT
}
2016-05-04 18:45:21.681 +10:00 [Debug] Response Content: {"Result":"<a href=\"https://duckduckgo.com/Apple\">Apple</a>A deciduous tree in the rose family best known for its sweet, pomaceous fruit, the apple.}
2016-05-04 18:45:22.074 +10:00 [Debug] Response elapsed time: 2750 ms
2016-05-04 18:45:22.077 +10:00 [Debug] Total elapsed time: 2788 ms

Advanced Usage

The constructor of HttpClientDiagnosticsHandler can take another HttpMessageHandler which provides you with a way to chain multiple handlers together. A common scenario would be using Refit to automatically convert interface definitions into REST clients and integrating with ModernHttpClient for performance improvements, Fusillade for auto-deduplication of requests/request limiting/request prioritization and then finally your own custom handler that handles REST API authentication, authorization/security in a single and central place. Which looks something like this….

public interface IDuckDuckGoApi
{
    [Get("/?q={query}&format=json")]
    IObservable<DuckDuckGoSearchResult> Search(string query);
}

public class DuckDuckGoApiService : IDuckDuckGoApiService
{
    public const string ApiBaseAddress = "https://api.duckduckgo.com";

    private readonly Lazy<IDuckDuckGoApi> _background;
    private readonly Lazy<IDuckDuckGoApi> _speculative;
    private readonly Lazy<IDuckDuckGoApi> _userInitiated;

    public DuckDuckGoApiService(string apiBaseAddress = null, bool enableDiagnostics = false)
    {
        Func<HttpMessageHandler, IDuckDuckGoApi> createClient = innerHandler =>
        {
            HttpMessageHandler handler;

            if (enableDiagnostics)
            {
                handler = new HttpClientDiagnosticsHandler(innerHandler);
            }
            else
            {
                handler = messageHandler;
            }

            var client = new HttpClient(handler)
            {
                BaseAddress = new Uri(apiBaseAddress ?? ApiBaseAddress)
            };

            return RestService.For<IDuckDuckGoApi>(client);
        };

        _background = new Lazy<IDuckDuckGoApi>(() => createClient(
            new RateLimitedHttpMessageHandler(new NativeMessageHandler(), Priority.Background)));

        _userInitiated = new Lazy<IDuckDuckGoApi>(() => createClient(
            new RateLimitedHttpMessageHandler(new NativeMessageHandler(), Priority.UserInitiated)));

        _speculative = new Lazy<IDuckDuckGoApi>(() => createClient(
            new RateLimitedHttpMessageHandler(new NativeMessageHandler(), Priority.Speculative)));
    }

    public IDuckDuckGoApi Background => _background.Value;
    public IDuckDuckGoApi Speculative => _speculative.Value;
    public IDuckDuckGoApi UserInitiated => _userInitiated.Value;
}

Related Posts

ReactiveUI v7.2.0 released

Learn these three buttons

Announcing ReactiveUI virtual community meetups

ReactiveUI v7.1.0 released

ReactiveUI v7.0.0 released

Semantic Versioning of Xamarin Applications

Announcing Serilog.Sinks.Xamarin

Announcing Cake.Raygun

Announcing Cake.AppleSimulator

Example of Xamarin iOS with Cake