106  
csharp
Search  
Always will be ready notify the world about expectations as easy as possible: job change page
Jul 9, 2023

HTTPClient in C# — Starters Guide

Author:
Kenji Elzerman
Source:
Views:
3757

HTTPClient In C#

When you have multiple applications and they need to communicate with each other to exchange data you might want to use a protocol that makes something like that happen. In C#, the HTTPClient class provides a powerful and flexible way to make HTTP requests and handle responses. Whether you’re building a web application that needs to interact with APIs or simply need to retrieve data from a server, HTTPClient in C# can help.

In this tutorial, we’ll explore how to use the HTTPClient class in C# to make GET and POST requests, handle errors, and more. We’ll cover the basics of setting up and configuring the HTTPClient and advanced usage scenarios such as working with different content types and handling authentication. By the end of this tutorial, you’ll have a solid understanding of how to use the HTTPClient in your own C# projects.

In this tutorial, I will use a few free APIs that you can find online. You don’t need to register or generate a key. If they do change in the future, please let me know.

The HTTPClient Explained?

Microsoft has a good and short description of the HTTPClient in C#:

Provides a class for sending HTTP requests and receiving HTTP responses from a resource identified by a URI.

And that is exactly what this class does.

HTTP is the very foundation of data communication on the Internet. Every time you visit a page, upload a photo of a cute dog to social media, check your e-mail, and much more, it requires data to be sent and received through the World Wide Web.

If you work with C# and need to receive information or data from an external, online data source, you need to send out an HTTP request and need to be able to receive the response. Before the .NET Framework 4.5, we used the HttpWebRequest and HttpWebResponse to handle these requests. Since version 4.5 we have the HTTPClient class.

So, why not use the HttpWebResponse and HttpWebRequest? There are some differences between those and the HTTPClient. Here are a few:

  1. HTTPClient has better asynchronous support.
  2. The HTTPClient is easier to use and read
  3. HTTPClient hands decompression of response content automatically
  4. HTTPClient automatically reuses the connection for multiple requests for better performance. HttpWebRequest has the KeepAlive property, but it’s disabled by default.
  5. HTTPClient automatically includes a set of default headers in every request, such as User-Agent, Accept, and Connection headers. HttpWebRequest does not provide default headers.

The HTTPWebRequest is still usable in the newest version of .NET and could be a good option in several cases. Newer classes and functions don’t always mean the older ones are bad.

It really depends on the situation when you need to perform HTTP requests. Here are some basic guidelines:

Use HTTPClient when:

  • You need a simpler and more modern API for sending HTTP requests and receiving HTTP responses.
  • You want to perform asynchronous operations using the async/await pattern.
  • You need automatic handling of decompression, connection reuse, and default headers.
  • You want to take advantage of HTTP/2 support.

Use HttpWebRequest when:

  • You need more control over the HTTP request and response and are willing to work with a lower-level API.
  • You need to support older .NET Framework versions (before 4.5), as HttpWebRequest has been around since .NET Framework 1.1.
  • You need to perform more advanced HTTP operations, such as sending chunked requests or using custom HTTP methods.
  • You are working with a legacy system that requires the use of HttpWebRequest.

Getting The HTTPClient Ready

A few types of HTTP requests describe what you might want to do. In this tutorial, I will explain how you can perform a GET, POST, and DELETE request. Let’s start with the simplest of all: GET.

Before we can make an HTTP request we need to set up the HTTPClient. I create a Console App to write and test the code. I also install the NuGet package Newtonsoft.Json and will use this in the next code.

Using and setting up the HTTPClient comes in different layers. We need to initialize the HTTPClient class, then send out the request, and check if that request was successful. If we expect data to be sent back we need to grab that data and transform it into our code.

If we create code to implement it, it would look like this:

using (HttpClient client = new())
{
    HttpResponseMessage response = await client.GetAsync("https://official-joke-api.appspot.com/random_ten");

    if (response.IsSuccessStatusCode)
    {
        string content = await response.Content.ReadAsStringAsync();

        List<Joke>? jokes = JsonConvert.DeserializeObject<List<Joke>>(content);

        if (jokes == null)
            return;

        foreach (Joke joke in jokes)
        {
            Console.WriteLine(joke.Setup);
            Console.WriteLine(joke.Punchline);
            Console.WriteLine();
        }
    }
}

public class Joke
{
    public string Setup { get; set; }
    public string Punchline { get; set; }
}

Let’s walk through it:

First, the HTTPClient is initialized. I am using the using so the HTTPClient initialization will get disposed of when I don’t need it anymore, also closing the connections. Then I send the GET request to the URL. This is an asynchronous method, so I use the await.

Next, I check if the response was successful. Meaning that I get a positive HTTP status code. If it is not successful I could throw an exception or something.

