Como faço chamadas para uma API REST usando c #?

335

Este é o código que tenho até agora:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System;
using System.Net.Http;
using System.Web;
using System.Net;
using System.IO;

namespace ConsoleProgram
{
    public class Class1
    {
        private const string URL = "https://sub.domain.com/objects.json?api_key=123";
        private const string DATA = @"{""object"":{""name"":""Name""}}";

        static void Main(string[] args)
        {
            Class1.CreateObject();
        }

        private static void CreateObject()
        {
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(URL);
            request.Method = "POST";
            request.ContentType = "application/json"; 
            request.ContentLength = DATA.Length;
            StreamWriter requestWriter = new StreamWriter(request.GetRequestStream(), System.Text.Encoding.ASCII);
            requestWriter.Write(DATA);
            requestWriter.Close();

             try {
                WebResponse webResponse = request.GetResponse();
                Stream webStream = webResponse.GetResponseStream();
                StreamReader responseReader = new StreamReader(webStream);
                string response = responseReader.ReadToEnd();
                Console.Out.WriteLine(response);
                responseReader.Close();
            } catch (Exception e) {
                Console.Out.WriteLine("-----------------");
                Console.Out.WriteLine(e.Message);
            }

        }
    }
}

O problema é que acho que o bloco de exceção está sendo acionado (porque quando removo a tentativa de captura, recebo uma mensagem de erro do servidor (500). Mas não vejo as linhas Console.Out que coloco no bloco de captura.

Meu console:

The thread 'vshost.NotifyLoad' (0x1a20) has exited with code 0 (0x0).
The thread '<No Name>' (0x1988) has exited with code 0 (0x0).
The thread 'vshost.LoadReference' (0x1710) has exited with code 0 (0x0).
'ConsoleApplication1.vshost.exe' (Managed (v4.0.30319)): Loaded 'c:\users\l. preston sego iii\documents\visual studio 11\Projects\ConsoleApplication1\ConsoleApplication1\bin\Debug\ConsoleApplication1.exe', Symbols loaded.
'ConsoleApplication1.vshost.exe' (Managed (v4.0.30319)): Loaded 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Configuration\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Configuration.dll', Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
A first chance exception of type 'System.Net.WebException' occurred in System.dll
The thread 'vshost.RunParkingWindow' (0x184c) has exited with code 0 (0x0).
The thread '<No Name>' (0x1810) has exited with code 0 (0x0).
The program '[2780] ConsoleApplication1.vshost.exe: Program Trace' has exited with code 0 (0x0).
The program '[2780] ConsoleApplication1.vshost.exe: Managed (v4.0.30319)' has exited with code 0 (0x0).

Estou usando o Visual Studio 2011 Beta e o .NET 4.5 Beta.

NullVoxPopuli
fonte
Além disso, você colocou pontos de interrupção lá para ver onde exatamente está explodindo?
NotMe
este é o resultado de janela de saída, mas não consolar
Serj-Tm
5
O MSDN tinha um excelente artigo sobre a criação de serviços RESTful: msdn.microsoft.com/library/dd203052.aspx ... e clientes RESTful: msdn.microsoft.com/en-us/magazine/ee309509.aspx
Lynn Crumbling
@ Chrishrively, o que isso tem a ver com o IE? = \ Está explodindo na linha request.GetResponse.
NullVoxPopuli
@TheLindyHop; Absolutamente nada. Eu li errado.
NotMe

Respostas:

427

A API da Web do ASP.Net substituiu a API da Web do WCF mencionada anteriormente.

Eu pensei em postar uma resposta atualizada, já que a maioria dessas respostas é do início de 2012, e esse tópico é um dos principais resultados ao fazer uma pesquisa no Google por "chamar serviço repousante c #".

A orientação atual da Microsoft é usar as Bibliotecas cliente da API da Web do Microsoft ASP.NET para consumir um serviço RESTful. Está disponível como um pacote NuGet, Microsoft.AspNet.WebApi.Client. Você precisará adicionar este pacote NuGet à sua solução.

Veja como o seu exemplo ficaria quando implementado usando a biblioteca cliente da API da Web do ASP.Net:

using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Headers; 

namespace ConsoleProgram
{
    public class DataObject
    {
        public string Name { get; set; }
    }

    public class Class1
    {
        private const string URL = "https://sub.domain.com/objects.json";
        private string urlParameters = "?api_key=123";

        static void Main(string[] args)
        {
            HttpClient client = new HttpClient();
            client.BaseAddress = new Uri(URL);

            // Add an Accept header for JSON format.
            client.DefaultRequestHeaders.Accept.Add(
            new MediaTypeWithQualityHeaderValue("application/json"));

            // List data response.
            HttpResponseMessage response = client.GetAsync(urlParameters).Result;  // Blocking call! Program will wait here until a response is received or a timeout occurs.
            if (response.IsSuccessStatusCode)
            {
                // Parse the response body.
                var dataObjects = response.Content.ReadAsAsync<IEnumerable<DataObject>>().Result;  //Make sure to add a reference to System.Net.Http.Formatting.dll
                foreach (var d in dataObjects)
                {
                    Console.WriteLine("{0}", d.Name);
                }
            }
            else
            {
                Console.WriteLine("{0} ({1})", (int)response.StatusCode, response.ReasonPhrase);
            }

            //Make any other calls using HttpClient here.

            //Dispose once all HttpClient calls are complete. This is not necessary if the containing object will be disposed of; for example in this case the HttpClient instance will be disposed automatically when the application terminates so the following call is superfluous.
            client.Dispose();
        }
    }
}

Se você planeja fazer várias solicitações, reutilize sua instância HttpClient. Consulte esta pergunta e suas respostas para obter mais detalhes sobre por que uma instrução using não foi usada na instância HttpClient neste caso: HttpClient e HttpClientHandler precisam ser descartados?

Para mais detalhes, incluindo outros exemplos, acesse aqui: http://www.asp.net/web-api/overview/web-api-clients/calling-a-web-api-from-a-net-client

Esta publicação no blog também pode ser útil: http://johnnycode.com/2012/02/23/consuming-your-own-asp-net-web-api-rest-service/

Brian Swift
fonte
6
Obrigado! Eu precisava instalar o pacote NuGet do cliente WebApi para que isso funcionasse para mim: Install-Package Microsoft.AspNet.WebApi.Client
Ev.
3
Se você precisar zombar de sua integração REST, mesmo com as bibliotecas cliente, ainda não é fácil. Tente RestSharp?
Rob Church
6
Para tornar esta resposta ainda melhor do que já é, você deve envolver a declaração HttpClient em um usando instrução para melhor gerir o seu recurso :)
Daniel Siebert
7
Tentei usar, mas não foi possível usar o ReadAsAsync (), obtendo o erro "HttpContent não contém uma definição para 'ReadAsAsync' e nenhum método de extensão.
Robert Green MBA
7
@RobertGreenMBA: para obter o método de extensão ReadAsAsync(), adicione uma referência a System.Net.Http.Formatting.dll. (Intuitivo, certo?)
Arin
122

