Skip to the content.

How to run curl synchronously in C#

To run curl synchronously in C#, call Curl.Execute("curl ...") instead of Curl.ExecuteAsync. It blocks the calling thread until the response arrives and returns the same CurlResult, which suits console tools, scripts, build steps and tests.

dotnet add package CurlDotNet

The curl command

using CurlDotNet;

var result = Curl.Execute("curl -H 'Accept: application/json' https://httpbin.org/get");

Console.WriteLine(result.StatusCode);
Console.WriteLine(result.Body);

The fluent builder

using CurlDotNet.Core;

var result = CurlRequestBuilder
    .Get("https://httpbin.org/basic-auth/user/passwd")
    .WithBasicAuth("user", "passwd")
    .Execute();

Console.WriteLine(result.IsSuccess);

Synchronous helpers

using CurlDotNet;

var get  = Curl.Get("https://httpbin.org/get");
var post = Curl.Post("https://httpbin.org/post", "a=1&b=2");
var json = Curl.PostJson("https://httpbin.org/post", new { name = "Ada" });
var file = Curl.Download("https://httpbin.org/image/png", "logo.png");

Curl.Execute(command, cancellationToken), Curl.Execute(command, settings) and Curl.Execute(curlOptions) mirror the async overloads.

In a .csx script

Synchronous calls keep scripts short. With dotnet-script:

#r "nuget: CurlDotNet, 9.8.0"
using CurlDotNet;

var result = Curl.Execute("curl https://httpbin.org/get");
Console.WriteLine(result.StatusCode);

Run it with dotnet script check.csx. On the .NET 10 SDK, a file-based app works too: put #:package CurlDotNet@9.8.0 at the top of check.cs and run dotnet run check.cs.

When blocking is fine

When to use ExecuteAsync instead

Curl.Execute waits on ExecuteAsync(...). Every await inside the library uses ConfigureAwait(false), so the call does not deadlock on a UI or classic ASP.NET SynchronizationContext by itself, but it still blocks the calling thread for the whole transfer, and a callback you supply (a progress or redirect handler, middleware, your own HttpMessageHandler) that waits for that same context can still deadlock. Do not use the synchronous methods on a UI thread or in classic ASP.NET request code; await ExecuteAsync there.

Since C# 7.1 Main can be async, and top-level statements can use await directly, so in new console apps the async version costs nothing extra.

Errors are the same

Curl.Execute throws the same CurlException types as the async methods (they are not wrapped in AggregateException), and HTTP error statuses still come back as a normal result.