การโทร cURL ใน C #


89

ฉันต้องการcurlโทรต่อไปนี้ในแอปพลิเคชันคอนโซล C # ของฉัน:

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

ฉันพยายามทำเหมือนคำถามที่โพสต์ไว้ที่นี่แต่ฉันไม่สามารถกรอกคุณสมบัติได้อย่างถูกต้อง

ฉันยังพยายามแปลงเป็นคำขอ HTTP ปกติ:

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

ฉันสามารถแปลงการโทร cURL เป็นคำขอ HTTP ได้หรือไม่ ถ้าเป็นเช่นนั้นอย่างไร? ถ้าไม่ฉันจะโทร cURL ข้างต้นจากแอปพลิเคชันคอนโซล C # อย่างถูกต้องได้อย่างไร



@DanielEarwicker: ผมว่ามันไม่ได้เป็นเพียงเพราะHttpClientเป็นในการผสมในขณะนี้และมันจะเป็นวิธีการรับ HTTP เนื้อหามากกว่าและก้าวไปข้างหน้า HttpWebRequestWebClient
casperOne

คำตอบ:


148

คุณจะไม่เรียกcURLโดยตรง แต่คุณจะใช้หนึ่งในตัวเลือกต่อไปนี้:

ฉันขอแนะนำให้ใช้HttpClientคลาสนี้เนื่องจากได้รับการออกแบบมาให้ดีขึ้นมาก (จากมุมมองด้านการใช้งาน) มากกว่าสองคลาสเดิม

ในกรณีของคุณคุณจะทำสิ่งนี้:

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());
}

นอกจากนี้โปรดทราบว่าHttpClientคลาสนี้มีการสนับสนุนที่ดีกว่ามากสำหรับการจัดการประเภทการตอบสนองที่แตกต่างกันและการสนับสนุนที่ดีกว่าสำหรับการดำเนินการแบบอะซิงโครนัส (และการยกเลิก) ในตัวเลือกที่กล่าวถึงก่อนหน้านี้


7
ฉันได้ลองทำตามรหัสของคุณสำหรับปัญหาที่คล้ายกัน แต่ฉันได้รับข้อผิดพลาดที่รอให้ตั้งค่าเป็นวิธี async เท่านั้น?
Jay

@Jay ใช่ async และการรอคอยเป็นคู่คุณไม่สามารถใช้คู่กันได้หากไม่มีคู่อื่น ซึ่งหมายความว่าคุณต้องสร้าง method ที่มี (ซึ่งไม่มีเลย) async
casperOne

1
@Jay วิธีการเหล่านั้นส่วนใหญ่จะส่งคืนTask<T>คุณไม่สามารถใช้asyncและจัดการกับประเภทการส่งคืนได้ตามปกติ (คุณต้องโทรหาTask<T>.Resultโปรดทราบว่าคุณควรใช้asyncแม้ว่าคุณจะเสียเธรดในการรอผลลัพธ์
casperOne

1
@Maxsteel ใช่มันเป็นอาร์เรย์KeyValuePair<string, string>ดังนั้นคุณจะใช้new [] { new KeyValuePair<string, string>("text", "this is a block of text"), new KeyValuePair<string, string>("activity[verb]", "testVerb") }
casperOne

1
งานโทรออกแบบนี้ได้ไหม curl -k -i -H "Accept: application/json" -H "X-Application: <AppKey>" -X POST -d 'username=<username>&password=<password>' https://identitysso.betfair.com/api/login
Murray Hart

25

หรือใน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);

1
ตัวอย่างการใช้งานพื้นฐานใช้ไม่ได้นอกกรอบ restSharp เป็นขยะ
Alex G

13

ด้านล่างนี้เป็นโค้ดตัวอย่างการทำงาน

โปรดทราบว่าคุณต้องเพิ่มการอ้างอิงถึง 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();

อ้างอิง: TheDeveloperBlog.com


3