Minha sugestão seria usar o RestSharp . Você pode fazer chamadas para os serviços REST e convertê-los em objetos POCO com muito pouco código padrão, para realmente precisar analisar a resposta. Isso não resolverá seu erro específico, mas responde à sua pergunta geral sobre como fazer chamadas para serviços REST. Ter que alterar seu código para usá-lo deve compensar a facilidade de uso e a robustez do futuro. Isso é apenas meus 2 centavos embora

Exemplo:

namespace RestSharpThingy
{
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Net;
    using System.Reflection;

    using RestSharp;

    public static class Program
    {
        public static void Main()
        {
            Uri baseUrl = new Uri("https://httpbin.org/");
            IRestClient client = new RestClient(baseUrl);
            IRestRequest request = new RestRequest("get", Method.GET) { Credentials = new NetworkCredential("testUser", "P455w0rd") };

            request.AddHeader("Authorization", "Bearer qaPmk9Vw8o7r7UOiX-3b-8Z_6r3w0Iu2pecwJ3x7CngjPp2fN3c61Q_5VU3y0rc-vPpkTKuaOI2eRs3bMyA5ucKKzY1thMFoM0wjnReEYeMGyq3JfZ-OIko1if3NmIj79ZSpNotLL2734ts2jGBjw8-uUgKet7jQAaq-qf5aIDwzUo0bnGosEj_UkFxiJKXPPlF2L4iNJSlBqRYrhw08RK1SzB4tf18Airb80WVy1Kewx2NGq5zCC-SCzvJW-mlOtjIDBAQ5intqaRkwRaSyjJ_MagxJF_CLc4BNUYC3hC2ejQDoTE6HYMWMcg0mbyWghMFpOw3gqyfAGjr6LPJcIly__aJ5__iyt-BTkOnMpDAZLTjzx4qDHMPWeND-TlzKWXjVb5yMv5Q6Jg6UmETWbuxyTdvGTJFzanUg1HWzPr7gSs6GLEv9VDTMiC8a5sNcGyLcHBIJo8mErrZrIssHvbT8ZUPWtyJaujKvdgazqsrad9CO3iRsZWQJ3lpvdQwucCsyjoRVoj_mXYhz3JK3wfOjLff16Gy1NLbj4gmOhBBRb8rJnUXnP7rBHs00FAk59BIpKLIPIyMgYBApDCut8V55AgXtGs4MgFFiJKbuaKxq8cdMYEVBTzDJ-S1IR5d6eiTGusD5aFlUkAs9NV_nFw");
            request.AddParameter("clientId", 123);

            IRestResponse<RootObject> response = client.Execute<RootObject>(request);

            if (response.IsSuccessful)
            {
                response.Data.Write();
            }
            else
            {
                Console.WriteLine(response.ErrorMessage);
            }

            Console.WriteLine();

            string path = Assembly.GetExecutingAssembly().Location;
            string name = Path.GetFileName(path);

            request = new RestRequest("post", Method.POST);
            request.AddFile(name, File.ReadAllBytes(path), name, "application/octet-stream");
            response = client.Execute<RootObject>(request);
            if (response.IsSuccessful)
            {
                response.Data.Write();
            }
            else
            {
                Console.WriteLine(response.ErrorMessage);
            }

            Console.ReadLine();
        }

