HttpClient Basics
HttpClient sends HTTP requests from C#. Give it a base address, await GetAsync for a response, check its status code, and read its body. A failed status is an answer to handle; a server that can't be reached throws an HttpRequestException.
Journeyman · C# · REST API · Updated
After this lesson you can
- Send a GET request with HttpClient, and read the response's status code and body
- Handle an unsuccessful status code and a server that can't be reached
Key takeaways
HttpClientsends requests from C#: set itsBaseAddress, thenawait client.GetAsync(...)for anHttpResponseMessagewith a status code and a body.- A
404or400is an answer, not an error in your program: checkresponse.IsSuccessStatusCodebefore you trust the body. - When a failed status means you can't go on, call
response.EnsureSuccessStatusCode(): it throws anHttpRequestExceptionfor anything but 2xx. - When the API can't be reached at all,
GetAsyncthrows anHttpRequestException, so wrap calls in atry. - Make one
HttpClientand use it for all your requests, rather than a new one for each.
So far, .http files have been your API's client. Now a C# program will be. Any program can call an API: a console app, a desktop app, even another web API that needs data from a third one. In .NET, they all use HttpClient.
The examples in this chapter call the categories API you built in HTTP and Web APIs. Start it (Ctrl+F5 in its own Visual Studio window) and leave it running, then create a new console app for the client. Use your API's own address wherever you see http://localhost:5179.
A first request
using HttpClient client = new HttpClient();
client.BaseAddress = new Uri("http://localhost:5179/");
HttpResponseMessage response = await client.GetAsync("api/categories/8");
Console.WriteLine((int)response.StatusCode);
Console.WriteLine(response.StatusCode);
Console.WriteLine(await response.Content.ReadAsStringAsync());
200
OK
{"categoryId":8,"categoryName":"Seafood","description":"Seaweed and fish"}
BaseAddressis the start of every address.GetAsync("api/categories/8")is added to it. (Keep the/at the end of the base address, and none at the start of the path, so they join correctly.)GetAsyncsends aGETand returns anHttpResponseMessage: the whole response, as an object. It's async, because the answer comes over the network.response.StatusCodeis the status, as anHttpStatusCodevalue:OK,NotFound,Created. Cast it tointfor the number.response.Content.ReadAsStringAsync()reads the body as text: here, JSON. The next lesson turns it into aCategoryobject.
When the answer isn't OK
A 404 or a 400 isn't an error in your program: it's an answer, and your code decides what to do with it. IsSuccessStatusCode is true for any 2xx code:
using System.Net;
using HttpClient client = new HttpClient();
client.BaseAddress = new Uri("http://localhost:5179/");
foreach (int id in new[] { 8, 300 })
{
HttpResponseMessage response = await client.GetAsync( quot;api/categories/{id}");
if (response.IsSuccessStatusCode)
{
Console.WriteLine( quot;{id}: found");
}
else if (response.StatusCode == HttpStatusCode.NotFound)
{
Console.WriteLine( quot;{id}: there's no such category");
}
else
{
Console.WriteLine( quot;{id}: the API answered {(int)response.StatusCode}");
}
}
8: found
300: there's no such category
(HttpStatusCode lives in System.Net, hence the using System.Net; at the top.)
When a failed status means you can't go on, response.EnsureSuccessStatusCode() throws an HttpRequestException for anything but 2xx.
When the server can't be reached
If the API isn't running, or the address is wrong, there's no answer at all. GetAsync throws an HttpRequestException, so wrap calls in a try, like any work that leaves your program:
using HttpClient client = new HttpClient();
client.BaseAddress = new Uri("http://localhost:5999/");
try
{
HttpResponseMessage response = await client.GetAsync("api/categories");
Console.WriteLine((int)response.StatusCode);
}
catch (HttpRequestException)
{
Console.WriteLine("The API can't be reached. Is it running?");
}
The API can't be reached. Is it running?
Nothing listens on port 5999, so the request never gets an answer. Two kinds of failure, two ways to handle them:
| What happened | How you find out |
|---|---|
The API answered, but not with success: 404, 400, 500 |
response.IsSuccessStatusCode is false; check response.StatusCode |
| The API couldn't be reached at all | GetAsync throws an HttpRequestException |
One HttpClient, used again and again
Make one HttpClient and use it for all your requests, rather than a new one for each. Each HttpClient holds network connections open for a while, and a program that makes thousands of them can run out. A console app keeps one in a variable, as here. (ASP.NET Core apps share them through dependency injection instead, with builder.Services.AddHttpClient(); Microsoft's docs show how when you need it.)
Check yourself
2 questions to try on the lesson page.
So what
HttpClient is the browser's job done by code: send a request, get a response, read its status and body. Check the status before you trust the body, and catch HttpRequestException for the times there's no answer at all.