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.