Table of contents

How do I read the HTTP status code from an HttpClient (C#) response?

When working with web scraping or API integration in C#, understanding HTTP status codes is crucial for proper error handling and flow control. The HttpClient class provides straightforward access to status codes through the HttpResponseMessage object.

Quick Answer

The HTTP status code is available through the StatusCode property of the HttpResponseMessage object:

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

public class HttpStatusExample
{
    public static async Task Main()
    {
        using var client = new HttpClient();
        HttpResponseMessage response = await client.GetAsync("https://api.example.com/data");

        // Access the status code
        int statusCode = (int)response.StatusCode;
        Console.WriteLine($"Status Code: {statusCode}");

        // Or use the enum value
        Console.WriteLine($"Status: {response.StatusCode}");
    }
}

Understanding HTTP Status Codes

HTTP status codes are three-digit numbers that indicate the result of an HTTP request:

  • 1xx (Informational): Request received, continuing process
  • 2xx (Success): Request successfully received, understood, and accepted
  • 3xx (Redirection): Further action needs to be taken
  • 4xx (Client Error): Request contains bad syntax or cannot be fulfilled
  • 5xx (Server Error): Server failed to fulfill a valid request

Accessing Status Codes in Different Ways

Using the StatusCode Property

The most common approach is to access the StatusCode property directly:

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

public class StatusCodeReader
{
    public static async Task CheckStatus()
    {
        using var client = new HttpClient();
        HttpResponseMessage response = await client.GetAsync("https://api.example.com/endpoint");

        // Get as HttpStatusCode enum
        HttpStatusCode statusCode = response.StatusCode;

        // Get as integer
        int statusCodeInt = (int)response.StatusCode;

        Console.WriteLine($"Status Code (enum): {statusCode}");
        Console.WriteLine($"Status Code (int): {statusCodeInt}");
        Console.WriteLine($"Reason Phrase: {response.ReasonPhrase}");
    }
}

Checking for Success

The IsSuccessStatusCode property provides a boolean check for 2xx status codes:

public static async Task<string> FetchDataSafely(string url)
{
    using var client = new HttpClient();
    HttpResponseMessage response = await client.GetAsync(url);

    if (response.IsSuccessStatusCode)
    {
        return await response.Content.ReadAsStringAsync();
    }
    else
    {
        Console.WriteLine($"Request failed with status: {response.StatusCode}");
        return null;
    }
}

Handling Different Status Codes

When web scraping or consuming APIs, you'll want to handle different status codes appropriately:

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

public class StatusCodeHandler
{
    public static async Task<string> HandleResponse(string url)
    {
        using var client = new HttpClient();
        client.Timeout = TimeSpan.FromSeconds(30);

        try
        {
            HttpResponseMessage response = await client.GetAsync(url);

            switch (response.StatusCode)
            {
                case HttpStatusCode.OK: // 200
                    Console.WriteLine("Success! Processing content...");
                    return await response.Content.ReadAsStringAsync();

                case HttpStatusCode.Created: // 201
                    Console.WriteLine("Resource created successfully");
                    return await response.Content.ReadAsStringAsync();

                case HttpStatusCode.NoContent: // 204
                    Console.WriteLine("Success with no content");
                    return string.Empty;

                case HttpStatusCode.MovedPermanently: // 301
                case HttpStatusCode.Found: // 302
                    Console.WriteLine($"Redirected to: {response.Headers.Location}");
                    return await HandleResponse(response.Headers.Location.ToString());

                case HttpStatusCode.BadRequest: // 400
                    Console.WriteLine("Bad request - check your parameters");
                    return null;

                case HttpStatusCode.Unauthorized: // 401
                    Console.WriteLine("Authentication required");
                    return null;

                case HttpStatusCode.Forbidden: // 403
                    Console.WriteLine("Access forbidden");
                    return null;

                case HttpStatusCode.NotFound: // 404
                    Console.WriteLine("Resource not found");
                    return null;

                case HttpStatusCode.TooManyRequests: // 429
                    Console.WriteLine("Rate limit exceeded - implement retry logic");
                    await Task.Delay(5000); // Wait before retry
                    return await HandleResponse(url);

                case HttpStatusCode.InternalServerError: // 500
                    Console.WriteLine("Server error - may be temporary");
                    return null;

                case HttpStatusCode.ServiceUnavailable: // 503
                    Console.WriteLine("Service unavailable - retry later");
                    return null;

                default:
                    Console.WriteLine($"Unhandled status code: {response.StatusCode}");
                    return null;
            }
        }
        catch (HttpRequestException ex)
        {
            Console.WriteLine($"Request error: {ex.Message}");
            return null;
        }
        catch (TaskCanceledException ex)
        {
            Console.WriteLine($"Request timeout: {ex.Message}");
            return null;
        }
    }
}

Using EnsureSuccessStatusCode

The EnsureSuccessStatusCode() method throws an HttpRequestException if the status code is not in the 2xx range:

public static async Task<string> FetchWithException(string url)
{
    using var client = new HttpClient();

    try
    {
        HttpResponseMessage response = await client.GetAsync(url);
        response.EnsureSuccessStatusCode(); // Throws if not 2xx

        return await response.Content.ReadAsStringAsync();
    }
    catch (HttpRequestException ex)
    {
        Console.WriteLine($"HTTP Error: {ex.Message}");

        // Extract status code from exception
        if (ex.StatusCode.HasValue)
        {
            Console.WriteLine($"Status Code: {(int)ex.StatusCode.Value}");
        }

        throw;
    }
}

Implementing Retry Logic Based on Status Codes

For web scraping applications, implementing retry logic with HttpClient for specific status codes is essential:

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

public class RetryHandler
{
    private static readonly int[] RetryableStatusCodes =
    {
        429, // Too Many Requests
        500, // Internal Server Error
        502, // Bad Gateway
        503, // Service Unavailable
        504  // Gateway Timeout
    };

    public static async Task<HttpResponseMessage> GetWithRetry(
        string url,
        int maxRetries = 3)
    {
        using var client = new HttpClient();
        int retryCount = 0;

        while (retryCount <= maxRetries)
        {
            HttpResponseMessage response = await client.GetAsync(url);
            int statusCode = (int)response.StatusCode;

            if (response.IsSuccessStatusCode)
            {
                return response;
            }

            if (Array.Exists(RetryableStatusCodes, code => code == statusCode))
            {
                retryCount++;

                if (retryCount <= maxRetries)
                {
                    int delayMs = (int)Math.Pow(2, retryCount) * 1000; // Exponential backoff
                    Console.WriteLine($"Status {statusCode} - Retrying in {delayMs}ms... (Attempt {retryCount}/{maxRetries})");
                    await Task.Delay(delayMs);
                    continue;
                }
            }

            return response;
        }

        throw new Exception("Max retries exceeded");
    }
}

Advanced Status Code Monitoring

For production web scraping applications, monitoring status codes helps identify issues:

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

public class StatusCodeMonitor
{
    private readonly Dictionary<int, int> _statusCodeCounts = new();

    public async Task<string> MonitoredRequest(string url)
    {
        using var client = new HttpClient();
        HttpResponseMessage response = await client.GetAsync(url);

        int statusCode = (int)response.StatusCode;

        // Track status code occurrences
        if (_statusCodeCounts.ContainsKey(statusCode))
        {
            _statusCodeCounts[statusCode]++;
        }
        else
        {
            _statusCodeCounts[statusCode] = 1;
        }

        // Log status information
        LogStatusCode(response);

        return response.IsSuccessStatusCode
            ? await response.Content.ReadAsStringAsync()
            : null;
    }

    private void LogStatusCode(HttpResponseMessage response)
    {
        Console.WriteLine($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] " +
                         $"Status: {(int)response.StatusCode} {response.StatusCode} - " +
                         $"Reason: {response.ReasonPhrase}");
    }

    public void PrintStatistics()
    {
        Console.WriteLine("\nStatus Code Statistics:");
        foreach (var kvp in _statusCodeCounts)
        {
            Console.WriteLine($"  {kvp.Key}: {kvp.Value} occurrences");
        }
    }
}