        private static void Write(this RootObject rootObject)
        {
            Console.WriteLine("clientId: " + rootObject.args.clientId);
            Console.WriteLine("Accept: " + rootObject.headers.Accept);
            Console.WriteLine("AcceptEncoding: " + rootObject.headers.AcceptEncoding);
            Console.WriteLine("AcceptLanguage: " + rootObject.headers.AcceptLanguage);
            Console.WriteLine("Authorization: " + rootObject.headers.Authorization);
            Console.WriteLine("Connection: " + rootObject.headers.Connection);
            Console.WriteLine("Dnt: " + rootObject.headers.Dnt);
            Console.WriteLine("Host: " + rootObject.headers.Host);
            Console.WriteLine("Origin: " + rootObject.headers.Origin);
            Console.WriteLine("Referer: " + rootObject.headers.Referer);
            Console.WriteLine("UserAgent: " + rootObject.headers.UserAgent);
            Console.WriteLine("origin: " + rootObject.origin);
            Console.WriteLine("url: " + rootObject.url);
            Console.WriteLine("data: " + rootObject.data);
            Console.WriteLine("files: ");
            foreach (KeyValuePair<string, string> kvp in rootObject.files ?? Enumerable.Empty<KeyValuePair<string, string>>())
            {
                Console.WriteLine("\t" + kvp.Key + ": " + kvp.Value);
            }
        }
    }

    public class Args
    {
        public string clientId { get; set; }
    }

    public class Headers
    {
        public string Accept { get; set; }

        public string AcceptEncoding { get; set; }

        public string AcceptLanguage { get; set; }

        public string Authorization { get; set; }

        public string Connection { get; set; }

        public string Dnt { get; set; }

        public string Host { get; set; }

        public string Origin { get; set; }

        public string Referer { get; set; }

        public string UserAgent { get; set; }
    }

    public class RootObject
    {
        public Args args { get; set; }

        public Headers headers { get; set; }

        public string origin { get; set; }

        public string url { get; set; }

        public string data { get; set; }

