¿Cómo hago llamadas a una API REST usando C #?

335

Este es el código que tengo hasta ahora:

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

        }
    }
}

El problema es que creo que se está activando el bloque de excepción (porque cuando elimino el try-catch, recibo un mensaje de error del servidor (500). Pero no veo la consola. Fuera de las líneas que puse en el bloque catch.

Mi consola:

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).

Estoy usando Visual Studio 2011 Beta y .NET 4.5 Beta.

NullVoxPopuli
fuente
Además, ¿ha puesto puntos de quiebre allí para ver exactamente dónde está explotando?
NotMe
este es el resultado de la ventana de salida pero no de la consola
Serj-Tm
55
MSDN tenía un excelente artículo sobre la creación de servicios RESTful: msdn.microsoft.com/library/dd203052.aspx ... y clientes RESTful: msdn.microsoft.com/en-us/magazine/ee309509.aspx
Lynn Crumbling
@ChrisLively, ¿qué tiene esto que ver con IE? = \ Está explotando en la solicitud. Obtener línea de respuesta.
NullVoxPopuli
@TheLindyHop; Absolutamente nada. No lo leí bien.
NotMe

Respuestas:

427

La API web ASP.Net ha reemplazado a la API web WCF mencionada anteriormente.

Pensé en publicar una respuesta actualizada, ya que la mayoría de estas respuestas son de principios de 2012, y este hilo es uno de los mejores resultados al hacer una búsqueda en Google para "llamar al servicio reparador c #".

La guía actual de Microsoft es utilizar las bibliotecas de cliente de API web de Microsoft ASP.NET para consumir un servicio RESTful. Está disponible como un paquete NuGet, Microsoft.AspNet.WebApi.Client. Deberá agregar este paquete NuGet a su solución.

Así es como se vería su ejemplo cuando se implementa usando la biblioteca de cliente ASP.Net Web API:

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

Si planea hacer varias solicitudes, debe volver a usar su instancia de HttpClient. Consulte esta pregunta y sus respuestas para obtener más detalles sobre por qué no se usó una instrucción de uso en la instancia de HttpClient en este caso: ¿Deben eliminarse HttpClient y HttpClientHandler?

Para obtener más detalles, incluidos otros ejemplos, vaya aquí: http://www.asp.net/web-api/overview/web-api-clients/calling-a-web-api-from-a-net-client

Esta publicación de blog también puede ser útil: http://johnnycode.com/2012/02/23/consuming-your-own-asp-net-web-api-rest-service/

Brian Swift
fuente
66
¡Gracias! Necesitaba instalar el paquete NuGet del cliente WebApi para que esto funcionara para mí: Install-Package Microsoft.AspNet.WebApi.Client
Ev.
3
Si necesita burlarse de su integración REST, incluso con las bibliotecas del cliente, aún no es fácil. Prueba RestSharp?
Rob Church el
66
Para que esta respuesta sea aún mejor de lo que ya es, debe envolver la declaración HttpClient en una declaración de uso para administrar mejor su recurso :)
Daniel Siebert
77
Intenté usar pero no puedo usar ReadAsAsync (), obteniendo el error "HttpContent no contiene una definición para 'ReadAsAsync' y ningún método de extensión.
Robert Green MBA
77
@RobertGreenMBA: para obtener el método de extensión ReadAsAsync(), agregue una referencia a System.Net.Http.Formatting.dll. (Intuitivo, ¿verdad?)
Arin
122

Mi sugerencia sería usar RestSharp . Puede realizar llamadas a los servicios REST y hacer que se conviertan en objetos POCO con muy poco código repetitivo para tener que analizar la respuesta. Esto no resolverá su error particular, pero responde a su pregunta general sobre cómo hacer llamadas a los servicios REST. Tener que cambiar su código para usarlo debería ser rentable en la facilidad de uso y la solidez en el futuro. Eso es solo mis 2 centavos

Ejemplo:

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
fuente
66
RestSharp y JSON.NET es definitivamente el camino a seguir. Encontré que el conjunto de herramientas de MS falta y es probable que falle.
cbuteau
2
Otro voto para RestSharp porque puede simularlo para probar mucho, mucho más fácilmente que las bibliotecas de WebApi Client.
Rob Church el
1
para usuarios mono: RestSharp parece estar utilizando las API de System.Net WebRequest, que, en mi experiencia, no es tan confiable como las implementaciones .net. (se cuelga "al azar")
Tom
3
Sería bueno tener un ejemplo en esta respuesta, por favor.
Caltor
2
La falta de un ejemplo hace que esta publicación no sea útil.
smac2020
39

Sin relación, estoy seguro, pero envuelva sus IDisposableobjetos en usingbloques para garantizar la eliminación adecuada:

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
fuente
44
Buena respuesta que no utiliza ningún paquete adicional fuera del entorno regular .NET.
palswim
@Jesse C. Slicer..por qué recibí el error 404 en WebResponse webResponse = request.GetResponse ();
Goh Han
2
¿Porque no se encontró el recurso? Hay muchas, MUCHAS razones para obtener un 404.
Jesse C. Slicer
1
Esta es una gran solución @ JesseC.Slicer. Puedo aplicar este código para extraer un token y verlo desde la consola. ¿Tiene algún consejo para que yo tome este token y lo use para autenticación / inicio de sesión? Quiero usar GET para obtener algunos datos, pero solo podría hacerlo si estoy conectado. ¿Dónde puedo obtener más información al respecto? ¡Gracias!
Paul Laguna
18

Aquí hay algunas formas diferentes de llamar a una API externa en C # (actualizado 2019).

