Fazendo uma chamada cURL em C #


89

Quero fazer a seguinte curlchamada em meu aplicativo de console C #:

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

Tentei fazer como a questão postada aqui , mas não consigo preencher as propriedades corretamente.

Também tentei convertê-lo em uma solicitação HTTP normal:

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

Posso converter uma chamada cURL em uma solicitação HTTP? Se sim, como? Se não, como posso fazer a chamada cURL acima de meu aplicativo de console C # corretamente?



@DanielEarwicker: Eu diria que não, apenas porque HttpClientestá na mistura agora, e será a maneira de obter o conteúdo HTTP HttpWebRequeste WebClientseguir em frente.
casperOne

Respostas:


148

Bem, você não chamaria cURL diretamente, em vez disso, usaria uma das seguintes opções:

Eu recomendo fortemente usar a HttpClientclasse, já que ela foi projetada para ser muito melhor (do ponto de vista da usabilidade) do que as duas anteriores.

No seu caso, você faria o seguinte:

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

Observe também que a HttpClientclasse tem um suporte muito melhor para lidar com diferentes tipos de resposta e melhor suporte para operações assíncronas (e o cancelamento delas) em relação às opções mencionadas anteriormente.


7
Tentei seguir o seu código para um problema semelhante, mas estou recebendo erros que aguardam só podem ser definidos para métodos assíncronos.
Jay

@Jay Sim, async e await são um par, você não pode usar um sem o outro. Isso significa que você deve tornar o método de conteúdo (do qual não há nenhum aqui) assíncrono.
casperOne

1
@Jay A maioria desses métodos retornam Task<T>, você simplesmente não pode usar asynce então lidar com os tipos de retorno normalmente (você teria que chamar Task<T>.Result. Observe, é melhor usar asyncembora, pois você está desperdiçando o thread esperando pelo resultado.
casperOne

1
@Maxsteel Sim, é um array de, KeyValuePair<string, string>então você usarianew [] { new KeyValuePair<string, string>("text", "this is a block of text"), new KeyValuePair<string, string>("activity[verb]", "testVerb") }
casperOne

1
Isso pode funcionar para fazer uma chamada como essa? 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 de

25

Ou em 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
O exemplo de uso básico não funciona fora da caixa. restSharp é lixo.
Alex G

13

Abaixo está um código de exemplo funcional.

Observe que você precisa adicionar uma referência 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();

Referência: TheDeveloperBlog.com


3

Sei que essa é uma pergunta muito antiga, mas posto esta solução caso ajude alguém. Recentemente, encontrei esse problema e o Google me trouxe até aqui. A resposta aqui me ajuda a entender o problema, mas ainda há problemas devido à minha combinação de parâmetros. O que eventualmente resolve meu problema é o conversor curl para C # . É uma ferramenta muito poderosa e suporta a maioria dos parâmetros do Curl. O código que ele gera pode ser executado quase imediatamente.


3
Eu teria muito cuidado para não colar dados confidenciais (como cookies de autenticação) lá ...
Adi H

2

Resposta tardia, mas foi o que acabei fazendo. Se você deseja executar seus comandos curl de forma muito semelhante à que você executa no Linux e tem o Windows 10 ou posterior, faça o seguinte:

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

A razão pela qual o código é um pouco longo é porque o Windows apresentará um erro se você executar uma aspa simples. Em outras palavras, o comando curl 'https://google.com'funcionará no Linux e não no Windows. Graças a esse método que criei, você pode usar aspas simples e executar seus comandos curl exatamente como você os executa no Linux. Este código também verifica se há caracteres de escape, como \'e \".

Por exemplo, use este código como

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

Se você quiser executar a mesma string novamente C:\Windows\System32\curl.exe, não funcionará porque, por algum motivo, o Windows não gosta de aspas simples.


0

Chamar cURL de seu aplicativo de console não é uma boa ideia.

Mas você pode usar o TinyRestClient, que facilita a criação de solicitações:

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

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

0

Bem, se você é novo no C # com cmd-line exp. você pode usar sites online como " https://curl.olsh.me/ " ou search curl to C # converter irá retornar um site que pode fazer isso por você.

ou se você estiver usando o Postman, você pode usar Gerar Snippet de Código. O único problema com o gerador de código do Postman é a dependência da biblioteca RestSharp.


0

Não se esqueça de adicionar System.Net.Http, especialmente se você receber este erro:

Código de severidade Descrição Erro de estado de supressão de linha de arquivo de projeto CS0246 O tipo ou nome de namespace 'HttpClient' não foi encontrado (falta uma diretiva using ou uma referência de assembly?) 1_default.aspx D: \ Projetos \ Testes \ FacebookAPI \ FB-CustomAudience \ default.aspx.cs 56 ativo

Neste caso, você deve:

  1. Adicionar System.Net.Http do Nuget: Ferramentas / Gerenciador de pacotes NuGet / Gerenciador de pacotes NuGet para solução;
  2. Pesquise System.Net.Http
  3. Adicione no topo da sua página o seguinte código: using System.Net.Http;
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.