Part 1
C# HttpClient
1. C# Httpclient GET Request
2.
C#
Httpclient HEAD Request
3.
C#
Httpclient POST Request
4.
C# Httpclient
JSON Request
5.
C#
Httpclient Download Image
6.
C#
Httpclient Basic Authentication
C# HttpClient tutorial shows how
to create HTTP requests with HttpClient in C#. The Hypertext Transfer Protocol (HTTP) is an
application protocol for distributed, collaborative, hypermedia information
systems. HTTP is the foundation of data communication for the World Wide Web.
HttpClient
is a base
class for sending HTTP requests and receiving HTTP responses from a resource
identified by a URI.
using System;
using System.Net.Http;
using System.Threading.Tasks;
namespace HttpClientStatus
{
class Program
{
static async Task Main(string[] args)
{
using var client = new
HttpClient();
var result = await client.GetAsync("http://webcode.me");
Console.WriteLine(result.StatusCode);
}
}
}
The GetAsync()
method sends
a GET request to the specified Uri as an asynchronous operation. The await
operator
suspends the evaluation of the enclosing async method until the asynchronous
operation completes. When the asynchronous operation completes, the await
operator
returns the result of the operation, if any.
C#
Httpclient GET Request
The GET method requests a representation of the specified
resource.
using System;
using
System.Net.Http;
using
System.Threading.Tasks;
namespace HttpClientEx
{
class Program
{
static async Task
Main(string[] args)
{
using var client
= new HttpClient();
var content = await
client.GetStringAsync("http://webcode.me");
Console.WriteLine(content);
}
}
}
The
example issues a GET request to the webcode.me
website. It outputs the
simple HTML code of the home page.
var content = await client.GetStringAsync("http://webcode.me");
The GetStringAsync()
sends a GET request to the specified Uri and returns the response
body as a string in an asynchronous operation.
$ dotnet run
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My html page</title>
</head>
<body>
<p>
Today is a beautiful day. We go swimming and fishing.
</p>
<p>
Hello there. How are you?
</p>
</body>
</html>
C#
Httpclient HEAD Request
The HTTP HEAD method requests the headers that are returned if the
specified resource would be requested with an HTTP GET method.
using System;
using
System.Net.Http;
using
System.Threading.Tasks;
namespace HttpClientHead
{
class Program
{
static async Task
Main(string[] args)
{
var url = "http://webcode.me";
using var client
= new HttpClient();
var result = await client.SendAsync(new
HttpRequestMessage(HttpMethod.Head,
url));
Console.WriteLine(result);
}
}
}
The example issues a
HEAD request.
$ dotnet run
StatusCode: 200, ReasonPhrase: 'OK', Version: 1.1,
Content: System.Net.Http.HttpConnectionResponseContent, Headers:
{
Server: nginx/1.6.2
Date: Sat, 12 Oct 2019 19:55:14 GMT
Connection: keep-alive
ETag: "5d32ffc5-15c"
Accept-Ranges: bytes
Content-Type: text/html
Content-Length: 348
Last-Modified: Sat, 20 Jul 2019 11:49:25 GMT
}
This are the header
fields of the response.
C#
Httpclient POST Request
The HTTP POST method sends data to the server. The type of the
body of the request is indicated by the Content-Type
header.
$ dotnet add package Newtonsoft.Json
We need to add the Newtonsoft.Json
package to process JSON
data.
using System;
using
System.Text;
using
System.Net.Http;
using
System.Threading.Tasks;
using
Newtonsoft.Json;
namespace HttpClientPost
{
class Person
{
public string Name { get; set; }
public string
Occupation { get; set; }
public override string
ToString()
{
return $"{Name}: {Occupation}";
}
}
class Program
{
static async Task
Main(string[] args)
{
var person = new
Person();
person.Name = "John Doe";
person.Occupation = "gardener";
var json = JsonConvert.SerializeObject(person);
var data = new
StringContent(json, Encoding.UTF8,
"application/json");
var url = "https://httpbin.org/post";
using var client
= new HttpClient();
var response = await client.PostAsync(url, data);
string result =
response.Content.ReadAsStringAsync().Result;
Console.WriteLine(result);
}
}
}
In the example, we
send a POST request to https://httpbin.org/post
website, which is an
online testing service for developers.
var person = new Person();
person.Name = "John Doe";
person.Occupation = "gardener";
var json = JsonConvert.SerializeObject(person);
var data = new StringContent(json, Encoding.UTF8, "application/json");
We turn an object into a JSON data with the help of the Newtonsoft.Json
package.
var response = await client.PostAsync(url, data);
We send an asynchronous POST request with the PostAsync()
method.
string result = response.Content.ReadAsStringAsync().Result;
Console.WriteLine(result);
We read the returned data and print it to the console.
$ dotnet run
{
"args": {},
"data": "{\"Name\":\"John Doe\",\"Occupation\":\"gardener\"}",
"files": {},
"form": {},
"headers": {
"Content-Length": "43",
"Content-Type": "application/json; charset=utf-8",
"Host": "httpbin.org"
},
"json": {
"Name": "John Doe",
"Occupation": "gardener"
},
...
"url": "https://httpbin.org/post"
}
This is the output.
C# Httpclient
JSON Request
JSON (JavaScript Object Notation) is a lightweight data-interchange format. This format is easy for
humans to read and write and for machines to parse and generate. It is a less verbose and
more readable alternative to XML. The official Internet media type for JSON
is application/json
.
using System;
using
System.Threading.Tasks;
using
System.Collections.Generic;
using
System.Net.Http;
using
System.Net.Http.Headers;
using
Newtonsoft.Json;
namespace HttpClientJson
{
class Contributor
{
public string Login { get; set; }
public short Contributions
{ get; set; }
public override string
ToString()
{
return $"{Login,20}: {Contributions} contributions";
}
}
class Program
{
private static async Task Main()
{
using var client =
new HttpClient();
client.BaseAddress = new Uri("https://api.github.com");
client.DefaultRequestHeaders.Add("User-Agent", "C# console program");
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
var url = "repos/symfony/symfony/contributors";
HttpResponseMessage response = await client.GetAsync(url);
response.EnsureSuccessStatusCode();
var resp = await
response.Content.ReadAsStringAsync();
List<Contributor>
contributors =
JsonConvert.DeserializeObject<List<Contributor>>(resp);
contributors.ForEach(Console.WriteLine);
}
}
}
The example generates
a GET request to to Github. It finds out the top contributors of the Symfony
framework. It uses the Newtonsoft.Json
to work with JSON.
client.DefaultRequestHeaders.Add("User-Agent", "C# console program");
In the request header, we specify the user agent.
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
In the accept header value, we tell that JSON is an acceptable
response type.
var url = "repos/symfony/symfony/contributors";
HttpResponseMessage response = await client.GetAsync(url);
var resp = await response.Content.ReadAsStringAsync();
We generate a request and read the content asynchronously.
List<Contributor> contributors = JsonConvert.DeserializeObject<List<Contributor>>(resp);
contributors.ForEach(Console.WriteLine);
We transform the JSON response into a list of Contributor
objects with the JsonConvert.DeserializeObject()
method.
C# Httpclient Download Image
The GetByteArrayAsync()
sends a GET request to
the specified Uri and returns the response body as a byte array in an
asynchronous operation.
using System;
using
System.IO;
using
System.Net.Http;
using
System.Threading.Tasks;
namespace HttpClientDownloadImage
{
class Program
{
static async Task
Main(string[] args)
{
using var
httpClient = new
HttpClient();
var url = "http://webcode.me/favicon.ico";
byte[] imageBytes = await
httpClient.GetByteArrayAsync(url);
string documentsPath = System.Environment.GetFolderPath(
System.Environment.SpecialFolder.Personal);
string localFilename = "favicon.ico";
string localPath = Path.Combine(documentsPath,
localFilename);
File.WriteAllBytes(localPath,
imageBytes);
}
}
}
In the example, we
download an image from the webcode.me
website. The image is
written to the user's Documents
folder.
byte[] imageBytes = await httpClient.GetByteArrayAsync(url);
The GetByteArrayAsync()
returns the image as an
array of bytes.
string documentsPath = System.Environment.GetFolderPath(
System.Environment.SpecialFolder.Personal);
We determine the Documents
folder with the GetFolderPath()
method.
File.WriteAllBytes(localPath, imageBytes);
The bytes are written to the disk with the File.WriteAllBytes()
method.
C# Httpclient Basic Authentication
In HTTP protocol, basic access authentication is a method for an HTTP
user agent (such as a web browser or a console application) to provide a user
name and password when making a request. In basic HTTP authentication, a
request contains a header field in the form of Authorization: Basic <credentials>
, where credentials is the
base64 encoding of id and password joined by a single colon :
.
Note: The
credentials are not encrypted; therefore, HTTP basic authentication must be
used with the HTTPS protocol.
HTTP Basic authentication is the simplest technique for enforcing
access controls to web resources. It does not require cookies, session
identifiers, or login pages; rather, HTTP Basic authentication uses standard
fields in the HTTP header.
using System;
using
System.IO;
using
System.Net.Http;
using
System.Threading.Tasks;
namespace HttpClientDownloadImage
{
class Program
{
static async Task
Main(string[] args)
{
using var
httpClient = new
HttpClient();
var url = "http://webcode.me/favicon.ico";
byte[] imageBytes = await
httpClient.GetByteArrayAsync(url);
string documentsPath = System.Environment.GetFolderPath(
System.Environment.SpecialFolder.Personal);
string localFilename = "favicon.ico";
string localPath = Path.Combine(documentsPath,
localFilename);
File.WriteAllBytes(localPath,
imageBytes);
}
}
}
The example sends
credentials to the httpbin.org
website.
var authToken = Encoding.ASCII.GetBytes($"{userName}:{passwd}");
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(authToken));
Here we build the authentication header.
var url = "https://httpbin.org/basic-auth/user7/passwd";
The URL contains authentication details because we test it with
the httpbin.org
website. This way we
don't need to set up our own server. Authentication details are never put into
the URL, of course.
$ dotnet run
{
"authenticated": true,
"user": "user7"
}
This is the output.
In this tutorial, we have used C# HttpClient
to create HTTP requests.
Part 2
When
to use WebClient vs. HttpClient vs. HttpWebRequest
Understand the pros and cons of
the .Net Framework's various native classes for working with HTTP requests and
responses
You
have three different choices for consuming REST APIs when working in the .NET
Framework: WebClient, HttpClient, and HttpWebRequest. In this post we will look
at these three ways we can access REST APIs from within the managed
environment, i.e., without resorting to third-party libraries. In the sections
that follow I will illustrate these approaches with relevant code examples to
help you gain a better understanding of the concepts.
In a nutshell,
WebRequest—in its HTTP-specific implementation, HttpWebRequest—represents the
original way to consume HTTP requests in .NET Framework. WebClient provides a
simple but limited wrapper around HttpWebRequest. And HttpClient is the new and
improved way of doing HTTP requests and posts, having arrived with .NET
Framework 4.5.
Let’s start our
discussion with the WebRequest abstract class.
System.Net.WebRequest
The
System.Net.WebRequest class is an abstract class. Thus you will need to create
a HttpWebRequest or FileWebRequest to consume HTTP requests using this class.
The following code snippet shows how you can work with WebRequest.
WebRequest webRequest = WebRequest.Create(uri);
webRequest.Credentials = CredentialCache.DefaultCredentials;
webRequest.Method ="GET";
HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse();
System.Net.HttpWebRequest
WebRequest was the
first class provided in the .NET Framework to consume HTTP requests. It gives
you a lot of flexibility in handling each and every aspect of the request and
response objects, without blocking the user interface thread. You can use this class
to access and work with headers, cookies, protocols, and timeouts when working
with HTTP. The following code snippet illustrates how HttpWebRequest can be
used.
HttpWebRequest http = HttpWebRequest)WebRequest.Create(“http://localhost:8900/api/default”);
WebResponse response = http.GetResponse();
MemoryStream memoryStream = response.GetResponseStream();
StreamReader streamReader = new StreamReader(memoryStream);
string data = streamReader.ReadToEnd();
System.Net.WebClient
The
System.Net.WebClient class in .NET provides a high-level abstraction on top of
HttpWebRequest. WebClient is just a wrapper around HttpWebRequest, so uses
HttpWebRequest internally. Thus WebClient is a bit slow compared to
HttpWebRequest, but requires you to write much less code. You can use WebClient
for simple ways to connect to and work with HTTP services. It is generally a
better choice than HttpWebRequest unless you need to leverage the additional
features that HttpWebRequest provides. The following code snippet shows how you
can work with WebClient.
string data = null;
using (var webClient = new WebClient())
{
data = webClient.DownloadString(url);
}
System.Net.Http.HttpClient
HttpClient was
introduced in .NET Framework 4.5. For developers using .NET 4.5 or later, it is
the preferred way to consume HTTP requests unless you have a specific reason
not to use it. In essence, HttpClient combines the flexibility of
HttpWebRequest and the simplicity of WebClient, giving you the best of both the
worlds.
The HttpWebRequest
class provides a lot of control over the request/response object. However, you
should be aware that HttpClient was never designed to be a replacement for
WebClient. You should use HttpWebRequest instead of HttpClient whenever you
need the additional features that HttpWebRequest provides. Further, unlike
WebClient, HttpClient lacks support for progress reporting and custom URI
schemes.
Although HttpClient
doesn’t support FTP, mocking and testing HttpClient is easier. All I/O bound
methods in HttpClient are asynchronous, and you can use the same HttpClient
instance to make concurrent requests as well. The following code snippet
illustrates how you can work with HttpClient.
public async Task<Author> GetAuthorsAsync(string uri)
{
Author author = null;
HttpResponseMessage response = await client.GetAsync(uri);
if (response.IsSuccessStatusCode)
{
author = await response.Content.ReadAsAsync<Author>();
}
return author;
}
Note that when there
is an error in the response, HttpClient doesn’t throw an error.
Rather,
it sets the IsSuccessStatusCode
property to false.
If you want to throw an exception if the IsSuccessStatusCode
property is false, you can
make a call to the EnsureSuccessStatusCode
method on the response
instance as shown below.
response.EnsureSuccessStatusCode();
HttpClient was
designed to be instantiated once and reused throughout the application’s
lifecycle—you should not create a new HttpClient instance for every request
that your application needs to process. If you do, the available sockets could
become exhausted by heavy traffic, resulting in SocketException
errors. The recommended
practice is to create a single, shared HttpClient instance.
Calling Web Services with HttpWebRequest, WebClient and
HttpClient
The .NET Framework gives you three different ways to call a Web
Service. However, depending on your scenario, the latest and greatest object
isn’t necessarily your best choice.
If you’re going to call a RESTful Web Service, the .NET
Framework gives you three objects you can use to make the call: HttpWebRequest,
WebClient and HttpClient. Each has its costs and benefits (of course), so this
column is about why you might choose each one.
HttpWebRequest: Full Control
For me, the HttpWebRequest is primarily of "historical
interest" -- it’s the earliest of the tools to appear (as I remember) and
is also the least "developer-friendly" of the three objects.
The issue with the HttpWebRequest is that, if you want to call a
RESTful service with the HttpWebRequest, you’re going to have to specify everything yourself. Listing
1 shows the simplest possible request using the HttpWebRequest object:
a call to a single Web Service method, passing a single parameter
("Vogel"), and getting back a single, Boolean result.
Listing
1: Calling a RESTful Service Using HttpWebRequest
Dim hwr As
HttpWebRequest
hwr =
WebRequest.Create("http://localhost:56590/Home/ValidName?LastName=Vogel")
Try
Dim wr As WebResponse
wr = hwr.GetResponse()
If CType(wr, HttpWebResponse).StatusCode =
HttpStatusCode.OK Then
Dim st As Stream
st = wr.GetResponseStream()
Dim sr As StreamReader
sr = New StreamReader(st)
Dim res As Boolean
res = sr.ReadToEnd()
If res Then
'...work with result...
End If
End If
Catch ex as Exception
'...handle error...
End Try
I’ve left some important steps out of here: I haven’t, for
example, provided any credentials to log into the service; in C# the conversion
of the returned data (the string "false") to a Boolean would be more
complicated; and the WebResponse has a Dispose method that I should be calling
through a Using block. But, even with those steps omitted, that’s a lot of
code.
What’s good about the HttpWebRequest is that you have complete
control over everything that’s sent to the Web Service. You can set the user
agent string to allow your client to, for example, masquerade as an iPhone.
WebClient: Ease of Use
The WebClient object addresses the complexity of the
HttpWebRequest by wrapping it to provide a simpler interface for calling
RESTful services. Listing 2 does the same thing as Listing
1, but requires far less code.
Listing
2: Calling a RESTful Service Using WebClient
Dim wc As WebClient
wc = New WebClient
Try
Dim res As Boolean
res =
wc.DownloadString("http://localhost:56590/Home/ValidName?LastName=Vogel")
If res Then
'...work with result...
End If
Catch ex As Exception
'...handle error...
End Try
In addition to simplifying requests, the WebClient provides
methods for asynchronously calling Web Services (both in uploading and
downloading). And, while you don’t have quite the low-level control that the
HttpWebRequest does, it still gives you (for example) the ability to manipulate
the headers that you send to the Web Service.
If you’re using a version of the .NET Framework earlier than
4.5, then the WebClient should be your first choice. You should use the
HttpWebRequest only if you find there’s something you need that the WebClient
won’t do.
HttpClient: Asynchronous Heaven
However, if you are using the .NET Framework version 4.5 or
later (and version 4.5 has been out for five years now), then you also have
access to the HttpClient object. The HttpClient provides functionality that
neither WebClient nor HttpWebRequest does. For example, with HttpClient you can
make multiple requests without having to create a new object; you can track the
progress of long-running requests; and it’s a lot easier to integrate the
HttpClient into testing through mocking.
The downside of using the HttpClient is that every method
is asynchronous. If you use HttpClient in a pseudo-synchronous mode, the code
can be a little ugly, as Listing 3 shows, which has almost as
many lines of code as the original HttpWebRequest object required.
Listing
3: Calling a RESTful Service Using HttpClient Synchronously
Dim hc As HttpClient
hc = New HttpClient
Try
Dim trm As Task(Of HttpResponseMessage)
trm =
hc.GetAsync("http://localhost:56590/Home/ValidName?LastName=Vogel")
Dim rm As HttpResponseMessage
rm = trm.Result
If rm.IsSuccessStatusCode Then
Dim ts As Task(Of String)
ts = rm.Content.ReadAsStringAsync
Dim res As Boolean
res = ts.Result
If res Then
'...work with result...
End If
End If
Catch ex As Exception
'...handle exception...
End Try
However, if you use HttpClient as it was intended
(asynchronously), then the code gets simpler. If I use await and async, as
shown in Listing 4, the code isn’t quite as short as with the
WebClient … but it’s close and it’s asynchronous.
Listing
4: Calling a RESTful Service Using HttpClient Asynchronously
Dim hc As HttpClient
hc = New HttpClient
Try
Dim rm As HttpResponseMessage
rm = Await
hc.GetAsync("http://localhost:56590/Home/ValidName?LastName=Vogel")
If rm.IsSuccessStatusCode Then
Dim res As Boolean
res = Await rm.Content.ReadAsStringAsync
If res Then
'...work with a result...
End If
End If
Catch ex As Exception
'...work with exception...
End Try
So, what is my best choice? If I’m happy with synchronous code
and don’t need to mock my RESTful calls when testing, I’m still using the
WebClient. However, if I can leverage asynchronous code, have a long-running
process I want to track, or need to mock calls for testing, then I use
HttpClient. And, on those very rare occasions when I need to do something odd
with the HTTP protocol, I fall back on the HttpWebRequest object.
You can’t, after all, have too many tools.