446

This is the code I have so far:

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

        }
    }

The problem is that I think the exception block is being triggered (because when I remove the try-catch, I get a server error (500) message. But I don't see the Console.Out lines I put in the catch block.

My 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).
ΩmegaMan
  • 29,542
  • 12
  • 100
  • 122
NullVoxPopuli
  • 61,906
  • 73
  • 206
  • 352
  • Also, have you put break points in there to see where, exactly, it is blowing up? – NotMe Mar 08 '12 at 15:41
  • this is result from output window but not console – Serj-Tm Mar 08 '12 at 15:41
  • 5
    MSDN had an excellent article on building RESTful services: http://msdn.microsoft.com/library/dd203052.aspx ... and RESTful clients: http://msdn.microsoft.com/en-us/magazine/ee309509.aspx – Lynn Crumbling Mar 08 '12 at 15:43

17 Answers17

534

The ASP.NET Web API has replaced the WCF Web API previously mentioned.

I thought I'd post an updated answer since most of these responses are from early 2012, and this thread is one of the top results when doing a Google search for "call restful service C#".

Current guidance from Microsoft is to use the Microsoft ASP.NET Web API Client Libraries to consume a RESTful service. This is available as a NuGet package, Microsoft.AspNet.WebApi.Client. You will need to add this NuGet package to your solution.

Here's how your example would look when implemented using the ASP.NET Web API Client Library:

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

If you plan on making multiple requests, you should re-use your HttpClient instance. See this question and its answers for more details on why a using statement was not used on the HttpClient instance in this case: Do HttpClient and HttpClientHandler have to be disposed between requests?

For more details, including other examples, see Call a Web API From a .NET Client (C#)

This blog post may also be useful: Using HttpClient to Consume ASP.NET Web API REST Services

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Brian Swift
  • 5,756
  • 2
  • 14
  • 8
  • 12
    Thanks! I needed to install the WebApi client NuGet package for this to work for me: Install-Package Microsoft.AspNet.WebApi.Client – Ev. May 22 '14 at 07:38
  • 3
    If you need to mock out your REST integration, even with the client libraries it's still not easy. Try RestSharp? – Rob Church Jan 07 '16 at 15:55
  • 7
    To make this answer even better than it already is, you should wrap the HttpClient declaration into a using statement to better manage your resource :) – Daniel Siebert Sep 13 '16 at 13:07
  • 1
    You may have to run `Install-Package Microsoft.AspNet.WebApi.Client` to install the Web API Client Libraries. – whiteshooz Sep 25 '16 at 15:31
  • 3
    @DanielSiebert, you may do it, but Microsoft recommends reusing the same instance for multiple calls. See the link to asp.net on the answer. – Tsahi Asher Dec 22 '16 at 08:05
  • 8
    Tried to use but unable to use ReadAsAsync(), getting error "HttpContent does not contain a definition for 'ReadAsAsync' and no extension method. – Robert Green MBA Mar 27 '17 at 10:37
  • This doesn't work for me. When I try it I get "An exception of type 'System.IO.FileNotFoundException' occurred in System.Net.Http.Formatting.dll but was not handled in user code" on the var dataObjects = ... line. – Essej Apr 20 '17 at 06:00
  • 8
    @RobertGreenMBA: To get the extension method `ReadAsAsync()`, add a reference to `System.Net.Http.Formatting.dll`. (Intuitive, right?) – Arin Jun 08 '17 at 19:34
  • 1
    -1: .net is a managed platform, but HttpClient is unmanaged (meaning you MUST use using to tell it when it can dispose those unmanaged pointers). Without it, your code won't scale to a couple of users (and, yes, this IS important, so important that the language have a specific keyword to deal with it). – JCKödel Oct 20 '17 at 15:48
  • 2
    For details regarding disposing of HttpClient, please see the following [Stack Overflow question](https://stackoverflow.com/questions/15705092/do-httpclient-and-httpclienthandler-have-to-be-disposed?utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa) – Brian Swift Apr 02 '18 at 18:29
  • How did this get so many upvotes? I've added the `using` statement because not using that is asking for trouble but the blocking code is also wrong. If you reading this answer, ignore it and read [this answer instead](https://stackoverflow.com/a/9620477/542251). – Liam Jun 29 '18 at 12:27
  • 1
    I added a note to the answer to clarify why a using statement is not used. I also added code comments on how to use HttpClient in the case of multiple requests, a use case which many users searching for this answer will be trying to fulfill. Helpful comments to address the NuGet package and http.formatting.dll reference have been added to the answer as well, in case someone implements without reading the stack overflow comments. – Brian Swift Jul 03 '18 at 18:22
  • 1
    *If you plan on making multiple requests, you should re-use your HttpClient instance* But your not...`HttpClient client = new HttpClient();` Your creating a new instance every time, so this 100% should be being disposed. Otherwise your causing a memory leaks and leaving HTTP channels open. Your edit is wrong. The most correct answer on your linked question is [this one](https://stackoverflow.com/a/44959403/542251). *create one instance and reuse it*, your not doing this so it should be disposed/wrapped in a `using`. – Liam Jul 09 '18 at 12:32
  • 1
    Should "urlParameters" be static ? – N.K Feb 03 '20 at 07:02
  • 1
    And this is how a usefull answer and comments become a Code Review process ;-) – Mauricio Gracia Gutierrez May 12 '21 at 15:39
148

My suggestion would be to use RestSharp. You can make calls to REST services and have them cast into POCO objects with very little boilerplate code to actually have to parse through the response. This will not solve your particular error, but it answers your overall question of how to make calls to REST services. Having to change your code to use it should pay off in the ease of use and robustness moving forward. That is just my two cents though.

Example:

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; }
    }
}
Sydney_dev
  • 1,448
  • 2
  • 17
  • 24
