Hacer una llamada cURL en C #

89

Quiero realizar la siguiente curlllamada en mi aplicación de consola C #:

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

Intenté hacer como la pregunta publicada aquí , pero no puedo completar las propiedades correctamente.

También intenté convertirlo en una solicitud HTTP regular:

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

¿Puedo convertir una llamada cURL en una solicitud HTTP? ¿Si es así, cómo? Si no es así, ¿cómo puedo realizar correctamente la llamada cURL anterior desde mi aplicación de consola C #?

ahumado
fuente
posible duplicado de la descarga de archivos usando httprequest
Daniel Earwicker
@DanielEarwicker: Yo diría que no lo es, solo porque HttpClientestá en la mezcla ahora, y será la forma de obtener contenido HTTP HttpWebRequesty WebClientseguir adelante.
casperOne

Respuestas:

147

Bueno, no llamarías a cURL directamente, sino que usarías una de las siguientes opciones:

Recomiendo encarecidamente usar el HttpClient clase, ya que está diseñada para ser mucho mejor (desde el punto de vista de la usabilidad) que las dos anteriores.

En su caso, haría esto:

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

También tenga en cuenta que la HttpClientclase tiene un soporte mucho mejor para manejar diferentes tipos de respuesta y un mejor soporte para operaciones asincrónicas (y su cancelación) sobre las opciones mencionadas anteriormente.

casperOne
fuente
7
He intentado seguir su código para un problema similar, pero me están dando errores que esperan solo se pueden configurar en métodos asíncronos.
Jay
@Jay Sí, async y await son un par, no puedes usar uno sin el otro. Esto significa que debe hacer que el método contenedor (del cual no hay ninguno aquí) sea asíncrono.
casperOne
1
@Jay La mayoría de esos métodos regresan Task<T>, simplemente no puede usarlos asyncy luego tratar con los tipos de retorno normalmente (tendría que llamar Task<T>.Result. Tenga en cuenta que es mejor usarlos asyncya que está desperdiciando el hilo esperando el resultado.
casperOne
1
@Maxsteel Sí, es una variedad de, KeyValuePair<string, string>por lo que solo usaríanew [] { new KeyValuePair<string, string>("text", "this is a block of text"), new KeyValuePair<string, string>("activity[verb]", "testVerb") }
casperOne
1
¿Puede funcionar esto para hacer una llamada como esta? 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
24

O en reposo Sharp :

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);
en línea Thomas
fuente
1
El ejemplo de uso básico no funciona de inmediato. restSharp es basura.
Alex G
1
@AlexG Entonces lo estás haciendo mal. Funciona para mi.
user2924019
13

A continuación se muestra un código de ejemplo funcional.

Tenga en cuenta que debe agregar una referencia a 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();

Referencia: TheDeveloperBlog.com

BenW
fuente
3

Sé que esta es una pregunta muy antigua, pero publico esta solución en caso de que ayude a alguien. Recientemente encontré este problema y Google me trajo aquí. La respuesta aquí me ayuda a comprender el problema, pero todavía hay problemas debido a mi combinación de parámetros. Lo que finalmente resuelve mi problema es el convertidor de curl a C # . Es una herramienta muy poderosa y es compatible con la mayoría de los parámetros de Curl. El código que genera se puede ejecutar casi de inmediato.

Beto
fuente
3
Sería muy cuidadoso de no pegar ningún dato sensible (como cookies de autenticación) allí ...
Adi H
2

Respuesta tardía, pero esto es lo que terminé haciendo. Si desea ejecutar sus comandos curl de manera muy similar a como los ejecuta en Linux y tiene Windows 10 o posterior, haga esto:

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

La razón por la que el código es un poco largo es porque Windows le dará un error si ejecuta una comilla simple. En otras palabras, el comando curl 'https://google.com'funcionará en Linux y no en Windows. Gracias a ese método que creé, puedes usar comillas simples y ejecutar tus comandos curl exactamente como los ejecutas en Linux. Este código también busca caracteres de escape como \'y \".

Por ejemplo, use este código como

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

Si C:\Windows\System32\curl.exevuelve a ejecutar la misma cadena , no funcionará porque, por alguna razón, a Windows no le gustan las comillas simples.

Tono Nam
fuente
0

Llamar a cURL desde la aplicación de su consola no es una buena idea.

Pero puede usar TinyRestClient que facilita la creación de solicitudes:

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

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

Bueno, si eres nuevo en C # con cmd-line exp. puede utilizar sitios en línea como " https://curl.olsh.me/ " o buscar el convertidor de curl a C # devolverá el sitio que podría hacer eso por usted.

o si está usando Postman, puede usar Generate Code Snippet. El único problema con el generador de código Postman es la dependencia de la biblioteca RestSharp.

Navid Golforoushan
fuente