        public Dictionary<string, string> files { get; set; }
    }
}
Justin Pihony
fonte
6
O RestSharp e o JSON.NET são definitivamente o caminho a percorrer. Achei que o conjunto de ferramentas da MS estava ausente e provavelmente falharia.
Cbuteau 24/09/2015
2
Outro voto para o RestSharp, porque você pode testá-lo para testar muito, muito mais facilmente do que as bibliotecas WebApi Client.
Rob Church
1
para usuários mono - o RestSharp parece estar usando as APIs System.Net WebRequest - que, na minha experiência, não são tão confiáveis ​​quanto as implementações .net. ('aleatório' trava)
Tom
3
Seria bom ter um exemplo nesta resposta, por favor.
Caltor
2
A falta de um exemplo faz com que este post não seja útil!
smac2020
39

Sem relação, tenho certeza, mas envolva seus IDisposableobjetos em usingblocos para garantir o descarte adequado:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System;
using System.Web;
using System.Net;
using System.IO;

namespace ConsoleProgram
{
    public class Class1
    {
        private const string URL = "https://sub.domain.com/objects.json?api_key=123";
        private const string DATA = @"{""object"":{""name"":""Name""}}";

        static void Main(string[] args)
        {
            Class1.CreateObject();
        }

        private static void CreateObject()
        {
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(URL);
            request.Method = "POST";
            request.ContentType = "application/json";
            request.ContentLength = DATA.Length;
            using (Stream webStream = request.GetRequestStream())
            using (StreamWriter requestWriter = new StreamWriter(webStream, System.Text.Encoding.ASCII))
            {
                requestWriter.Write(DATA);
            }

            try
            {
                WebResponse webResponse = request.GetResponse();
                using (Stream webStream = webResponse.GetResponseStream() ?? Stream.Null)
                using (StreamReader responseReader = new StreamReader(webStream))
                {
                    string response = responseReader.ReadToEnd();
                    Console.Out.WriteLine(response);
                }
            }
            catch (Exception e)
            {
                Console.Out.WriteLine("-----------------");
                Console.Out.WriteLine(e.Message);
            }

        }
    }
}
Jesse C. Slicer
fonte
4
Boa resposta que não usa nenhum pacote extra fora do ambiente .NET normal.
palswim
@Jesse C. Slicer .. por que acertei o erro 404 no WebResponse webResponse = request.GetResponse ();
Goh Han
2
Porque o recurso não foi encontrado? Há muitas, muitas razões para obter um 404.
Jesse C. Slicer
1
Esta é uma ótima solução @ JesseC.Slicer. Sou capaz de aplicar esse código para extrair um token e vê-lo no console. Você tem alguma dica para que agora eu leve esse token para autenticação / login? Quero usar o GET para extrair alguns dados, mas só poderia ser feito se estiver conectado. Onde posso aprender mais sobre isso? Obrigado!
Paul Laguna
18

Aqui estão algumas maneiras diferentes de chamar uma API externa em C # (atualizado em 2019).

Maneiras internas do .NET:

  • WebRequest & WebClient - APIs detalhadas e documentação da Microsoft não é muito fácil de seguir
  • HttpClient - o mais novo garoto do .NET no setor e muito mais simples de usar que o anterior.

Pacotes NuGet gratuitos e de código aberto , que francamente têm uma experiência de desenvolvedor muito melhor do que os clientes internos do .NET:

  • ServiceStack.Text (1k estrelas no github, downloads de 7m Nuget) (*) - rápido, leve e resistente.
  • RestSharp (6k estrelas do github, 23m de downloads Nuget) (*) - cliente REST e HTTP API simples
  • Flurl (1,7k estrelas do github, 3m de downloads Nuget) (*) - uma biblioteca de clientes HTTP fluente, portátil e testável

Todos os pacotes acima fornecem uma ótima experiência para o desenvolvedor (API concisa e fácil) e são bem mantidos.

(*) em agosto de 2019

Exemplo: Obtendo um item Todo a partir de uma API Fake Rest usando ServiceStack.Text. As outras bibliotecas têm sintaxe muito semelhante.