Justin Pihony
  • 66,056
  • 18
  • 147
  • 180
  • 6
    RestSharp and JSON.NET is definitely the way to go. I found the MS toolset to be lacking and likely to fail. – cbuteau Sep 24 '15 at 13:59
  • 2
    Another vote for RestSharp because you can mock it out for testing much, much more easily than the WebApi Client libraries. – Rob Church Jan 07 '16 at 15:54
  • 1
    for mono users - RestSharp seems to be using the System.Net WebRequest apis - which, in my experience isn't as reliable as the .net implementations. ('random' hangs) – Tom Jul 12 '16 at 17:10
  • 3
    It would be nice to have an example in this answer please. – Caltor Jan 26 '17 at 13:35
  • 1
    restsharp's default json deserializer is not as powerful as json.net – user3791372 Feb 08 '17 at 17:09
  • A word of caution about RestSharp. I have found that while it appears to use semantic versioning, it actually does not, and have many times ran into breaking changes (interfaces changed/removed) when updating it from one version to another when the version number indicated the change would only bug fixes. – deadlydog Feb 17 '17 at 17:19
  • @user3791372 You can override the default deserializer: https://github.com/restsharp/RestSharp/wiki/Deserialization – TrueWill Jun 15 '17 at 17:39
  • 2
    A lack of an example makes this post not helpful! – smac2020 Apr 26 '19 at 16:23
  • One thing I found frustrating with RestSharp is its deserializer doesn't support arrays. Works great with `List`s though! – Alexis Leclerc Jun 21 '19 at 19:40
  • Please be aware that at the moment of writing this comment RestSharp team still has the socket exhaustion issue open in bug tracker: https://github.com/restsharp/RestSharp/issues/1322 – Владимiръ Aug 31 '20 at 19:23
51

Unrelated, I'm sure, but do wrap your IDisposable objects in using blocks to ensure proper disposal:

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);
            }
        }
    }
}
Jesse C. Slicer
  • 19,901
  • 3
  • 68
  • 87
  • 7
    Nice answer which doesn't use any extra packages outside of the regular .NET environment. – palswim Jan 02 '18 at 22:10
  • @Jesse C. Slicer..why i hit error 404 in WebResponse webResponse = request.GetResponse(); – Goh Han Jun 07 '19 at 08:41
  • 3
    Because the resource was not found? There are many, MANY reasons to get a 404. – Jesse C. Slicer Jun 07 '19 at 13:53
  • 1
    This is a great solution @JesseC.Slicer. I'm able to apply this code to pull a token and see it from the console. Do you have any tips in order for me to now take this token to use for authentication/login? I want to use GET to pull some data, but only could if I'm logged in. Where could I learn more about this? Thanks! – Paul Laguna Jan 29 '20 at 16:44
  • Using System twice :) – yossico Jan 18 '21 at 20:53
  • Thanks for the answer! If anyone is using token with it, you should add request.Headers.Add("Authorization", "Bearer " + token); after request.Method = "POST"; – dinozaver Apr 19 '23 at 09:26
36

Here are a few different ways of calling an external API in C# (updated 2019).

.NET's built-in ways:

  • WebRequest& WebClient - verbose APIs & Microsoft's documentation is not very easy to follow
  • HttpClient - .NET's newest kid on the block & much simpler to use than above.

Free, open-source NuGet Packages, which frankly have a much better developer experience than .NET's built in clients:

  • ServiceStack.Text (1,000 GitHub stars, 7 million NuGet downloads) (*) - fast, light and resilient.
  • RestSharp (6,000 GitHub stars, 23 million NuGet downloads) (*) - simple REST and HTTP API Client
  • Flurl (1,700 GitHub stars, 3 million NuGet downloads) (*)- a fluent, portable, testable HTTP client library

All the above packages provide a great developer experience (i.e., concise, easy API) and are well maintained.

