410 votes

Comment faire des appels à une API REST en utilisant C# ?

Voici le code que j'ai jusqu'à présent :

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

        }
    }

Le problème est que je pense que le bloc d'exception est déclenché (car lorsque je supprime le try-catch, j'obtiens un message d'erreur serveur (500). Mais je ne vois pas les lignes Console.Out que j'ai mises dans le bloc catch.

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

0 votes

De plus, avez-vous mis des points d'arrêt pour voir où, exactement, ça explose ?

0 votes

C'est le résultat de la fenêtre de sortie mais pas de la console

5 votes

MSDN a publié un excellent article sur la création de services RESTful : msdn.microsoft.com/library/dd203052.aspx ... et des clients RESTful : msdn.microsoft.com/en-us/magazine/ee309509.aspx

501voto

Brian Swift Points 561

L'API Web ASP.NET a remplacé le WCF API Web mentionnée précédemment.

J'ai pensé poster une réponse mise à jour puisque la plupart de ces réponses datent de début 2012, et que ce fil de discussion est l'un des premiers résultats lorsqu'on fait une recherche Google sur "call restful service C#".

Selon les directives actuelles de Microsoft, il faut utiliser les bibliothèques client de l'API Web de Microsoft ASP.NET pour consommer un fichier de type RESTful service. Ce service est disponible en tant que NuGet paquet, Microsoft.AspNet.WebApi.Client. Vous devrez ajouter ce paquet NuGet à votre solution.

Voici à quoi ressemblerait votre exemple s'il était mis en œuvre à l'aide de la bibliothèque client 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();
        }
    }
}

Si vous prévoyez de faire plusieurs requêtes, vous devriez réutiliser votre instance de HttpClient. Consultez cette question et ses réponses pour plus de détails sur la raison pour laquelle une instruction using n'a pas été utilisée sur l'instance HttpClient dans ce cas : HttpClient et HttpClientHandler doivent-ils être éliminés entre les requêtes ?

Pour plus de détails, y compris d'autres exemples, voir Appeler une API Web à partir d'un client .NET (C#)

Cet article de blog peut également vous être utile : Utilisation de HttpClient pour consommer les services REST de l'API Web ASP.NET

10 votes

Merci ! J'ai dû installer le paquet NuGet du client WebApi pour que cela fonctionne pour moi : Installer-Package Microsoft.AspNet.WebApi.Client

3 votes

Si vous devez simuler votre intégration REST, même avec les bibliothèques clientes, ce n'est pas facile. Essayez RestSharp ?

7 votes

Pour rendre cette réponse encore meilleure qu'elle ne l'est déjà, vous devriez envelopper la déclaration HttpClient dans une déclaration using pour mieux gérer votre ressource :)

138voto

Justin Pihony Points 21088

Ma suggestion serait d'utiliser RestSharp . Vous pouvez faire des appels à des services REST et les faire passer dans des fichiers POCO avec très peu de code passe-partout pour l'analyse de la réponse. Cela ne résoudra pas votre erreur particulière, mais répond à votre question générale sur la façon d'appeler les services REST. Le fait d'avoir à modifier votre code pour l'utiliser devrait se traduire par une facilité d'utilisation et une robustesse accrues. Ce n'est que mon avis.

Exemple :

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 votes

RestSharp et JSON.NET sont définitivement la voie à suivre. J'ai trouvé que les outils de MS étaient insuffisants et risquaient d'échouer.

2 votes

Un autre vote pour RestSharp parce que vous pouvez le simuler pour le tester beaucoup, beaucoup plus facilement que les bibliothèques WebApi Client.

1 votes

Pour les utilisateurs de mono - RestSharp semble utiliser l'apis System.Net WebRequest - qui, d'après mon expérience, n'est pas aussi fiable que les implémentations .net. ('random' hangs)

46voto

Jesse C. Slicer Points 11750

Sans rapport, je suis sûr, mais emballez votre IDisposable objets dans using pour assurer une élimination appropriée :

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

6 votes

Une réponse agréable qui n'utilise pas de paquetage supplémentaire en dehors de l'environnement .NET normal.

0 votes

@Jesse C. Slicer..pourquoi j'obtiens une erreur 404 dans WebResponse webResponse = request.GetResponse() ;

3 votes

Parce que la ressource n'a pas été trouvée ? Il y a beaucoup, beaucoup de raisons d'obtenir un 404.

20voto

Veuillez utiliser le code ci-dessous pour votre demande d'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 votes

-1 : .net est une plateforme gérée, mais HttpClient n'est pas géré (ce qui signifie que vous DEVEZ utiliser using pour lui indiquer quand il peut disposer de ces pointeurs non gérés). Sans cela, votre code ne pourra pas s'adapter à quelques utilisateurs (et, oui, c'est important, tellement important que le langage a un mot-clé spécifique pour le gérer).

5 votes

@JCKödel - Vous n'avez pas tout à fait raison ici et vous devriez lire ceci. stackoverflow.com/a/22561368 - HttpClient a été conçu pour être réutilisé pour de multiples appels.

1 votes

Oui @JCKödel, lisez cet article. stackoverflow.com/questions/15705092/

0voto

dice Points 1986

Comme vous utilisez Visual Studio 11 Beta, vous voudrez utiliser la dernière et la meilleure version. La nouvelle API Web contient des classes pour cela.

Voir HttpClient : http://wcf.codeplex.com/wikipage?title=WCF%20HTTP

0 votes

Le lien est (effectivement) rompu. Il redirige vers https://archive.codeplex.com/?p=wcf .

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X