class Program
{
    static void Main(string[] args)
    {
        // fake rest API
        string url = "https://jsonplaceholder.typicode.com/todos/1";

        // GET data from api & map to Poco
        var todo =  url.GetJsonFromUrl().FromJson<Todo>();

        // print result to screen
        todo.PrintDump();
    }
    public class Todo
    {
        public int UserId { get; set; }
        public int Id { get; set; }
        public string Title { get; set; }
        public bool Completed { get; set; }
    }

}

A execução do exemplo acima em um aplicativo .NET Core Console produz a seguinte saída.

insira a descrição da imagem aqui

Instale esses pacotes usando o NuGet

Install-Package ServiceStack.Text, or

Install-Package RestSharp, or

Install-Package Flurl.Http
Programando com Mark
fonte
17

Use o código abaixo para sua solicitação de API REST

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Json;

namespace ConsoleApplication2
{
    class Program
    {
        private const string URL = "https://XXXX/rest/api/2/component";
        private const string DATA = @"{
    ""name"": ""Component 2"",
    ""description"": ""This is a JIRA component"",
    ""leadUserName"": ""xx"",
    ""assigneeType"": ""PROJECT_LEAD"",
    ""isAssigneeTypeValid"": false,
    ""project"": ""TP""}";

        static void Main(string[] args)
        {
            AddComponent();
        }

        private static void AddComponent()
        {
            System.Net.Http.HttpClient client = new System.Net.Http.HttpClient();
            client.BaseAddress = new System.Uri(URL);
            byte[] cred = UTF8Encoding.UTF8.GetBytes("username:password");
            client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", Convert.ToBase64String(cred));
            client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));

            System.Net.Http.HttpContent content = new StringContent(DATA, UTF8Encoding.UTF8, "application/json");
            HttpResponseMessage messge = client.PostAsync(URL, content).Result;
            string description = string.Empty;
            if (messge.IsSuccessStatusCode)
            {
                string result = messge.Content.ReadAsStringAsync().Result;
                description = result;
            }
        }
    }
}
Srinivasan Radhakrishnan
fonte
-1: .net é uma plataforma gerenciada, mas o HttpClient não é gerenciado (o que significa que você DEVE usar para saber quando ele pode descartar os ponteiros não gerenciados). Sem ele, seu código não será dimensionado para alguns usuários (e, sim, isso é importante, tão importante que o idioma possui uma palavra-chave específica para lidar com ele).
JKödel 20/10
5
@ JCKödel - Você não está absolutamente certo aqui e deve ler este stackoverflow.com/a/22561368 - HttpClient foi projetado para ser re-utilizado para várias chamadas
hB0
1
Sim @ JCKödel leia este artigo stackoverflow.com/questions/15705092/...
Nathan
11

Gostaria de compartilhar minha solução no ASP.NET Core

using Newtonsoft.Json;
using System;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Configuration;

namespace WebApp
{
    public static class HttpHelper
    {
        // In my case this is https://localhost:44366/
        private static readonly string apiBasicUri = ConfigurationManager.AppSettings["apiBasicUri"];

        public static async Task Post<T>(string url, T contentValue)
        {
            using (var client = new HttpClient())
            {
                client.BaseAddress = new Uri(apiBasicUri);
                var content = new StringContent(JsonConvert.SerializeObject(contentValue), Encoding.UTF8, "application/json");
                var result = await client.PostAsync(url, content);
                result.EnsureSuccessStatusCode();
            }
        }

        public static async Task Put<T>(string url, T stringValue)
        {
            using (var client = new HttpClient())
            {
                client.BaseAddress = new Uri(apiBasicUri);
                var content = new StringContent(JsonConvert.SerializeObject(stringValue), Encoding.UTF8, "application/json");
                var result = await client.PutAsync(url, content);
                result.EnsureSuccessStatusCode();
            }
        }

        public static async Task<T> Get<T>(string url)
        {
            using (var client = new HttpClient())
            {
                client.BaseAddress = new Uri(apiBasicUri);
                var result = await client.GetAsync(url);
                result.EnsureSuccessStatusCode();
                string resultContentString = await result.Content.ReadAsStringAsync();
                T resultContent = JsonConvert.DeserializeObject<T>(resultContentString);
                return resultContent;
            }
        }