Formas integradas de .NET:

  • WebRequest y WebClient : las API detalladas y la documentación de Microsoft no son muy fáciles de seguir
  • HttpClient : el chico más nuevo de .NET en el bloque y mucho más fácil de usar que el anterior.

Paquetes NuGet gratuitos de código abierto , que francamente tienen una experiencia de desarrollador mucho mejor que los clientes integrados de .NET:

  • ServiceStack.Text (1k estrellas github, 7m descargas Nuget) (*): rápido, ligero y resistente.
  • RestSharp (6k estrellas github, 23m descargas Nuget) (*) - cliente REST simple y API HTTP
  • Flurl (1.7k estrellas github, 3m descargas Nuget) (*) - una biblioteca de cliente HTTP fluible, portátil y comprobable

Todos los paquetes anteriores proporcionan una excelente experiencia de desarrollador (es decir, API conciso y fácil) y están bien mantenidos.

(*) a agosto de 2019

Ejemplo: Obtener un elemento de Todo de una API de Fake Rest usando ServiceStack.Text. Las otras bibliotecas tienen una sintaxis muy similar.

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

}

Ejecutar el ejemplo anterior en una aplicación .NET Core Console produce el siguiente resultado.

ingrese la descripción de la imagen aquí

Instale estos paquetes usando NuGet

Install-Package ServiceStack.Text, or

Install-Package RestSharp, or

Install-Package Flurl.Http
Programando con Mark
fuente
17

Utilice el siguiente código para su solicitud 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
fuente
-1: .net es una plataforma administrada, pero HttpClient no está administrado (lo que significa que DEBE usarlo para indicar cuándo puede eliminar esos punteros no administrados). Sin él, su código no se escalará a un par de usuarios (y, sí, esto ES importante, tan importante que el idioma tiene una palabra clave específica para tratarlo).
JCKödel
55
@ JCKödel: no tiene toda la razón aquí y debería leer este stackoverflow.com/a/22561368 : HttpClient ha sido diseñado para ser reutilizado para múltiples llamadas
hB0
1
Sí @ JCKödel, lea este artículo stackoverflow.com/questions/15705092/…
Nathan
11

Me gustaría compartir mi solución en 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 publicar usa algo como esto:

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

Ejemplo para borrar:

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

Ejemplo para obtener la lista:

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

Ejemplo para obtener solo uno:

ClaimTerm processedClaimImage = await HttpHelper.Get<ClaimTerm>($"/api/values/{id}");
Raskolnikov
fuente
2
Es un código realmente agradable, aunque no deberías usar httpclient dentro de un bloque de uso. ver aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong
Myke Black
9

Actualización para llamar a una API REST cuando se utiliza .NET 4.5 o .NET Core

Sugeriría DalSoft.RestClient (advertencia que lo creé). La razón es que, debido a que utiliza la tipificación dinámica, puede resumir todo en una llamada fluida, incluida la serialización / deserialización. A continuación se muestra un ejemplo de trabajo PUT:

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
fuente
5

OBTENER:

// 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;
}

ENVIAR:

// 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 y desirialze JSON utilicé el paquete Newtonsoft.Json NuGet.

JerryGoyal
fuente
4

Echa un vistazo a Refit para hacer llamadas a servicios de descanso desde .net. Lo encontré muy fácil de usar: https://github.com/paulcbetts/refit

Reajustar: la biblioteca REST automática de tipos seguros para .NET Core, Xamarin y .NET

Refit es una biblioteca fuertemente inspirada en la biblioteca Retrofit de Square, y convierte su API REST en una interfaz en 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
fuente
¿Sabes si Refit usa la reflexión para lograr esto? No puedo encontrar la información en ningún lado.
tfrascaroli
lo siento @tfrascaroli, no estoy seguro de la mano.
patrickbadley
2

Este es un código de ejemplo que funciona con seguridad. Me llevó un día hacer esto para leer un conjunto de objetos del servicio Rest:

RootObject es el tipo de objeto que estoy leyendo del servicio de descanso.

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();
usuario4064093
fuente
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
fuente
1

Lo hice de esta manera simple, con la web Api 2.0. Puede eliminar UseDefaultCredentials. Lo utilicé para mis propios 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
fuente
0

La respuesta marcada aquí sugiere usar HttpClient directamente y deshacerse de él. Esto podría funcionar, pero es bastante fácil encontrarse con problemas con HttpClient si no lo usa correctamente. Si va a usar HttpClient, es mejor que entregue la creación / eliminación de HttpClients a una biblioteca de terceros que use un patrón de fábrica. RestClient.Net es una de esas bibliotecas.

Viene con una fábrica de HttpClient muy básica para que no se encuentre con el problema de agotamiento del socket,

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
}

Pero la implementación IHttpClientFactory de Microsoft también se puede usar para lo último y lo mejor:

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

RestClient.Net tiene en cuenta la inyección de dependencia, la burla, los contenedores IoC, la capacidad de prueba de la unidad y, sobre todo, es rápido. He buscado y el único otro cliente que parece funcionar en una capacidad similar es Flurl.

Melbourne Developer
fuente
-2

El primer paso es crear la clase auxiliar para el 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;
        }

    }
}

Entonces puedes usar esta clase en tu código.

Este es un ejemplo de cómo llamar a la API de descanso sin portador utilizando la clase anterior.

// 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 es un ejemplo de cómo puede llamar a la API de resto que requiere portador.

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

También puede consultar el siguiente repositorio si desea ver el ejemplo de funcionamiento de cómo funciona.

https://github.com/mokh223/callApi

mokh223
fuente