Mastering Async in .NET 8

Explore the power of asynchronous programming in .NET 8 with our comprehensive demonstration. Learn how to enhance your web applications with modern async patterns, including HttpClient decorators, HttpClientFactory integration, Polly resilience strategies, and advanced logging and telemetry.

Async with HttpClient

Discover how to make efficient asynchronous HTTP requests using HttpClient and leverage the decorator pattern for enhanced functionality like retry, logging, and caching.

Polly & HttpClientFactory

Learn to create resilient HTTP clients with HttpClientFactory and Polly, implementing strategies such as retries, circuit breakers, and more, all using async methods.

Logging & Telemetry

Integrate robust async logging and telemetry in your .NET 8 applications. Track performance, monitor errors, and gather insights with minimal impact on your application's performance.

Decorator Pattern with HttpClient

The Decorator Pattern is a structural design pattern that allows behavior to be added to individual objects, dynamically, without affecting the behavior of other objects from the same class. In this demo, we showcase how to use the decorator pattern with HttpClient to add features such as logging, retries, and error handling in a modular and maintainable way.

Example: HttpClient Logging Decorator


// Base Decorator Class
public class HttpClientDecorator : HttpClient
{
    protected readonly HttpClient _client;

    public HttpClientDecorator(HttpClient client)
    {
        _client = client;
    }
}

// Logging Decorator
public class LoggingHttpClientDecorator : HttpClientDecorator
{
    public LoggingHttpClientDecorator(HttpClient client) : base(client) { }

    public async Task GetAsync(string requestUri)
    {
        Console.WriteLine($"Making request to {requestUri}");
        var response = await _client.GetAsync(requestUri);
        Console.WriteLine($"Received response: {response.StatusCode}");
        return response;
    }
}
            

Example: Adding Resilience with Polly

Polly is a .NET resilience and transient-fault-handling library that allows you to define policies such as retries, circuit breakers, and fallbacks. Below is an example of how to integrate Polly with HttpClient using the decorator pattern:


// Polly Decorator
public class PollyHttpClientDecorator : HttpClientDecorator
{
    public PollyHttpClientDecorator(HttpClient client) : base(client) { }

    public async Task GetAsync(string requestUri)
    {
        var retryPolicy = Policy
            .Handle()
            .WaitAndRetryAsync(3, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)));

        return await retryPolicy.ExecuteAsync(() => _client.GetAsync(requestUri));
    }
}
            

By combining different decorators, you can build a powerful, extensible HttpClient that can handle a variety of cross-cutting concerns such as logging and error handling without cluttering your business logic.

Best Practices for Using Decorators

  • Single Responsibility: Each decorator should handle one specific concern, such as logging or retries, keeping the implementation clean and focused.
  • Dependency Injection: Use dependency injection to manage decorators, allowing for easy swapping and configuration.
  • Testing: Decorators should be independently testable, ensuring each functionality can be verified in isolation.