        public static async Task Delete(string url)
        {
            using (var client = new HttpClient())
            {
                client.BaseAddress = new Uri(apiBasicUri);
                var result = await client.DeleteAsync(url);
                result.EnsureSuccessStatusCode();
            }
        }
    }
}

Para postar use algo como isto:

await HttpHelper.Post<Setting>($"/api/values/{id}", setting);

Exemplo para excluir:

await HttpHelper.Delete($"/api/values/{id}");

Exemplo para obter a lista:

List<ClaimTerm> claimTerms = await HttpHelper.Get<List<ClaimTerm>>("/api/values/");

Exemplo para obter apenas um:

ClaimTerm processedClaimImage = await HttpHelper.Get<ClaimTerm>($"/api/values/{id}");
Raskolnikov
fonte
2
É um código muito bom, embora você não deva usar o httpclient dentro de um bloco de uso. Veja aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong
Myke Black
9

Atualização para chamar uma API REST ao usar o .NET 4.5 ou .NET Core

Gostaria de sugerir DalSoft.RestClient (ressalva que eu criei). O motivo é que, devido à digitação dinâmica, você pode encerrar tudo em uma chamada fluente, incluindo serialização / desserialização. Abaixo está um exemplo de PUT em funcionamento:

dynamic client = new RestClient("http://jsonplaceholder.typicode.com");

var post = new Post { title = "foo", body = "bar", userId = 10 };

var result = await client.Posts(1).Put(post);
DalSoft
fonte
5

OBTER:

// GET JSON Response
public WeatherResponseModel GET(string url) {
    WeatherResponseModel model = new WeatherResponseModel();
    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
    try {
        WebResponse response = request.GetResponse();
        using(Stream responseStream = response.GetResponseStream()) {
            StreamReader reader = new StreamReader(responseStream, Encoding.UTF8);
            model = JsonConvert.DeserializeObject < WeatherResponseModel > (reader.ReadToEnd());
        }
    } catch (WebException ex) {
        WebResponse errorResponse = ex.Response;
        using(Stream responseStream = errorResponse.GetResponseStream()) {
            StreamReader reader = new StreamReader(responseStream, Encoding.GetEncoding("utf-8"));
            String errorText = reader.ReadToEnd();
            // log errorText
        }
        throw;
    }

    return model;
}

POSTAR:

// POST a JSON string
void POST(string url, string jsonContent) {
    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
    request.Method = "POST";

    System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();
    Byte[]byteArray = encoding.GetBytes(jsonContent);

    request.ContentLength = byteArray.Length;
    request.ContentType =  @ "application/json";

    using(Stream dataStream = request.GetRequestStream()) {
        dataStream.Write(byteArray, 0, byteArray.Length);
    }
    long length = 0;
    try {
        using(HttpWebResponse response = (HttpWebResponse)request.GetResponse()) {
            // got response
            length = response.ContentLength;
        }
    } catch (WebException ex) {
        WebResponse errorResponse = ex.Response;
        using(Stream responseStream = errorResponse.GetResponseStream()) {
            StreamReader reader = new StreamReader(responseStream, Encoding.GetEncoding("utf-8"));
            String errorText = reader.ReadToEnd();
            // log errorText
        }
        throw;
    }
}

Nota: Para serializar e dessirializar o JSON, usei o pacote Newtonsoft.Json NuGet.

JerryGoyal
fonte
4

Confira Remontar para fazer chamadas para descansar serviços de .net. Achei muito fácil de usar: https://github.com/paulcbetts/refit

Remontar: A biblioteca REST automática de segurança de tipo para .NET Core, Xamarin e .NET

O Refit é uma biblioteca fortemente inspirada na biblioteca Retrofit da Square e transforma sua API REST em uma interface ao vivo:

public interface IGitHubApi {
        [Get("/users/{user}")]
        Task<User> GetUser(string user); } The RestService class generates an implementation of IGitHubApi that uses HttpClient to make its calls:

var gitHubApi = RestService.For<IGitHubApi>("https://api.github.com");