(*) as at August 2019

Example: Getting a Todo item from a Fake Rest API using ServiceStack.Text. The other libraries have very similar syntax.

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

}

Running the above example in a .NET Core Console app, produces the following output.

Enter image description here

Install these packages using NuGet

Install-Package ServiceStack.Text, or

Install-Package RestSharp, or

Install-Package Flurl.Http
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Mark
  • 2,175
  • 20
  • 23
  • Please bear in mind that ServiceStack is NOT Free OpenSource! The Free version is limited in usage - details here: https://servicestack.net/download#free-quotas – Tomasz Oct 28 '20 at 09:09
  • 2
    @Tomasz - ServiceStack.Text and the HttpUtils shown above are free, open-source https://github.com/ServiceStack/ServiceStack.Text. – Mark Oct 28 '20 at 13:17
  • 1
    Yes, you're right, the ServiceStack.Text part of it is FOSS, thanks for correcting me. – Tomasz Dec 03 '20 at 08:57
  • Using IHttpClientFactory and GetFromJsonAsync ? – Kiquenet May 31 '21 at 09:37
26

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

To post, use something like this:

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

Example for delete:

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

Example to get a list:

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

Example to get only one:

ClaimTerm processedClaimImage = await HttpHelper.Get<ClaimTerm>($"/api/values/{id}");
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Raskolnikov
  • 3,791
  • 9
  • 43
  • 88
  • 3
    That's a really nice bit of code, although you should not use httpclient inside a using block. see https://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/ – Myke Black Mar 04 '20 at 13:34
  • You better use this code block instead of "result.EnsureSuccessStatusCode();" if (result.IsSuccessStatusCode) { // Handle success } else { // Handle failure } – Project Mayhem Feb 19 '21 at 09:31
  • You were very clear. GREAT – Blasco73 Mar 25 '22 at 10:37
21

Please use the below code for your REST API request:

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;
            }
        }
    }
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
  • 1
    -1: .net is a managed platform, but HttpClient is unmanaged (meaning you MUST use using to tell it when it can dispose those unmanaged pointers). Without it, your code won't scale to a couple of users (and, yes, this IS important, so important that the language have a specific keyword to deal with it). – JCKödel Oct 20 '17 at 15:47
  • 5
    @JCKödel - You're not absolutely right here and should read this https://stackoverflow.com/a/22561368 - HttpClient has been designed to be re-used for multiple calls – hB0 Oct 31 '18 at 04:57
  • 1
    Yes @JCKödel please read this article https://stackoverflow.com/questions/15705092/do-httpclient-and-httpclienthandler-have-to-be-disposed – Nathan Jun 24 '19 at 15:43
  • 1
    I think @JCKödel is absolutely right! In THE code posted above, the HttpClient is being instantiated over and over again, which is **incorrect**. Take the following note: *"HttpClient is intended to be instantiated once and re-used throughout the life of an application. Instantiating an HttpClient class for every request will exhaust the number of sockets available under heavy loads. This will result in SocketException errors. Below is an example using HttpClient correctly."* from the [Microsoft Docs](https://learn.microsoft.com/en-us/dotnet/api/system.net.http.httpclient) – Tomasz Oct 28 '20 at 09:19
11

Calling a REST API when using .NET 4.5 or .NET Core

I would suggest DalSoft.RestClient (caveat: I created it). The reason being, because it uses dynamic typing, you can wrap everything up in one fluent call including serialization/de-serialization. Below is a working PUT example:

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);
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
DalSoft
  • 10,673
  • 3
  • 42
  • 55
6

GET:

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

POST:

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

Note: To serialize and desirialze JSON, I used the Newtonsoft.Json NuGet package.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
GorvGoyl
  • 42,508
  • 29
  • 229
  • 225
5

Check out Refit for making calls to REST services from .NET. I've found it very easy to use:

Refit: The automatic type-safe REST library for .NET Core, Xamarin and .NET

Refit is a library heavily inspired by Square's Retrofit library, and it turns your REST API into a live interface:

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");
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
patrickbadley
  • 2,510
  • 2
  • 29
  • 30
2

This is example code that works for sure. It took me a day to make this to read a set of objects from a REST service:

RootObject is the type of the object I'm reading from the REST service.

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();
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
2

I did it in this simple way, with Web API 2.0. You can remove UseDefaultCredentials. I used it for my own use cases.

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;
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
MNF
  • 687
  • 9
  • 13
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

The answer marked here suggests using HttpClient directly and the disposing of it. This might work, but it's quite easy to run in to problems with HttpClient if you don't use it correctly.

If you're going to use HttpClient, you're better off handing over the creation/disposal of HttpClients to a third-party library that uses the factory pattern. RestClient.Net is one such library.

It comes with a very basic HttpClient factory so that you don't run in to the socket exhaustion problem,

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
}