But it is successful so I can retrieve the content from the response. The response.Content.ReadAsStringAsync() retrieves the response as a string, making it perfect to convert it to a JSON.

And then we are actually done with the HTTPClient in C#. I look through the list of jokes and print them on my screen.

Pretty simple, right? All you need to do is have an URL, initialization of the HTTPClient class, and off you go.

Sending POST Requests

While a GET request is pretty simple, a POST needs a little bit extra. A POST request lets you send data from a client to the source, like an API. Therefore, the POST request needs a body with data.

This body is usually a key-value situation. The key is a property name and the value is …. Well, the value of that property. Apart from the body, there isn’t anything special about it. It even starts the same, but we don’t expect any data to be returned, so we don’t have to grab and deserialize data.

using (HttpClient client = new())
{
    Joke newJoke = new Joke
    {
        Setup = "Why do bees hum?",
        Punchline = "Because they don't know the words."
    };

    StringContent body = new(JsonConvert.SerializeObject(newJoke));
    body.Headers.ContentType = new MediaTypeHeaderValue("application/json");

    HttpResponseMessage response = await client.PostAsync("https://official-joke-api.appspot.com/random_ten", body);
    if (!response.IsSuccessStatusCode)
    {
        var content = await response.Content.ReadAsStringAsync();
        throw new Exception(content);
    }
}

public class Joke
{
    public string Setup { get; set; }
    public string Punchline { get; set; }
}

Again, I initialize the HTTPClient. Then I create a new joke, nothing special here. But then I create a new variable of the type StringContent and initialize it with the newJoke that is being converted to a JSON string. Because I am using JSON as the body of the request, I need to set the ContentType of the body to application/json.

The reason I need to set the ContentType is to let the target know what kind of data I’ll be sending to it. It also could be XML and the target can’t receive XML if I send JSON.

The PUT request works exactly the same but instead of using client.PostAsync you use the client.PutAsync.

There are a lot of other headers you can set, but I will tell you more about that later.

Alright! Next, I do the actual POST to the URL. This time I use the client.PostAsync. The first parameter is the URL, we already did that with the GET, and the second one is the body, which we created earlier.

With a POST request, or PUT and DELETE, there is no need to check if the response is successful or not. More the opposite; we want to know when it went wrong. Therefore, I check if the response is not successful. If this is true, I get the content of the request. This is most of the time the error from the target telling me what I did wrong.

I put this information in an exception so I will be alerted when something went wrong while posting information to the target. This information could be that a required property is empty, or the endpoint is incorrect, and so on.

Sending DELETE Requests

The DELETE request looks a lot like the POST request, but with a slight difference: We don’t expect to receive data from the target. If you already created the code for the POST, you can simply copy-paste that and change it a bit to this:

using (HttpClient client = new())
{
    HttpResponseMessage response = await client.DeleteAsync("https://some.api.com/random_ten/12");

    if (!response.IsSuccessStatusCode)
    {
        var content = await response.Content.ReadAsStringAsync();
        throw new Exception(content);
    }
}

Okay, when I look at it, it doesn’t look the same at all. Anyway…

Again, I initialize the HTTPClient. Then I send the DELETE request to a target. DELETE requests usually need an identifier in the URL, hence the ’12’ in this example URL.

We only want to know when the request has failed and sends back a response with a back status code, so we just want to check if the response is not successful.

To figure out what went wrong we can extract the error by reading the content from the response and put it in an exception.

Advanced HTTPClient

I think you get the idea of how to use the HTTPClient in C#. But there is much more to it than just sending simple requests to a target and reading its response. You might need a few advanced settings while expanding your HTTPClient class.

Authorization

Some APIs need you to authorize by adding a token to your request to the API. This is usually a JWT from the API. You need to add this token to the Authorization header of the request.

This is one of the default request headers of the client. Setting this is pretty easy if you know where to add it:

using (HttpClient client = new())
{
    client.DefaultRequestHeaders.Add("Authorization", "Bearer Your_Token_Here");

    HttpResponseMessage response = await client.DeleteAsync("https://some.api.com/random_ten/12");

    if (!response.IsSuccessStatusCode)
    {
        var content = await response.Content.ReadAsStringAsync();
        throw new Exception(content);
    }
}

Although it looks pretty simple, please keep in mind you need to set the DefaultRequestHeaders before you send the request. There is no point in setting the default request headers after you send everything to the target.

Using a Timeout

By default, the HTTPClient waits 100000 ms (100 seconds) for a request to finish. If it doesn’t complete before that, an exception is thrown. This is what we call a timeout.

You can change that to whatever you want if you feel the need to do that. There is a setting of the HTTPClient class which is called Timeout and set with a TimeSpan.

