How to send curl PUT, DELETE and PATCH requests in C#
To send PUT, DELETE or PATCH requests in C# the curl way, set the method with -X in the command you pass to Curl.ExecuteAsync (-X PUT, -X PATCH, -X DELETE), or start the fluent builder with CurlRequestBuilder.Put, .Patch or .Delete.
dotnet add package CurlDotNet
PUT: replace a resource
using CurlDotNet;
var result = await Curl.ExecuteAsync("""
curl -X PUT https://httpbin.org/put \
-H "Content-Type: application/json" \
-d '{"id":42,"name":"Ada","role":"admin"}'
""");
Console.WriteLine(result.StatusCode); // 200
PATCH: change part of a resource
using CurlDotNet;
var result = await Curl.ExecuteAsync(
"""curl -X PATCH https://httpbin.org/patch --json '{"role":"owner"}'""");
Console.WriteLine(result.StatusCode);
DELETE
using CurlDotNet;
var result = await Curl.ExecuteAsync(
"curl -X DELETE https://httpbin.org/delete -H 'Authorization: Bearer my-token'");
Console.WriteLine(result.IsSuccess); // many APIs answer 204 No Content
The fluent builder
using CurlDotNet.Core;
var put = await CurlRequestBuilder.Put("https://httpbin.org/put")
.WithJson(new { id = 42, name = "Ada" }).ExecuteAsync();
var patch = await CurlRequestBuilder.Patch("https://httpbin.org/patch")
.WithJson(new { role = "owner" }).ExecuteAsync();
var delete = await CurlRequestBuilder.Delete("https://httpbin.org/delete")
.WithBearerToken("my-token").ExecuteAsync();
Other verbs go through CurlRequestBuilder.Request("OPTIONS", url) or -X OPTIONS.
A small REST client
CurlApiClient wraps a base URL and sends JSON for you:
using CurlDotNet;
var api = new CurlApiClient("https://httpbin.org", TimeSpan.FromSeconds(15));
var created = await api.PostJsonAsync("/post", new { name = "Ada" });
var updated = await api.PutJsonAsync("/put", new { name = "Ada L." });
var patched = await api.PatchJsonAsync("/patch", new { role = "owner" });
var deleted = await api.DeleteAsync("/delete");
With LibCurl
LibCurl.PutAsync and PatchAsync serialize an object body to JSON, but they do not add a JSON Content-Type themselves (without one the body goes out as application/x-www-form-urlencoded, as with curl -d). Add it as a default header:
using CurlDotNet.Lib;
using var curl = new LibCurl();
curl.WithHeader("Content-Type", "application/json");
var result = await curl.PutAsync("https://httpbin.org/put", new { id = 42 });
Console.WriteLine(result.StatusCode);
Checking the result
Expect 200 OK, 201 Created, 202 Accepted or 204 No Content on success; result.IsSuccess covers all of them. A 409 Conflict or 412 Precondition Failed does not throw, so check the status, call EnsureSuccess() to turn any non-2xx status into an exception, or add -f to the command to have curl’s CurlHttpReturnedErrorException (exit code 22) thrown for any status of 400 or above.
-T file is a shortcut for a PUT of a file’s bytes, and -X GET -d '...' sends a GET with a body, both as in curl. With -L, a method set with -X is kept on every redirect hop.