Skip to the content.

How to run a curl command in C#

To run a curl command in C#, install the CurlDotNet NuGet package and pass the command string to Curl.ExecuteAsync; it parses the curl flags and sends the request through .NET’s HttpClient, so there is no curl.exe, no native libcurl and no Process.Start.

dotnet add package CurlDotNet

Run the curl string as-is

using CurlDotNet;

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

Console.WriteLine(result.StatusCode);  // 200
Console.WriteLine(result.Body);        // the JSON response text

The leading curl is optional: Curl.ExecuteAsync("https://httpbin.org/get") sends the same request.

Paste multi-line commands from API docs

Commands in API documentation usually span several lines. Put them in a C# 11 raw string literal and they run unchanged. The parser joins lines ending in \ (bash), ` (PowerShell) or ^ (cmd.exe).

using CurlDotNet;

var result = await Curl.ExecuteAsync("""
    curl -X POST https://httpbin.org/post \
      -H "Content-Type: application/json" \
      -d '{"name":"Ada","role":"admin"}'
    """);

Console.WriteLine(result.StatusCode);

On older C# versions, use a verbatim string (@"...") and double every embedded ".

The same request with the fluent builder

If you are writing the request yourself rather than pasting one, CurlRequestBuilder gives you IntelliSense and compile-time checking:

using CurlDotNet.Core;

var result = await CurlRequestBuilder
    .Post("https://httpbin.org/post")
    .WithJson(new { name = "Ada", role = "admin" })
    .ExecuteAsync();

Console.WriteLine(result.StatusCode);

Call .ToCurlCommand() on a builder to see the equivalent curl string.

What comes back

Every call returns a CurlDotNet.Core.CurlResult:

Member What it holds
StatusCode HTTP status as an int
IsSuccess true for 200-299
Body Response text (for text content types)
Headers Response headers, case-insensitive dictionary
IsBinary / BinaryData Raw bytes for images, PDFs, archives and other binary responses
OutputFiles Paths written by -o / -O
Timings.Total Total time in milliseconds

An HTTP error status such as 404 does not throw; check IsSuccess or call EnsureSuccess(). Add -f / --fail to have it throw CurlHttpReturnedErrorException (exit code 22) instead. Network failures (DNS, refused connection, timeout) throw a CurlException subclass whose CurlErrorCode is curl’s exit code. See error handling and the exit code reference.

Check a command without sending it

using CurlDotNet;

var check = Curl.Validate("curl -X POST");
if (!check.IsValid)
    Console.WriteLine(check.Error);  // No URL specified in command "curl -X POST": ...

Which curl flags work

The parser knows curl 8.7.1’s complete option table, including combined short flags (-sSL), attached values (-m10) and --long=value. The flags you meet in API docs all work: -X, -H, -d and its variants (--data-binary, --data-raw, --data-urlencode, --json), -G, -F, -T, -u with --basic, --digest, --ntlm, --negotiate and --anyauth, -A, -e, -b and -c (cookie strings and cookie jars), -L, --max-redirs, -k, -x, --proxy-user, --socks5, -m, --connect-timeout, --retry, -o, -O, -D, -I, -i, -v, --trace, --compressed, -r, -w, --http2 and --aws-sigv4. Several URLs in one command run one after another, URL globs such as [1-3] expand, and -K reads a config file; see multiple URLs and globbing and config files and variables.

Options that are recognised but not implemented are listed in ParsedOptions.UnsupportedOptions, and typos land in ParsedOptions.UnknownOptions (which makes Validate report the command as invalid). Not available: protocols other than HTTP, HTTPS, FTP and FILE, and --parallel (transfers run one after another). Client certificates and custom CAs (--cert, --key, --cacert, --capath, --pinnedpubkey) are applied on .NET 5 and later and listed in UnsupportedOptions on .NET Standard 2.0 and .NET Framework. ~/.curlrc is never read implicitly; pass it with -K.

Like the curl CLI, CurlDotNet sends User-Agent: curl/8.7.1 and Accept: */* by default, so APIs that require a User-Agent (GitHub’s, for example) work as pasted. Use -A to send your own.