Table of contents

How do I use HttpClient (C#) to make a request to a REST API?

HttpClient is the standard way to make HTTP requests to REST APIs in C#. This guide covers everything from basic setup to advanced features and best practices.

Required Namespaces

First, include the necessary namespaces:

using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;

Best Practice: Use HttpClientFactory (Recommended)

In modern .NET applications, use IHttpClientFactory instead of creating HttpClient instances directly:

// In Startup.cs or Program.cs
services.AddHttpClient();

// In your service or controller
public class ApiService
{
    private readonly HttpClient _httpClient;

    public ApiService(HttpClient httpClient)
    {
        _httpClient = httpClient;
    }
}

Basic HttpClient Setup

For simple scenarios, you can create an HttpClient instance:

using var client = new HttpClient();
client.BaseAddress = new Uri("https://api.example.com/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(
    new MediaTypeWithQualityHeaderValue("application/json"));

Authentication Headers

Add authentication headers for secured APIs:

// Bearer token
client.DefaultRequestHeaders.Authorization = 
    new AuthenticationHeaderValue("Bearer", "your-token-here");

// API Key
client.DefaultRequestHeaders.Add("X-API-Key", "your-api-key");

// Basic authentication
var credentials = Convert.ToBase64String(
    Encoding.ASCII.GetBytes("username:password"));
client.DefaultRequestHeaders.Authorization = 
    new AuthenticationHeaderValue("Basic", credentials);

GET Requests

Simple GET Request

public async Task<string> GetDataAsync()
{
    try
    {
        HttpResponseMessage response = await client.GetAsync("api/users");
        response.EnsureSuccessStatusCode();

        string content = await response.Content.ReadAsStringAsync();
        return content;
    }
    catch (HttpRequestException ex)
    {
        Console.WriteLine($"Request error: {ex.Message}");
        throw;
    }
}

GET with Query Parameters

public async Task<string> GetUsersAsync(int page, int limit)
{
    string endpoint = $"api/users?page={page}&limit={limit}";
    HttpResponseMessage response = await client.GetAsync(endpoint);
    response.EnsureSuccessStatusCode();

    return await response.Content.ReadAsStringAsync();
}

Deserialize JSON Response

public async Task<List<User>> GetUsersAsync()
{
    HttpResponseMessage response = await client.GetAsync("api/users");
    response.EnsureSuccessStatusCode();

    string json = await response.Content.ReadAsStringAsync();
    var users = JsonSerializer.Deserialize<List<User>>(json, new JsonSerializerOptions
    {
        PropertyNameCaseInsensitive = true
    });

    return users;
}

POST Requests

POST with JSON Data

public async Task<User> CreateUserAsync(User newUser)
{
    string json = JsonSerializer.Serialize(newUser);
    var content = new StringContent(json, Encoding.UTF8, "application/json");

    HttpResponseMessage response = await client.PostAsync("api/users", content);
    response.EnsureSuccessStatusCode();

    string responseJson = await response.Content.ReadAsStringAsync();
    return JsonSerializer.Deserialize<User>(responseJson, new JsonSerializerOptions
    {
        PropertyNameCaseInsensitive = true
    });
}

POST with Form Data

public async Task<string> PostFormDataAsync()
{
    var formData = new List<KeyValuePair<string, string>>
    {
        new("name", "John Doe"),
        new("email", "john@example.com"),
        new("age", "30")
    };

    using var content = new FormUrlEncodedContent(formData);
    HttpResponseMessage response = await client.PostAsync("api/users", content);
    response.EnsureSuccessStatusCode();

    return await response.Content.ReadAsStringAsync();
}

PUT and DELETE Requests

PUT Request (Update)

public async Task<User> UpdateUserAsync(int userId, User updatedUser)
{
    string json = JsonSerializer.Serialize(updatedUser);
    var content = new StringContent(json, Encoding.UTF8, "application/json");

    HttpResponseMessage response = await client.PutAsync($"api/users/{userId}", content);
    response.EnsureSuccessStatusCode();

    string responseJson = await response.Content.ReadAsStringAsync();
    return JsonSerializer.Deserialize<User>(responseJson);
}

DELETE Request

public async Task<bool> DeleteUserAsync(int userId)
{
    HttpResponseMessage response = await client.DeleteAsync($"api/users/{userId}");
    return response.IsSuccessStatusCode;
}

Error Handling and Status Codes

public async Task<ApiResponse<T>> MakeRequestAsync<T>(string endpoint)
{
    try
    {
        HttpResponseMessage response = await client.GetAsync(endpoint);

        if (response.IsSuccessStatusCode)
        {
            string content = await response.Content.ReadAsStringAsync();
            var data = JsonSerializer.Deserialize<T>(content);
            return new ApiResponse<T> { Success = true, Data = data };
        }
        else
        {
            return new ApiResponse<T> 
            { 
                Success = false, 
                ErrorMessage = $"HTTP {response.StatusCode}: {response.ReasonPhrase}" 
            };
        }
    }
    catch (HttpRequestException ex)
    {
        return new ApiResponse<T> 
        { 
            Success = false, 
            ErrorMessage = $"Request failed: {ex.Message}" 
        };
    }
    catch (TaskCanceledException ex) when (ex.InnerException is TimeoutException)
    {
        return new ApiResponse<T> 
        { 
            Success = false, 
            ErrorMessage = "Request timeout" 
        };
    }
}

Complete Example with Best Practices

using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;

public class RestApiClient
{
    private readonly HttpClient _httpClient;

    public RestApiClient(HttpClient httpClient)
    {
        _httpClient = httpClient;
        _httpClient.BaseAddress = new Uri("https://jsonplaceholder.typicode.com/");
        _httpClient.DefaultRequestHeaders.Accept.Clear();
        _httpClient.DefaultRequestHeaders.Accept.Add(
            new MediaTypeWithQualityHeaderValue("application/json"));
        _httpClient.Timeout = TimeSpan.FromSeconds(30);
    }

    public async Task<Post[]> GetPostsAsync()
    {
        try
        {
            HttpResponseMessage response = await _httpClient.GetAsync("posts");
            response.EnsureSuccessStatusCode();

            string json = await response.Content.ReadAsStringAsync();
            return JsonSerializer.Deserialize<Post[]>(json, new JsonSerializerOptions
            {
                PropertyNameCaseInsensitive = true
            });
        }
        catch (HttpRequestException ex)
        {
            Console.WriteLine($"HTTP Request failed: {ex.Message}");
            throw;
        }
        catch (JsonException ex)
        {
            Console.WriteLine($"JSON deserialization failed: {ex.Message}");
            throw;
        }
    }

    public async Task<Post> CreatePostAsync(Post newPost)
    {
        try
        {
            string json = JsonSerializer.Serialize(newPost);
            var content = new StringContent(json, Encoding.UTF8, "application/json");

            HttpResponseMessage response = await _httpClient.PostAsync("posts", content);
            response.EnsureSuccessStatusCode();

            string responseJson = await response.Content.ReadAsStringAsync();
            return JsonSerializer.Deserialize<Post>(responseJson, new JsonSerializerOptions
            {
                PropertyNameCaseInsensitive = true
            });
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Create post failed: {ex.Message}");
            throw;
        }
    }
}

public class Post
{
    public int Id { get; set; }
    public int UserId { get; set; }
    public string Title { get; set; }
    public string Body { get; set; }
}

// Usage example
class Program
{
    static async Task Main(string[] args)
    {
        using var httpClient = new HttpClient();
        var apiClient = new RestApiClient(httpClient);

        // Get all posts
        Post[] posts = await apiClient.GetPostsAsync();
        Console.WriteLine($"Retrieved {posts.Length} posts");

        // Create a new post
        var newPost = new Post
        {
            UserId = 1,
            Title = "My New Post",
            Body = "This is the content of my new post."
        };

        Post createdPost = await apiClient.CreatePostAsync(newPost);
        Console.WriteLine($"Created post with ID: {createdPost.Id}");
    }
}

Key Best Practices

  1. Use HttpClientFactory in production applications
  2. Reuse HttpClient instances - don't create new instances for each request
  3. Set appropriate timeouts to prevent hanging requests
  4. Handle exceptions properly with try-catch blocks
  5. Use async/await for better performance and scalability
  6. Dispose resources with using statements when creating HttpClient directly
  7. Validate SSL certificates in production (enabled by default)
  8. Use strongly-typed models for JSON serialization/deserialization

Try WebScraping.AI for Your Web Scraping Needs

Looking for a powerful web scraping solution? WebScraping.AI provides an LLM-powered API that combines Chromium JavaScript rendering with rotating proxies for reliable data extraction.

Key Features:

  • AI-powered extraction: Ask questions about web pages or extract structured data fields
  • JavaScript rendering: Full Chromium browser support for dynamic content
  • Rotating proxies: Datacenter and residential proxies from multiple countries
  • Easy integration: Simple REST API with SDKs for Python, Ruby, PHP, and more
  • Reliable & scalable: Built for developers who need consistent results

Getting Started:

Get page content with AI analysis:

curl "https://api.webscraping.ai/ai/question?url=https://example.com&question=What is the main topic?&api_key=YOUR_API_KEY"

Extract structured data:

curl "https://api.webscraping.ai/ai/fields?url=https://example.com&fields[title]=Page title&fields[price]=Product price&api_key=YOUR_API_KEY"

Try in request builder

Related Questions

Get Started Now

WebScraping.AI provides rotating proxies, Chromium rendering and built-in HTML parser for web scraping
Icon