Comparing with HttpWebRequest

For developers migrating from the older HttpWebRequest API, here's how status code access compares:

// HttpClient (modern approach)
using var client = new HttpClient();
HttpResponseMessage response = await client.GetAsync(url);
HttpStatusCode statusCode = response.StatusCode;

// HttpWebRequest (legacy approach)
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
using HttpWebResponse webResponse = (HttpWebResponse)request.GetResponse();
HttpStatusCode legacyStatusCode = webResponse.StatusCode;

The HttpClient approach is recommended for modern applications due to better async support and resource management.

Best Practices for Status Code Handling

  1. Always check status codes: Don't assume requests will succeed
  2. Use appropriate error handling: Different status codes require different responses
  3. Implement retry logic: For transient errors (5xx codes, 429)
  4. Respect rate limits: When receiving 429 status codes, implement backoff strategies
  5. Log status codes: Essential for debugging and monitoring web scraping operations
  6. Handle redirects properly: Be aware that HttpClient follows redirects by default
  7. Use structured exception handling: Catch specific exceptions and extract status codes

Working with Web Scraping APIs

When working with web scraping APIs that provide additional error handling features, you can still access standard HTTP status codes while benefiting from enhanced error messages and retry mechanisms. This is particularly useful when dealing with complex scraping scenarios that require managing multiple requests and responses efficiently.

Conclusion

Reading HTTP status codes from HttpClient responses in C# is straightforward using the StatusCode property. Proper status code handling is essential for building robust web scraping applications that can gracefully handle errors, implement retry logic, and provide meaningful feedback.

The key is to understand what each status code means and respond appropriately—whether that's retrying the request, logging an error, or taking corrective action. By implementing proper status code checking and error handling, you'll create more reliable and maintainable C# applications for web scraping and API integration.

Related Resources

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