Table of contents

How do I handle JSON data with HttpClient (C#)?

Working with JSON data is essential when building web applications and APIs in C#. HttpClient provides robust support for sending and receiving JSON data. This guide covers modern approaches using both System.Text.Json and Newtonsoft.Json.

Sending JSON Data

Modern Approach with System.Text.Json (.NET Core 3.0+)

The recommended approach for modern .NET applications uses System.Text.Json for serialization:

using System;
using System.Net.Http;
using System.Net.Http.Json; // For JSON extension methods
using System.Text.Json;
using System.Threading.Tasks;

public class User
{
    public string Name { get; set; }
    public int Age { get; set; }
    public string Email { get; set; }
}

class Program
{
    private static readonly HttpClient httpClient = new HttpClient();

    static async Task Main()
    {
        var user = new User
        {
            Name = "John Doe",
            Age = 30,
            Email = "john@example.com"
        };

        try
        {
            // Using PostAsJsonAsync (recommended for .NET 5+)
            var response = await httpClient.PostAsJsonAsync("https://api.example.com/users", user);

            response.EnsureSuccessStatusCode();

            var responseContent = await response.Content.ReadAsStringAsync();
            Console.WriteLine($"Response: {responseContent}");
        }
        catch (HttpRequestException ex)
        {
            Console.WriteLine($"HTTP Error: {ex.Message}");
        }
        catch (JsonException ex)
        {
            Console.WriteLine($"JSON Error: {ex.Message}");
        }
    }
}

Manual Serialization Approach

For more control over serialization options:

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

class Program
{
    private static readonly HttpClient httpClient = new HttpClient();

    static async Task Main()
    {
        var user = new User
        {
            Name = "Jane Smith",
            Age = 25,
            Email = "jane@example.com"
        };

        // Configure serialization options
        var options = new JsonSerializerOptions
        {
            PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
            WriteIndented = true
        };

        try
        {
            // Manual serialization
            var jsonString = JsonSerializer.Serialize(user, options);
            var content = new StringContent(jsonString, Encoding.UTF8, "application/json");

            var response = await httpClient.PostAsync("https://api.example.com/users", content);
            response.EnsureSuccessStatusCode();

            var responseBody = await response.Content.ReadAsStringAsync();
            Console.WriteLine($"Created user: {responseBody}");
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Error: {ex.Message}");
        }
    }
}

Receiving JSON Data

Using GetFromJsonAsync (.NET 5+)

The simplest approach for deserializing JSON responses:

using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Json;
using System.Text.Json;
using System.Threading.Tasks;

public class ApiResponse<T>
{
    public bool Success { get; set; }
    public T Data { get; set; }
    public string Message { get; set; }
}

class Program
{
    private static readonly HttpClient httpClient = new HttpClient();

    static async Task Main()
    {
        try
        {
            // Direct deserialization
            var user = await httpClient.GetFromJsonAsync<User>("https://api.example.com/users/1");
            Console.WriteLine($"User: {user.Name}, Age: {user.Age}");

            // Getting a collection
            var users = await httpClient.GetFromJsonAsync<List<User>>("https://api.example.com/users");
            foreach (var u in users)
            {
                Console.WriteLine($"User: {u.Name}");
            }

            // Getting wrapped response
            var response = await httpClient.GetFromJsonAsync<ApiResponse<User>>("https://api.example.com/users/1");
            if (response.Success)
            {
                Console.WriteLine($"Retrieved: {response.Data.Name}");
            }
        }
        catch (HttpRequestException ex)
        {
            Console.WriteLine($"HTTP Error: {ex.Message}");
        }
        catch (JsonException ex)
        {
            Console.WriteLine($"JSON Parsing Error: {ex.Message}");
        }
    }
}

Manual Deserialization with Error Handling

For more control over error handling and response processing:

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

class Program
{
    private static readonly HttpClient httpClient = new HttpClient();

    static async Task Main()
    {
        try
        {
            var response = await httpClient.GetAsync("https://api.example.com/users/1");

            if (response.IsSuccessStatusCode)
            {
                var jsonString = await response.Content.ReadAsStringAsync();

                var options = new JsonSerializerOptions
                {
                    PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
                    PropertyNameCaseInsensitive = true
                };

                var user = JsonSerializer.Deserialize<User>(jsonString, options);
                Console.WriteLine($"Name: {user.Name}, Age: {user.Age}");
            }
            else
            {
                Console.WriteLine($"Error: {response.StatusCode} - {response.ReasonPhrase}");

                if (response.StatusCode == HttpStatusCode.NotFound)
                {
                    Console.WriteLine("User not found");
                }
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Error: {ex.Message}");
        }
    }
}

Using Newtonsoft.Json (Legacy/Alternative)

If you prefer or need to use Newtonsoft.Json:

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

class Program
{
    private static readonly HttpClient httpClient = new HttpClient();

    static async Task Main()
    {
        var user = new User { Name = "Bob Wilson", Age = 35 };

        try
        {
            // Sending JSON
            var jsonString = JsonConvert.SerializeObject(user);
            var content = new StringContent(jsonString, Encoding.UTF8, "application/json");

            var response = await httpClient.PostAsync("https://api.example.com/users", content);
            response.EnsureSuccessStatusCode();

            // Receiving JSON
            var responseBody = await response.Content.ReadAsStringAsync();
            var createdUser = JsonConvert.DeserializeObject<User>(responseBody);

            Console.WriteLine($"Created: {createdUser.Name}");
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Error: {ex.Message}");
        }
    }
}

Advanced Scenarios

Handling Different Content Types

public static async Task<T> GetJsonAsync<T>(this HttpClient client, string url)
{
    var response = await client.GetAsync(url);
    response.EnsureSuccessStatusCode();

    var contentType = response.Content.Headers.ContentType?.MediaType;
    if (contentType != "application/json")
    {
        throw new InvalidOperationException($"Expected JSON content, got {contentType}");
    }

    var jsonString = await response.Content.ReadAsStringAsync();
    return JsonSerializer.Deserialize<T>(jsonString);
}

Custom JSON Options

public static class JsonConfig
{
    public static readonly JsonSerializerOptions DefaultOptions = new()
    {
        PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
        PropertyNameCaseInsensitive = true,
        DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
        WriteIndented = false
    };
}

// Usage
var user = await httpClient.GetFromJsonAsync<User>("https://api.example.com/users/1", JsonConfig.DefaultOptions);

Best Practices

  1. Use IHttpClientFactory: For production applications, use dependency injection with IHttpClientFactory to manage HttpClient instances properly.

  2. Configure JSON Options: Set up consistent JSON serialization options across your application.

  3. Handle Errors Gracefully: Always handle HTTP errors, JSON parsing errors, and network timeouts.

  4. Use Strongly Typed Models: Define classes that match your JSON structure for better type safety.

  5. Set Timeouts: Configure appropriate timeouts for your HTTP requests.

// Example with IHttpClientFactory and proper configuration
public class UserService
{
    private readonly HttpClient _httpClient;
    private readonly JsonSerializerOptions _jsonOptions;

    public UserService(HttpClient httpClient)
    {
        _httpClient = httpClient;
        _jsonOptions = new JsonSerializerOptions
        {
            PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
            PropertyNameCaseInsensitive = true
        };
    }

    public async Task<User> GetUserAsync(int id)
    {
        try
        {
            return await _httpClient.GetFromJsonAsync<User>($"users/{id}", _jsonOptions);
        }
        catch (HttpRequestException ex)
        {
            throw new ServiceException($"Failed to retrieve user {id}", ex);
        }
    }

    public async Task<User> CreateUserAsync(User user)
    {
        try
        {
            var response = await _httpClient.PostAsJsonAsync("users", user, _jsonOptions);
            response.EnsureSuccessStatusCode();
            return await response.Content.ReadFromJsonAsync<User>(_jsonOptions);
        }
        catch (HttpRequestException ex)
        {
            throw new ServiceException("Failed to create user", ex);
        }
    }
}

This comprehensive approach ensures robust JSON handling with proper error management and follows modern .NET best practices.

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