using (HttpClient client = new())
{
    client.DefaultRequestHeaders.Add("Authorization", "Bearer Your_Token_Here");
    client.Timeout = TimeSpan.FromSeconds(30);

    HttpResponseMessage response = await client.DeleteAsync("https://some.api.com/random_ten/12");

    if (!response.IsSuccessStatusCode)
    {
        var content = await response.Content.ReadAsStringAsync();
        throw new Exception(content);
    }
}

In the example above, the timeout of the HTTPClient is set to 30 seconds. This means that if the request of that initialized client takes more than 30 seconds, an exception is thrown.

Multiple Requests With One Client

If you need to send different requests within the same method or at the same time, you don’t have to close and open the HTTPClient. Simply reuse it. Below is an example. The client will only be closed after the closing accolade of the using.

string baseUrl = "https://official-joke-api.appspot.com/jokes/{0}";

using (HttpClient client = new())
{
    for(int i = 0; i < 10; i++)
    {
        HttpResponseMessage response = await client.GetAsync(string.Format(baseUrl, i + 1));

        if (response.IsSuccessStatusCode)
        {
            string content = await response.Content.ReadAsStringAsync();
            Joke? joke = Newtonsoft.Json.JsonConvert.DeserializeObject<Joke>(content);

            if (joke == null)
                return;

            Console.WriteLine(joke.Setup);
            Console.WriteLine(joke.Punchline);
            Console.WriteLine();
        }
        else
        {
            var currentColor = Console.ForegroundColor;

            string content = await response.Content.ReadAsStringAsync();
            Console.ForegroundColor = ConsoleColor.Red;
            Console.WriteLine(content);

            Console.ForegroundColor = currentColor;        
        }
    }
}

public class Joke
{
    public string Setup { get; set; }
    public string Punchline { get; set; }
}

Proxies

If you want to reach a target using a proxy, the HTTPClient in C# will help you out. It has a special handler that you can configure to use the proxy.

The following example has a proxy, which is fictional.

HttpClientHandler handler = new()
{
    Proxy = new WebProxy(new Uri($"socks5://123.45.678.90:12345")),
    UseProxy = true,
};

using (HttpClient client = new(handler))
{
    client.Timeout = TimeSpan.FromSeconds(10);

    HttpResponseMessage response = await client.GetAsync("https://official-joke-api.appspot.com/random_ten");

    if (response.IsSuccessStatusCode)
    {
        string content = await response.Content.ReadAsStringAsync();

        List<Joke>? jokes = JsonConvert.DeserializeObject<List<Joke>>(content);

        if (jokes == null)
            return;

        foreach (Joke joke in jokes)
        {
            Console.WriteLine(joke.Setup);
            Console.WriteLine(joke.Punchline);
            Console.WriteLine();
        }
    }
}

public record Joke(string Setup, string Punchline);

Download An Image

You can use the HTTPClient to download an image from the web, store it in an array of bytes, and then save it as a file. For this, we use the GetByteArrayAsync(uri) method.

using (HttpClient httpClient = new())
{
    byte[] imageBytes = await httpClient.GetByteArrayAsync("https://i.imgur.com/OVFxdJy.jpg");

    string desktopPath = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
    string localPath = Path.Combine(desktopPath, "this_makes_your_day.jpg");

    File.WriteAllBytes(localPath, imageBytes);
}

Conclusion

The HTTPClient in C# is used mostly when requesting or sending data from and to an external target, which is usually an API. It has different options and settings you can use to make your requests.

It has great advantages over HttpWebRequest, but the HttpWebRequest is still being used in older and new projects. It’s a good idea to get some idea of how the HttpWebRequest works, although it feels a lot to the HTTPClient.

Similar
Aug 15
Author: Jigar Shah
In this comprehensive tutorial, you’ll discover the step-by-step process to build a simple REST API using PHP and MySQL. In the modern-day web landscape, REST APIs are extensively utilized for accessing and manipulating data. By incorporating REST APIs into the...
Sep 11, 2023
Author: Artem A. Semenov
When crafting elegant and scalable software in C#, a keen understanding of Dependency Injection (DI) is more than a luxury — it’s a necessity. It’s a design pattern that underpins many modern .NET applications, providing a solid foundation for managing...
Aug 18, 2023
Author: Alex Maher
C# Data Structures Handbook! Every decision in programming is a silent influencer of performance and clarity. In C#, one such vital choice is selecting the right data structure. Data structures are foundational pillars. These structures are where data lives, breathes,...
May 29, 2023
Maximizing performance in asynchronous programming Task and Task<TResult> The Task and Task<TResult> types were introduced in .NET 4.0 as part of the Task Parallel Library (TPL) in 2010, which provided a new model for writing multithreaded and asynchronous code. For...
Send message
Type
Email
Your name
*Message