var octocat = await gitHubApi.GetUser("octocat");
patrickbadley
fonte
Você sabe se o Refit usa reflexão para conseguir isso? Não consigo encontrar as informações em lugar algum.
Tfrascaroli 25/04/19
desculpe @tfrascaroli Eu não tenho certeza de imediato.
patrickbadley
2

Este é um código de exemplo que funciona com certeza. Levei um dia para fazer isso para ler um conjunto de objetos do serviço Rest:

RootObject é o tipo de objeto que estou lendo no serviço restante.

string url = @"http://restcountries.eu/rest/v1";
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(IEnumerable<RootObject>));
WebClient syncClient = new WebClient();
string content = syncClient.DownloadString(url);

using (MemoryStream memo = new MemoryStream(Encoding.Unicode.GetBytes(content)))
{
    IEnumerable<RootObject> countries = (IEnumerable<RootObject>)serializer.ReadObject(memo);    
}

Console.Read();
user4064093
fonte
1
    var TakingRequset = WebRequest.Create("http://xxx.acv.com/MethodName/Get");
    TakingRequset.Method = "POST";
    TakingRequset.ContentType = "text/xml;charset=utf-8";
    TakingRequset.PreAuthenticate = true;

    //---Serving Request path query
     var PAQ = TakingRequset.RequestUri.PathAndQuery;

    //---creating your xml as per the host reqirement
    string xmlroot=@"<root><childnodes>passing parameters</childnodes></root>";
    string xmlroot2=@"<root><childnodes>passing parameters</childnodes></root>";

    //---Adding Headers as requested by host 
    xmlroot2 = (xmlroot2 + "XXX---");
    //---Adding Headers Value as requested by host 
  //  var RequestheaderVales = Method(xmlroot2);

    WebProxy proxy = new WebProxy("XXXXX-----llll", 8080);
    proxy.Credentials = new NetworkCredential("XXX---uuuu", "XXX----", "XXXX----");
    System.Net.WebRequest.DefaultWebProxy = proxy;


    // Adding The Request into Headers
    TakingRequset.Headers.Add("xxx", "Any Request Variable ");
    TakingRequset.Headers.Add("xxx", "Any Request Variable");

    byte[] byteData = Encoding.UTF8.GetBytes(xmlroot);
    TakingRequset.ContentLength = byteData.Length;

    using (Stream postStream = TakingRequset.GetRequestStream())
    {
        postStream.Write(byteData, 0, byteData.Length);
        postStream.Close();
    }



    StreamReader stredr = new StreamReader(TakingRequset.GetResponse().GetResponseStream());
    string response = stredr.ReadToEnd();
rajendra lenka
fonte
1

Eu fiz isso dessa maneira simples, com a web Api 2.0. Você pode remover UseDefaultCredentials.I usado para meus próprios casos de uso.

            List<YourObject> listObjects = new List<YourObject>();


            string response = "";
            using (var client = new WebClient() { UseDefaultCredentials = true })
            {
                 response = client.DownloadString(apiUrl);
            }

            listObjects = JsonConvert.DeserializeObject<List<YourObject>>(response);
            return listObjects ;
MNF
fonte
0

A resposta marcada aqui sugere usar o HttpClient diretamente e descartá-lo. Isso pode funcionar, mas é muito fácil encontrar problemas com o HttpClient se você não usá-lo corretamente. Se você usar o HttpClient, é melhor entregar a criação / descarte do HttpClients a uma biblioteca de terceiros que usa padrão de fábrica. RestClient.Net é uma dessas bibliotecas.

Ele vem com uma fábrica HttpClient muito básica, para que você não encontre o problema de exaustão do soquete,

public class DefaultHttpClientFactory : IHttpClientFactory, IDisposable
{
    #region Fields
    private bool disposed;
    private readonly ConcurrentDictionary<string, Lazy<HttpClient>> _httpClients;
    private readonly Func<string, Lazy<HttpClient>> _createClientFunc;
    #endregion

    #region Constructor
    public DefaultHttpClientFactory() : this(null)
    {
    }

    public DefaultHttpClientFactory(Func<string, Lazy<HttpClient>> createClientFunc)
    {
        _createClientFunc = createClientFunc;
        _httpClients = new ConcurrentDictionary<string, Lazy<HttpClient>>();

        if (_createClientFunc != null) return;
        _createClientFunc = name =>
        {
            return new Lazy<HttpClient>(() => new HttpClient(), LazyThreadSafetyMode.ExecutionAndPublication);
        };
    }
    #endregion

