106

I want to make the following curl call in my C# console application:

curl -d "text=This is a block of text" \
    http://api.repustate.com/v2/demokey/score.json

I tried to do like the question posted here, but I cannot fill the properties properly.

I also tried to convert it to a regular HTTP request:

http://api.repustate.com/v2/demokey/score.json?text="This%20is%20a%20block%20of%20text"

Can I convert a cURL call to an HTTP request? If so, how? If not, how can I make the above cURL call from my C# console application properly?

Michael
  • 8,362
  • 6
  • 61
  • 88
smohamed
  • 3,234
  • 4
  • 32
  • 57

8 Answers8

171

Well, you wouldn't call cURL directly, rather, you'd use one of the following options:

I'd highly recommend using the HttpClient class, as it's engineered to be much better (from a usability standpoint) than the former two.

In your case, you would do this:

using System.Net.Http;

var client = new HttpClient();

// Create the HttpContent for the form to be posted.
var requestContent = new FormUrlEncodedContent(new [] {
    new KeyValuePair<string, string>("text", "This is a block of text"),
});

// Get the response.
HttpResponseMessage response = await client.PostAsync(
    "http://api.repustate.com/v2/demokey/score.json",
    requestContent);

// Get the response content.
HttpContent responseContent = response.Content;

// Get the stream of the content.
using (var reader = new StreamReader(await responseContent.ReadAsStreamAsync()))
{
    // Write the output.
    Console.WriteLine(await reader.ReadToEndAsync());
}

Also note that the HttpClient class has much better support for handling different response types, and better support for asynchronous operations (and the cancellation of them) over the previously mentioned options.

