Working with HttpClient in ASP.NET Core

Integrating external APIs is a common task in modern web applications. In ASP.NET Core Razor Pages, HttpClient is the preferred class for making HTTP requests. This post walks you through how to use HttpClient in ASP.NET Core, avoid common pitfalls, and demonstrate how to integrate it effectively in a modern application.

Working with HttpClient in ASP.NET Core

Getting Started

When building modern applications, consuming external APIs is common. In ASP.NET Core, the recommended way to make HTTP requests is using the built-in HttpClient.

HttpClient is a class provided by the .NET framework for sending HTTP requests and receiving responses from web APIs or web services. It supports:

  • Sending asynchronous HTTP requests (GET, POST, PUT, DELETE)
  • Handling headers, cookies, and authentication.
  • Working with JSON and other content types.

Basic Usage of HttpClient

 public class MyApiClient  
 {  
   private readonly HttpClient _httpClient;  
   public MyApiClient(HttpClient httpClient)  
   {  
     _httpClient = httpClient;  
     _httpClient.BaseAddress = new Uri("https://api.example.com/");  
   }  
   public async Task<string> GetDataAsync()  
   {  
     var response = await _httpClient.GetAsync("data");  
     response.EnsureSuccessStatusCode();  
     return await response.Content.ReadAsStringAsync();  
   }  
 }  

Note:- Avoid initiating to HttpClient directly, A common mistake is to instantiate HttpClient directly using new HttpClient(). This can lead to socket exhaustion, especially under load, due to how DNS is handled internally by HttpClient. Instead, user the IHttpClientFactory which is provided by ASP.NET Core to create and manage HttpClient instances efficiently.

Steps to Intigrate HttpClient

Integrating HttpClient in ASP.NET Core is a common task for calling external APIs or services. ASP.NET Core provides a few best-practice ways to do this using dependency injection and HttpClientFactory, which avoids common pitfalls like socket exhaustion.

Here are the steps to integrate HttpClient in ASP.NET Core:

Register HttpClient in Startup.cs or Program.cs
In .NET 6+ (Minimal Hosting Model):
// Program.cs
var builder = WebApplication.CreateBuilder(args);
// Register a basic HttpClient
builder.Services.AddHttpClient();
// OR named client
builder.Services.AddHttpClient("MyApiClient", client =>
{
  client.BaseAddress = new Uri("https://api.example.com/");
  client.DefaultRequestHeaders.Add("Accept", "application/json");
  });

In .NET Core 3.1 or .NET 5 (with Startup.cs):
public void ConfigureServices(IServiceCollection services)
{
  services.AddHttpClient();
}

Inject HttpClient into your service or controller
HttpClient can be inject in three ways as given below.

Using Default HttpClient
public class MyService
{
  private readonly HttpClient _httpClient;
  public MyService(HttpClient httpClient)
  {
    _httpClient = httpClient;
  }
  public async Task<string> GetDataAsync()
  {
    var response = await _httpClient.GetAsync("https://api.example.com/data");
    return await response.Content.ReadAsStringAsync();
  }
}

Register the Service:
services.AddTransient<MyService>();

Using a Named Client
public class MyService
{
  private readonly HttpClient _httpClient;
  public MyService(IHttpClientFactory httpClientFactory)
  {
    _httpClient = httpClientFactory.CreateClient("MyApiClient");
  }
  public async Task<string> GetDataAsync()
  {
    var response = await _httpClient.GetAsync("endpoint");
    return await response.Content.ReadAsStringAsync();
  }
}

Using a Typed Client
This is a best practice for APIs. Create a typed client class:
public class MyApiClient
{
  private readonly HttpClient _httpClient;
  public MyApiClient(HttpClient httpClient)
  {
    _httpClient = httpClient;
  }
  public async Task<string> GetDataAsync()
  {
    var response = await _httpClient.GetAsync("data");
    return await response.Content.ReadAsStringAsync();
  }
}

Register it like this:

builder.Services.AddHttpClient<MyApiClient>(client =>
{
  client.BaseAddress = new Uri("https://api.example.com/");
  });

Use it in your controller
public class HomeController : Controller
{
  private readonly MyApiClient _apiClient;
  public HomeController(MyApiClient apiClient)
  {
    _apiClient = apiClient;
  }
  public async Task<IActionResult> Index()
  {
    var data = await _apiClient.GetDataAsync();
    return Content(data);
  }
}

Handle Errors and Timeouts Gracefully
Add policies (like retry, circuit breaker) using Polly:
builder.Services.AddHttpClient("MyApiClient")
.AddTransientHttpErrorPolicy(policy =>
policy.WaitAndRetryAsync(3, _ => TimeSpan.FromMilliseconds(600)));

Testing

Here basic code to test the HttpClient using HttpMessageHandler mocking.

var handlerMock = new Mock<HttpMessageHandler>();
handlerMock
.Protected()
.Setup<Task<HttpResponseMessage>>(
"SendAsync",
ItExpr.IsAny<HttpRequestMessage>(),
ItExpr.IsAny<CancellationToken>()
)
.ReturnsAsync(new HttpResponseMessage
{
  StatusCode = HttpStatusCode.OK,
  Content = new StringContent("{'key':'value'}"),
  });
  var httpClient = new HttpClient(handlerMock.Object);

Summary

HttpClient is a powerful tool in ASP.NET Core, but using it correctly is critical for performance, reliability, and testability. Always prefer HttpClientFactory and consider typed clients for clean, testable code.

Thanks

Kailash Chandra Behera

I am an IT professional with over 13 years of experience in the full software development life cycle for Windows, services, and web-based applications using Microsoft .NET technologies.

Previous Post Next Post

نموذج الاتصال