Come posso effettuare chiamate a un API REST usando C #?


335

Questo è il codice che ho finora:

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

        }
    }
}

Il problema è che penso che il blocco delle eccezioni venga attivato (perché quando rimuovo il try-catch, ricevo un messaggio di errore del server (500). Ma non vedo la console. Linee esterne che inserisco nel blocco catch.

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

Sto usando Visual Studio 2011 Beta e .NET 4.5 Beta.


Inoltre, hai inserito dei punti di interruzione per vedere dove, esattamente, sta esplodendo?
NotMe

questo è il risultato della finestra di output ma non della console
Serj-Tm

5
MSDN ha pubblicato un eccellente articolo sulla creazione di servizi RESTful: msdn.microsoft.com/library/dd203052.aspx ... e client RESTful: msdn.microsoft.com/en-us/magazine/ee309509.aspx
Lynn Crumbling

@ChrisLively cosa c'entra questo con IE? = \ Si sta espandendo sulla riga request.GetResponse.
NullVoxPopuli

@TheLindyHop; Assolutamente niente. Ho letto male.
NotMe

Risposte:


427

L'API Web ASP.Net ha sostituito l'API Web WCF menzionata in precedenza.

Ho pensato di pubblicare una risposta aggiornata poiché la maggior parte di queste risposte è dell'inizio del 2012 e questa discussione è uno dei migliori risultati quando si esegue una ricerca su Google per "chiamare servizio riposante c #".

La guida corrente di Microsoft è di utilizzare le librerie client dell'API Web ASP.NET Microsoft per utilizzare un servizio RESTful. Questo è disponibile come pacchetto NuGet, Microsoft.AspNet.WebApi.Client. Dovrai aggiungere questo pacchetto NuGet alla tua soluzione.

Ecco come apparirebbe il tuo esempio se implementato utilizzando la libreria client dell'API Web 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 si prevede di effettuare più richieste, è necessario riutilizzare l'istanza di HttpClient. Vedi questa domanda e le sue risposte per maggiori dettagli sul perché in questo caso non è stata utilizzata un'istruzione using sull'istanza HttpClient: HttpClient e HttpClientHandler devono essere eliminati?

Per maggiori dettagli, inclusi altri esempi, vai qui: http://www.asp.net/web-api/overview/web-api-clients/calling-a-web-api-from-a-net-client

Questo post del blog può anche essere utile: http://johnnycode.com/2012/02/23/consuming-your-own-asp-net-web-api-rest-service/


6
Grazie! Avevo bisogno di installare il pacchetto NuGet del client WebApi perché questo funzionasse per me: Install-Package Microsoft.AspNet.WebApi.Client
Ev.

3
Se hai bisogno di deridere l'integrazione REST, anche con le librerie client non è ancora facile. Prova RestSharp?
Rob Church

6
Per rendere questa risposta ancora migliore di quanto non sia già, dovresti racchiudere la dichiarazione HttpClient in un'istruzione using per gestire meglio la tua risorsa :)
Daniel Siebert

7
Ho provato a usare ma non sono riuscito a usare ReadAsAsync (), ottenendo l'errore "HttpContent non contiene una definizione per" ReadAsAsync "e nessun metodo di estensione.
Robert Green MBA

7
@RobertGreenMBA: per ottenere il metodo di estensione ReadAsAsync(), aggiungere un riferimento a System.Net.Http.Formatting.dll. (Intuitivo, vero?)
Arin,

122

Il mio consiglio sarebbe di usare RestSharp . È possibile effettuare chiamate ai servizi REST e farle eseguire il cast in oggetti POCO con pochissimo codice boilerplate per analizzare effettivamente la risposta. Questo non risolverà il tuo particolare errore, ma risponderà alla tua domanda generale su come effettuare chiamate ai servizi REST. Dover cambiare il codice per usarlo dovrebbe essere ripagato dalla facilità d'uso e dalla robustezza che vanno avanti. Questo è solo il mio 2 centesimi però

Esempio:

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

6
RestSharp e JSON.NET sono sicuramente la strada da percorrere. Ho scoperto che il set di strumenti MS è carente e probabilmente non riesce.
cbuteau,

2
Un altro voto per RestSharp perché puoi deriderlo per testare molto, molto più facilmente rispetto alle librerie del client WebApi.
Rob Church,

1
per gli utenti mono - RestSharp sembra utilizzare le API di System.Net WebRequest - che, secondo la mia esperienza, non è affidabile come le implementazioni .net. (blocchi "casuali")
Tom,

3
Sarebbe bello avere un esempio in questa risposta, per favore.
Caltor,

2
La mancanza di un esempio rende questo post non utile!
smac2020,

39

Non sono correlato, ne sono certo, ma avvolgi i tuoi IDisposableoggetti in usingblocchi per garantire uno smaltimento corretto:

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

        }
    }
}

4
Bella risposta che non utilizza alcun pacchetto aggiuntivo al di fuori del normale ambiente .NET.
Palswim,

@Jesse C. Slicer..perché ho riscontrato l'errore 404 in WebResponse webResponse = request.GetResponse ();
Goh Han

2
Perché la risorsa non è stata trovata? Ci sono molte, MOLTE ragioni per ottenere un 404.
Jesse C. Slicer

1
Questa è un'ottima soluzione @ JesseC.Slicer. Sono in grado di applicare questo codice per estrarre un token e vederlo dalla console. Hai qualche suggerimento per consentirmi di utilizzare questo token per l'autenticazione / il login? Voglio usare GET per estrarre alcuni dati, ma potrei farlo solo se ho effettuato l'accesso. Dove posso saperne di più su questo? Grazie!
Paul Laguna,

18