    #region Implementation
    public HttpClient CreateClient(string name)
    {
        if (name == null)
        {
            throw new ArgumentNullException(nameof(name));
        }

        return _httpClients.GetOrAdd(name, _createClientFunc).Value;
    }

    public void Dispose()
    {
        if (disposed) return;
        disposed = true;

        foreach (var name in _httpClients.Keys)
        {
            _httpClients[name].Value.Dispose();
        }
    }
    #endregion
}

Mas a implementação IHttpClientFactory da Microsoft também pode ser usada para os melhores e mais recentes:

    var serviceCollection = new ServiceCollection();
    var baseUri = new Uri("http://www.test.com");
    serviceCollection.AddSingleton(typeof(ISerializationAdapter), typeof(NewtonsoftSerializationAdapter));
    serviceCollection.AddSingleton(typeof(ILogger), typeof(ConsoleLogger));
    serviceCollection.AddSingleton(typeof(IClient), typeof(Client));
    serviceCollection.AddDependencyInjectionMapping();
    serviceCollection.AddTransient<TestHandler>();

    //Make sure the HttpClient is named the same as the Rest Client
    serviceCollection.AddSingleton<IClient>(x => new Client(name: clientName, httpClientFactory: x.GetRequiredService<IHttpClientFactory>()));
    serviceCollection.AddHttpClient(clientName, (c) => { c.BaseAddress = baseUri; })
        .AddHttpMessageHandler<TestHandler>();

    var serviceProvider = serviceCollection.BuildServiceProvider();
    var client = serviceProvider.GetService<IClient>();
    await client.GetAsync<object>();

O RestClient.Net leva em consideração a injeção de dependência, a zombaria, os contêineres de IoC, a testabilidade da unidade e, acima de tudo, é rápido. Eu procurei e o único outro cliente que parece funcionar em uma capacidade semelhante é o Flurl.Http

Melbourne Developer
fonte
-2

O primeiro passo é criar a classe auxiliar para o cliente http.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;

namespace callApi.Helpers
{
    public class CallApi
    {
        private readonly Uri BaseUrlUri;
        private HttpClient client = new HttpClient();

        public CallApi(string baseUrl)
        {
            BaseUrlUri = new Uri(baseUrl);
            client.BaseAddress = BaseUrlUri;
            client.DefaultRequestHeaders.Accept.Clear();
            client.DefaultRequestHeaders.Accept.Add(
                new MediaTypeWithQualityHeaderValue("application/json"));

        }

        public HttpClient getClient()
        {
            return client;
        }

        public HttpClient getClientWithBearer(string token)
        {
            client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
            return client;
        }

    }
}

Então você pode usar esta classe no seu código.

este é um exemplo de como você chama a API restante sem portador usando a classe acima.

// GET api/values
[HttpGet]
public async Task<ActionResult<string>> postNoBearerAsync(string email, string password,string baseUrl, string action)
{
    var request = new LoginRequest
    {
        email = email,
        password = password
    };

    var callApi = new CallApi(baseUrl);
    var client = callApi.getClient();
    HttpResponseMessage response = await client.PostAsJsonAsync(action, request);
    if (response.IsSuccessStatusCode)
        return Ok(await response.Content.ReadAsAsync<string>());
    else
        return NotFound();
}

este é um exemplo de como você pode chamar a API restante que requer portadora.

// GET api/values
[HttpGet]
public async Task<ActionResult<string>> getUseBearerAsync(string token, string baseUrl, string action)
{
    var callApi = new CallApi(baseUrl);
    var client = callApi.getClient();
    client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
    HttpResponseMessage response = await client.GetAsync(action);
    if (response.IsSuccessStatusCode)
    {
        return Ok(await response.Content.ReadAsStringAsync());

    }
    else
        return NotFound();
}

você também pode consultar o repositório abaixo se quiser ver o exemplo de funcionamento de como ele funciona.

https://github.com/mokh223/callApi

mokh223
fonte