But Microsoft's IHttpClientFactory implementation can also be used for the latest and greatest:

    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 takes in to account dependency injection, mocking, IoC containers, unit testability, and above all is fast. I've hunted around and the only the other client that seems to work in a similar capacity is Flurl.Http.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Christian Findlay
  • 6,770
  • 5
  • 51
  • 103
1

We have started using speakeasy. It is great:

https://github.com/jonnii/SpeakEasy

// create a client
var client = HttpClient.Create("http://example.com/api");
    
// get some companies!
var companies = client.Get("companies").OnOk().As<List<Company>>();
  
// upload a company, with validation error support
client.Post(company, "companies")
    .On(HttpStatusCode.BadRequest, (List<ValidationError> errors) => {
        Console.WriteLine("Ruh Roh, you have {0} validation errors", errors.Count());
    })
    .On(HttpStatusCode.Created, () => Console.WriteLine("Holy moly you win!"));
    
// update a company
client.Put(company, "company/:id", new { id = "awesome-sauce" })
    .OnOk(() => Console.WriteLine("Company updated"));
        
// run a search
client.Get("images/:category", new { category = "cats", breed = "omg the cutest", size = "kittens" })
    .OnOk().As<List<Image>>();
    
// make an asynchronous request
var response = await client.GetAsync("companies/:id", new { id = 5 })
response.OnOk(UpdateCompaniesCallback)
Denis
  • 11,796
  • 16
  • 88
  • 150
0

HTTP GET Request

    string api = this.configuration["getApiUrl"];//Read from Iconfiguration object injected
     public async Task<HttpResponseMessage> GetAsync(string api, ILogger log, params dynamic[] parameters)
            {
                log.LogInformation($"Get Token");
                var token = await GetTokenAsync(this.configuration["ClientId"], this.configuration["AppKey"]).ConfigureAwait(false);
                using (var client = new HttpClient())
                {
                  client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(BearerTokenName, token);
                    var apiBaseUrl = this.configuration["BaseUrl"];
                   
                    client.BaseAddress = new Uri(apiBaseUrl);
                    var apiUrl = ConstructUrl(api, parameters);
                    var result = await client.GetAsync(apiUrl).ConfigureAwait(false);
    
                    if (result.StatusCode == System.Net.HttpStatusCode.OK)
                    {
                        return result;
                    }
                    else
                    {
                       throw new HttpResponseException(new HttpResponseMessage(result.StatusCode) { Content = new StringContent(result.ReasonPhrase) });
                    }
                }
            }
    
  • Read String from HttpResponseMessage as below
     var client = await this.httpClientService.GetAsync(url, logger, Convert.ToInt32(Id, CultureInfo.InvariantCulture)).ConfigureAwait(false);
     var response = await client.Content.ReadAsStringAsync();

HTTP POST Request

     public async Task<string> PostAsync(string api, string contentValue, ILogger logger)
           {
               var token = await GetTokenAsync(this.configuration["ClientId"], this.configuration["AppKey"]).ConfigureAwait(false);
   
               using (var client = new HttpClient())
               {
                   client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(BearerTokenName, token);
                   client.BaseAddress = new Uri(resource);
                   var content = new StringContent(contentValue, Encoding.UTF8, MediaTypeNames.Application.Json);
                   var result = await client.PostAsync(new Uri(api, UriKind.Relative), content).ConfigureAwait(false);
   
                   if (result.StatusCode == System.Net.HttpStatusCode.OK)
                   {
                       return await result.Content.ReadAsStringAsync();
                   }
                   else
                   {
                       throw new HttpResponseException(new HttpResponseMessage(result.StatusCode) { Content = new StringContent(result.ReasonPhrase) });
                   }
               }
           }
    var response = await this.httpClientService.PostAsync(this.configuration["getDetails"], content, this.configuration["ApiBaseUrl"], logger).ConfigureAwait(false);
      catch (System.Web.Http.HttpResponseException httpException)
                        {
                            if (httpException.Response.StatusCode == HttpStatusCode.Unauthorized)
                            {
                                logger.LogError($"Failed To Update", httpException);
                            }
                            else
                            {
                                throw;
                            }
                        }
    return response;
Dev-lop-er
  • 578
  • 1
  • 7
  • 16
0

Since you are using Visual Studio 11 Beta, you will want to use the latest and greatest. The new Web API contains classes for this.

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

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
dice
  • 2,820
  • 1
  • 23
  • 34
-2

The first step is to create the helper class for the HTTP client.

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

Then you can use this class in your code.

This is an example of how you call the REST API without bearer using the above class.

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

This is an example of how you can call the REST API that require bearer.

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

You can also refer to the below repository if you want to see the working example of how it works.

https://github.com/mokh223/callApi

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
mokh223
  • 544
  • 3
  • 5
  • 14