Ecco alcuni modi diversi di chiamare un'API esterna in C # (aggiornato 2019).

I modi integrati di .NET:

  • WebRequest & WebClient : API dettagliate e documentazione di Microsoft non sono molto facili da seguire
  • HttpClient : il figlio più recente di .NET sul blocco e molto più semplice da usare di quanto sopra.

Pacchetti NuGet gratuiti e open source , che francamente hanno un'esperienza di sviluppo molto migliore rispetto ai client integrati di .NET:

  • ServiceStack.Text (1k github stars, 7m Nuget download) (*) - veloce, leggero e resistente.
  • RestSharp (6k github stars, 23m Nuget Downloads) (*) - semplice client API REST e HTTP
  • Flurl (1,7k github stars, 3m Nuget Downloads) (*) - una libreria client HTTP fluida, portatile e testabile

Tutti i pacchetti di cui sopra offrono un'ottima esperienza di sviluppo (ovvero concisa, facile API) e sono ben mantenuti.

(*) ad agosto 2019

Esempio: ottenere un elemento Todo da un'API Fake Rest utilizzando ServiceStack.Text. Le altre librerie hanno una sintassi molto simile.

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

}

L'esecuzione dell'esempio sopra riportato in un'app .NET Core Console produce il seguente output.

inserisci qui la descrizione dell'immagine

Installa questi pacchetti usando NuGet

Install-Package ServiceStack.Text, or

Install-Package RestSharp, or

Install-Package Flurl.Http

17

Utilizzare il codice seguente per la richiesta 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;
            }
        }
    }
}

-1: .net è una piattaforma gestita, ma HttpClient non è gestito (il che significa che DEVI usare per dirlo quando può eliminare quei puntatori non gestiti). Senza di esso, il tuo codice non si ridimensionerà a un paio di utenti (e, sì, questo È importante, così importante che la lingua ha una parola chiave specifica per gestirlo).
JCKödel,

5
@ JCKödel - Tu non sei assolutamente ragione qui e dovrebbe leggere questo stackoverflow.com/a/22561368 - HttpClient è stato progettato per essere riutilizzato per più chiamate
HB0

1
Sì @ JCKödel, leggi questo articolo stackoverflow.com/questions/15705092/…
Nathan,

11

Vorrei condividere la mia soluzione in 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();
            }
        }
    }
}

Per pubblicare utilizzare qualcosa del genere:

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

Esempio per l'eliminazione:

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

Esempio per ottenere l'elenco:

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

Esempio per ottenerne solo uno:

ClaimTerm processedClaimImage = await HttpHelper.Get<ClaimTerm>($"/api/values/{id}");

2
È un bel po 'di codice, anche se non dovresti usare httpclient all'interno di un blocco using. vedi aspnetmonsters.com/2016/08/2016 08-27-27
Myke Black

9

Aggiornamento per la chiamata di un'API REST quando si utilizza .NET 4.5 o .NET Core

Vorrei suggerire DalSoft.RestClient (avvertimento l'ho creato). Il motivo è che utilizza la digitazione dinamica è possibile racchiudere tutto in una chiamata fluida, compresa la serializzazione / deserializzazione. Di seguito è riportato un esempio PUT funzionante:

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

5

OTTENERE:

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

INVIARE:

// 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: per serializzare e desirializzare JSON ho usato il pacchetto NuGet Newtonsoft.Json.


4

Dai un'occhiata a Refit per effettuare chiamate per interrompere i servizi da .net. L'ho trovato molto facile da usare: https://github.com/paulcbetts/refit

Refit: la libreria REST automatica di tipo sicuro per .NET Core, Xamarin e .NET

Refit è una libreria fortemente ispirata alla libreria di Retrofit di Square e trasforma la tua API REST in un'interfaccia live:

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

Sai se Refit usa la riflessione per raggiungere questo obiettivo? Non riesco a trovare le informazioni da nessuna parte.
tfrascaroli,

scusa @tfrascaroli non sono sicuro a portata di mano.
patrickbadley,

2

Questo è un codice di esempio che funziona sicuramente. Mi ci è voluto un giorno per farlo leggere un set di oggetti dal servizio Rest:

RootObject è il tipo di oggetto che sto leggendo dal servizio rest.

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

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

1

L'ho fatto in questo modo semplice, con web Api 2.0. È possibile rimuovere UseDefaultCredentials. L'ho usato per i miei casi d'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 ;


0

La risposta contrassegnata qui suggerisce l'utilizzo diretto di HttpClient e la sua eliminazione. Questo potrebbe funzionare, ma è abbastanza facile imbattersi in problemi con HttpClient se non lo si utilizza correttamente. Se hai intenzione di utilizzare HttpClient, è meglio consegnare la creazione / eliminazione di HttpClients a una libreria di terze parti che utilizza il modello di fabbrica. RestClient.Net è una di queste librerie.

Viene fornito con una factory HttpClient di base in modo da non incorrere nel problema di esaurimento 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
}

Ma l'implementazione IHttpClientFactory di Microsoft può essere utilizzata anche per l'ultimo e il più grande:

    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 accetta l'iniezione delle dipendenze, il derisione, i contenitori IoC, la testabilità dell'unità e soprattutto è veloce. Ho cercato e l'unico altro client che sembra funzionare in modo simile è Flurl


-2

il primo passo è creare la classe helper per il client 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;
        }

    }
}

Quindi puoi usare questa classe nel tuo codice.

questo è un esempio di come chiami il resto api senza portatore usando la classe sopra.

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

questo è un esempio di come puoi chiamare le altre API che richiedono portatore.

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

puoi anche fare riferimento al repository di seguito se vuoi vedere l'esempio funzionante di come funziona.

https://github.com/mokh223/callApi

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.