ฉันรู้ว่านี่เป็นคำถามเก่ามาก แต่ฉันโพสต์วิธีแก้ปัญหานี้เผื่อว่าจะช่วยใครได้ ฉันเพิ่งพบปัญหานี้และ google พาฉันมาที่นี่ คำตอบที่นี่ช่วยให้ฉันเข้าใจปัญหา แต่ยังคงมีปัญหาเนื่องจากการรวมพารามิเตอร์ของฉัน สิ่งที่ในที่สุดจะช่วยแก้ปัญหาของฉันคือขดไป C # แปลง เป็นเครื่องมือที่ทรงพลังมากและรองรับพารามิเตอร์ส่วนใหญ่สำหรับ Curl โค้ดที่สร้างขึ้นสามารถรันได้เกือบจะในทันที


3
ฉันจะระมัดระวังไม่ให้วางข้อมูลที่ละเอียดอ่อน (เช่นคุกกี้รับรองความถูกต้อง) ไว้ที่นั่น ...
Adi H

2

ตอบช้า แต่นี่คือสิ่งที่ฉันทำ หากคุณต้องการเรียกใช้คำสั่ง curl ในลักษณะเดียวกับที่คุณรันบน linux และคุณมี windows 10 หรือรุ่นหลังให้ทำดังนี้:

    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();
            }
        }
    }

สาเหตุที่โค้ดยาวไปหน่อยเนื่องจาก windows จะทำให้คุณมีข้อผิดพลาดหากคุณดำเนินการอ้างเพียงครั้งเดียว กล่าวอีกนัยหนึ่งคำสั่งcurl 'https://google.com'จะทำงานบน linux และจะไม่ทำงานบน windows ด้วยวิธีการนั้นที่ฉันสร้างขึ้นคุณสามารถใช้เครื่องหมายคำพูดเดี่ยวและเรียกใช้คำสั่ง curl ของคุณได้เหมือนกับที่คุณเรียกใช้บน linux รหัสนี้ยังตรวจสอบการหลบหนีตัวอักษรเช่นและ\'\"

ตัวอย่างเช่นใช้รหัสนี้เป็น

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

หากคุณเรียกใช้สตริงเดิมC:\Windows\System32\curl.exeนั้นอีกครั้งจะใช้ไม่ได้เนื่องจากเหตุผลบางประการ windows ไม่ชอบเครื่องหมายคำพูดเดี่ยว


0

การโทร cURL จากแอปคอนโซลไม่ใช่ความคิดที่ดี

แต่คุณสามารถใช้TinyRestClientซึ่งช่วยให้สร้างคำขอได้ง่ายขึ้น:

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

client.PostRequest("v2/demokey/score.json").
AddQueryParameter("text", "").
ExecuteAsync<MyResponse>();

0

ถ้าคุณยังใหม่กับ C # ด้วย cmd-line exp คุณสามารถใช้เว็บไซต์ออนไลน์เช่น " https://curl.olsh.me/ " หรือการค้นหา curl เป็น C # converter จะส่งคืนไซต์ที่สามารถทำเช่นนั้นให้คุณได้

หรือถ้าคุณใช้บุรุษไปรษณีย์คุณสามารถใช้ Generate Code Snippet ได้เท่านั้นปัญหากับ Postman code generator คือการพึ่งพาไลบรารี RestSharp


0

อย่าลืมเพิ่ม System.Net.Http โดยเฉพาะหากคุณได้รับข้อผิดพลาดนี้:

คำอธิบายรหัสความรุนแรงข้อผิดพลาดสถานะการระงับบรรทัดไฟล์โครงการ CS0246 ไม่พบชนิดหรือชื่อเนมสเปซ 'HttpClient' (คุณขาดคำสั่งโดยใช้คำสั่งหรือการอ้างอิงแอสเซมบลีหรือไม่) 1_default.aspx D: \ Projetos \ Testes \ FacebookAPI \ FB-CustomAudience \ default.aspx.cs 56 ใช้งานอยู่

ในกรณีนี้คุณจะตะโกน:

  1. เพิ่ม System.Net.Http จาก Nuget: Tools / NuGet Package Manager / Manager NuGet Packages สำหรับโซลูชัน
  2. ค้นหา System.Net.Http
  3. เพิ่มโค้ดติดตามที่ด้านบนสุดของเพจโดยใช้ System.Net.Http;
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.