C# – How to send synchronous requests with HttpClient

In .NET 5 and above, you can use the HttpClient Sync API methods – Send() and ReadAsStream() – to send HTTP requests synchronously (as opposed to resorting to sync-over-async). Here’s the steps for doing this:

  • Create an instance of HttpRequestMessage.
  • Use the synchronous HttpClient.Send() to send the message.
  • Use the synchronous HttpContent.ReadAsStream() to get the response content.

HttpClient was originally designed for async requests and has many async convenience methods (like GetAsync() and ReadAsStringAsync()). There aren’t sync versions of any of these convenience methods (at least not yet). The Sync API basically has the bare minimum methods needed for using HttpClient without async.

I’ll show examples of sending synchronous GET and POST requests with HttpClient.

Synchronous GET request

Here’s an example of sending a synchronous GET request and deserializing the response content stream with System.Text.Json:

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

//note: save these instances for reuse
var httpClient = new HttpClient();
var jsonOptions = new JsonSerializerOptions(JsonSerializerDefaults.Web);

//make the sync GET request
using (var request = new HttpRequestMessage(HttpMethod.Get, "https://localhost:12345/Coder"))
{
	var response = httpClient.Send(request);

	response.EnsureSuccessStatusCode();

	using var stream = response.Content.ReadAsStream();
	var coder = JsonSerializer.Deserialize<Coder>(stream, jsonOptions);

	Console.WriteLine($"Got {coder.Language} coder named {coder.Name}");
}
Code language: C# (cs)

Notice that you have to deal with the response content as a stream (from HttpContent.ReadAsStream()). If the response content is JSON, you can use System.Text.Json since it can handle deserializing JSON from a stream.

This outputs the following:

Got C# coder named BobCode language: plaintext (plaintext)

Synchronous POST request

Here’s an example of sending a synchronous POST request and reading the response content stream as a string with StreamReader:

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

//note: save these instances for reuse
var httpClient = new HttpClient();
var jsonOptions = new JsonSerializerOptions(JsonSerializerDefaults.Web);

//make the sync POST request
using (var request = new HttpRequestMessage(HttpMethod.Post, "https://localhost:12345/Coder"))
{
	var json = JsonSerializer.Serialize(new Coder() { Name = "Bob", Language = "C#" });
	request.Content = new StringContent(json, System.Text.Encoding.UTF8, "application/json");
	
	var response = httpClient.Send(request);
	response.EnsureSuccessStatusCode();

	using var streamReader = new StreamReader(response.Content.ReadAsStream());
	Console.WriteLine(streamReader.ReadToEnd());

	//Note: StreamReader disposes the stream for you
}
Code language: C# (cs)

HttpContent.ReadAsStream() returns the content as a MemoryStream. When you want the content as a string, use StreamReader.ReadToEnd() as shown above.

This sends the request and gets back the following response body (read from the content stream):

Posted coder BobCode language: plaintext (plaintext)

4 thoughts on “C# – How to send synchronous requests with HttpClient”

  1. Hi,
    …. httpClient.Send(request); ….
    HttpClient class has not method Send(), it has SendAsync() only

    Reply
        • Hi Robin,

          There are a few hacky solutions for solving the problem and *hopefully* avoiding deadlocks and other potential issues (depends on the type of project you’re running in). I like the following option, because it’s relatively simple. You run HttpClient async calls in Task.Run and then use GetAwaiter().GetResult().

          var response = Task.Run(() => httpClient.GetAsync("https://localhost:12345/Coder")).GetAwaiter().GetResult();
          var content = Task.Run(() => response.Content.ReadAsStringAsync()).GetAwaiter().GetResult();

          I tested this in .NET Framework 4.8 in a WinForms app. Be sure to test this thoroughly in a realistic scenario for your application.

          The downside to this approach is it wastes a thread (2 are blocked instead of just 1). That only really matters if you’re sending tons of concurrent requests in your application, like in a high throughput web server. I would guess that’s not the case (otherwise you wouldn’t be wanting to send sync requests in the first place).

          Reply

Leave a Reply to BorisL Cancel reply