casperOne
  • 73,706
  • 19
  • 184
  • 253
  • 8
    I have tried following your code for a similar issue but I am being given errors that await can only be set to async methods? – Jay Sep 27 '13 at 15:48
  • @Jay Yes, async and await are a pair, you can't use one without the other. This means you have to make the containing method (of which there is none here) async. – casperOne Sep 27 '13 at 16:35
  • How could I check the response without async? – Jay Sep 29 '13 at 15:32
  • 1
    @Jay Most of those methods return `Task`, you can just not use `async` and then deal with the return types normally (you'd have to call `Task.Result`. Note, you're better of using `async` though as you're wasting the thread waiting for the result. – casperOne Sep 29 '13 at 19:03
  • @casperOne What If I have to pass something like: `text=test&activity[verb]=testVerb`? Can we pass more than one key value pair in `FormUrlEncodedContent`? – Maxsteel Jan 08 '14 at 19:26
  • 1
    @Maxsteel Yes, it's an array of `KeyValuePair` so you would just use `new [] { new KeyValuePair("text", "this is a block of text"), new KeyValuePair("activity[verb]", "testVerb") }` – casperOne Jan 09 '14 at 13:43
  • If you need to add custom headers to your request, you will need to use HttpWebRequest webreq = (HttpWebRequest)WebRequest.Create([yourUrl]); – Rudy Hinojosa Apr 02 '15 at 21:36
  • @RudyHinojosa That's not true. See the [`DefaultRequestHeaders`](https://msdn.microsoft.com/en-us/library/system.net.http.httpclient.defaultrequestheaders%28v=vs.118%29.aspx) property on the `HttpClient` class. – casperOne Apr 03 '15 at 03:46
  • Thanks Casper. I've learned a great deal more of our RequestHeaders since my last posting. I haven't had a chance to correct it. – Rudy Hinojosa Apr 03 '15 at 23:15
  • 2
    Can this work for making a call like this? `curl -k -i -H "Accept: application/json" -H "X-Application: " -X POST -d 'username=&password=' https://identitysso.betfair.com/api/login` – Murray Hart Feb 19 '16 at 11:47
  • I'm getting error - `Unable to process JSON` why ? any help ? – Neo Sep 10 '19 at 17:11
  • I know this post is old but, when I use cURL in Windows 10 command line utility, it works. However, when using either HttpWebRequest or HttpClient from a C# application, an HTTP 500 error occurs. What may be causing this? using curl I only do `curl -X POST "http://192.168.0.122:8088/api/door/remoteOpenByName?doorName=10.185.85.237-1&interval=5&access_token=1234"` and using HttpWebRequest, I do `WebRequest request = HttpWebRequest.Create(fullUri); request.Method = "POST"; WebResponse response = request.GetResponse()`. The exception is thrown in `request.GetResponse()` – jstuardo Jan 28 '21 at 23:52
25

Or in restSharp:

var client = new RestClient("https://example.com/?urlparam=true");
var request = new RestRequest(Method.POST);
request.AddHeader("content-type", "application/x-www-form-urlencoded");
request.AddHeader("cache-control", "no-cache");
request.AddHeader("header1", "headerval");
request.AddParameter("application/x-www-form-urlencoded", "bodykey=bodyval", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
Boris Verkhovskiy
  • 14,854
  • 11
  • 100
  • 103
online Thomas
  • 8,864
  • 6
  • 44
  • 85
13

Below is a working example code.

Please note you need to add a reference to Newtonsoft.Json.Linq

string url = "https://yourAPIurl";
WebRequest myReq = WebRequest.Create(url);
string credentials = "xxxxxxxxxxxxxxxxxxxxxxxx:yyyyyyyyyyyyyyyyyyyyyyyyyyyyyy";
CredentialCache mycache = new CredentialCache();
myReq.Headers["Authorization"] = "Basic " + Convert.ToBase64String(Encoding.ASCII.GetBytes(credentials));
WebResponse wr = myReq.GetResponse();
Stream receiveStream = wr.GetResponseStream();
StreamReader reader = new StreamReader(receiveStream, Encoding.UTF8);
string content = reader.ReadToEnd();
Console.WriteLine(content);
var json = "[" + content + "]"; // change this to array
var objects = JArray.Parse(json); // parse as array  
foreach (JObject o in objects.Children<JObject>())
{
    foreach (JProperty p in o.Properties())
    {
        string name = p.Name;
        string value = p.Value.ToString();
        Console.Write(name + ": " + value);
    }
}
Console.ReadLine();

Reference: TheDeveloperBlog.com

Mark Mayo
  • 12,230
  • 12
  • 54
  • 85
BenW
  • 1,393
  • 1
  • 16
  • 26
8

Late response but this is what I ended up doing. If you want to run your curl commands very similarly as you run them on linux and you have windows 10 or latter do this:

    public static string ExecuteCurl(string curlCommand, int timeoutInSeconds=60)
    {
        if (string.IsNullOrEmpty(curlCommand))
            return "";

        curlCommand = curlCommand.Trim();

        // remove the curl keworkd
        if (curlCommand.StartsWith("curl"))
        {
            curlCommand = curlCommand.Substring("curl".Length).Trim();
        }

        // this code only works on windows 10 or higher
        {

            curlCommand = curlCommand.Replace("--compressed", "");

            // windows 10 should contain this file
            var fullPath = System.IO.Path.Combine(Environment.SystemDirectory, "curl.exe");

            if (System.IO.File.Exists(fullPath) == false)
            {
                if (Debugger.IsAttached) { Debugger.Break(); }
                throw new Exception("Windows 10 or higher is required to run this application");
            }

            // on windows ' are not supported. For example: curl 'http://ublux.com' does not work and it needs to be replaced to curl "http://ublux.com"
            List<string> parameters = new List<string>();


            // separate parameters to escape quotes
            try
            {
                Queue<char> q = new Queue<char>();

                foreach (var c in curlCommand.ToCharArray())
                {
                    q.Enqueue(c);
                }

                StringBuilder currentParameter = new StringBuilder();

                void insertParameter()
                {
                    var temp = currentParameter.ToString().Trim();
                    if (string.IsNullOrEmpty(temp) == false)
                    {
                        parameters.Add(temp);
                    }

                    currentParameter.Clear();
                }

                while (true)
                {
                    if (q.Count == 0)
                    {
                        insertParameter();
                        break;
                    }

                    char x = q.Dequeue();

                    if (x == '\'')
                    {
                        insertParameter();

                        // add until we find last '
                        while (true)
                        {
                            x = q.Dequeue();

                            // if next 2 characetrs are \' 
                            if (x == '\\' && q.Count > 0 && q.Peek() == '\'')
                            {
                                currentParameter.Append('\'');
                                q.Dequeue();
                                continue;
                            }

                            if (x == '\'')
                            {
                                insertParameter();
                                break;
                            }

                            currentParameter.Append(x);
                        }
                    }
                    else if (x == '"')
                    {
                        insertParameter();

                        // add until we find last "
                        while (true)
                        {
                            x = q.Dequeue();

                            // if next 2 characetrs are \"
                            if (x == '\\' && q.Count > 0 && q.Peek() == '"')
                            {
                                currentParameter.Append('"');
                                q.Dequeue();
                                continue;
                            }

                            if (x == '"')
                            {
                                insertParameter();
                                break;
                            }

                            currentParameter.Append(x);
                        }
                    }
                    else
                    {
                        currentParameter.Append(x);
                    }
                }
            }
            catch
            {
                if (Debugger.IsAttached) { Debugger.Break(); }
                throw new Exception("Invalid curl command");
            }

            StringBuilder finalCommand = new StringBuilder();

            foreach (var p in parameters)
            {
                if (p.StartsWith("-"))
                {
                    finalCommand.Append(p);
                    finalCommand.Append(" ");
                    continue;
                }

                var temp = p;

                if (temp.Contains("\""))
                {
                    temp = temp.Replace("\"", "\\\"");
                }
                if (temp.Contains("'"))
                {
                    temp = temp.Replace("'", "\\'");
                }

                finalCommand.Append($"\"{temp}\"");
                finalCommand.Append(" ");
            }


            using (var proc = new Process
            {
                StartInfo = new ProcessStartInfo
                {
                    FileName = "curl.exe",
                    Arguments = finalCommand.ToString(),
                    UseShellExecute = false,
                    RedirectStandardOutput = true,
                    RedirectStandardError = true,
                    CreateNoWindow = true,
                    WorkingDirectory = Environment.SystemDirectory
                }
            })
            {
                proc.Start();

                proc.WaitForExit(timeoutInSeconds*1000);

                return proc.StandardOutput.ReadToEnd();
            }
        }
    }

The reason why the code is a little bit long is because windows will give you an error if you execute a single quote. In other words, the command curl 'https://google.com' will work on linux and it will not work on windows. Thanks to that method I created you can use single quotes and run your curl commands exactly as you run them on linux. This code also checks for escaping characters such as \' and \".

For example use this code as

var output = ExecuteCurl(@"curl 'https://google.com' -H 'Accept: application/json, text/javascript, */*; q=0.01'");

If you where to run that same string agains C:\Windows\System32\curl.exe it will not work because for some reason windows does not like single quotes.

Tono Nam
  • 34,064
  • 78
  • 298
  • 470
  • What Import/Namespace are you using that allows you to do this - ie use "curlCommand" in .NET? – PSU Mar 03 '22 at 11:56
  • Tono is just building a curl command and running it. Fine for an ETL. But otherwise, don't do this. It would be nice to have a library that wraps libCurl in C# that was updated this year. Latest I can find is 2016. – TamusJRoyce May 11 '23 at 14:29
  • example: curl --location https://roothost:port/api/endpoint/update --header "User-Agent: uspg" --header "Origin: http://localhost:5300" --header "Content-Type: application/json" --header "Accept: */*" --data "{"example": [{\"Key\": \"key\",\"Value\": \"value\"}],\"Id\": \"123\"}" --ntlm -u username:password – TamusJRoyce May 11 '23 at 14:30
6

I know this is a very old question but I post this solution in case it helps somebody. I recently met this problem and google led me here. The answer here helps me to understand the problem but there are still issues due to my parameter combination. What eventually solves my problem is curl to C# converter. It is a very powerful tool and supports most of the parameters for Curl. The code it generates is almost immediately runnable.

Bob
  • 381
  • 4
  • 14
1

Well if you are new to C# with cmd-line exp. you can use online sites like "https://curl.olsh.me/" or search curl to C# converter will returns site that could do that for you.

or if you are using postman you can use Generate Code Snippet only problem with Postman code generator is the dependency on RestSharp library.

Navid Golforoushan
  • 728
  • 1
  • 9
  • 16
  • latest postman support httpclient as well. But it won't add credentials. So ntlm authorization or others won't come through. https://curl.olsh.me demo is awesome too. One difference is postman forgets the using clause for HttpRequestMessage. curl.olsh.me includes the using – TamusJRoyce May 11 '23 at 14:23
1

Don't forget to add System.Net.Http, specially if you receive this error:

Severity Code Description Project File Line Suppression State Error CS0246 The type or namespace name 'HttpClient' could not be found (are you missing a using directive or an assembly reference?) 1_default.aspx D:\Projetos\Testes\FacebookAPI\FB-CustomAudience\default.aspx.cs 56 Active

In this case you shoud:

  1. Add System.Net.Http from Nuget: Tools / NuGet Package Manager / Manager NuGet Packages for Solution;
  2. Search for System.Net.Http
  3. Add in the top of your page the follow code: using System.Net.Http;
0

Call cURL from your console app is not a good idea.

But you can use TinyRestClient which make easier to build requests :

var client = new TinyRestClient(new HttpClient(),"https://api.repustate.com/");

client.PostRequest("v2/demokey/score.json").
AddQueryParameter("text", "").
ExecuteAsync<MyResponse>();
user8803505
  • 126
  • 1
  • 5