How do I make calls to a REST API using C#?

后端 未结 15 1606
面向向阳花
面向向阳花 2020-11-22 08:10

This is the code I have so far:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System;
using System.Net.Http;
usi         


        
相关标签:
15条回答
  • 2020-11-22 08:43

    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.

    0 讨论(0)
  • 2020-11-22 08:43

    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.

    0 讨论(0)
  • 2020-11-22 08:49

    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

    0 讨论(0)
  • 2020-11-22 08:51

    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.

    Install these packages using NuGet

    Install-Package ServiceStack.Text, or
    
    Install-Package RestSharp, or
    
    Install-Package Flurl.Http
    
    0 讨论(0)
  • 2020-11-22 08:51

    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}");
    
    0 讨论(0)
  • 2020-11-22 08:52

    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);
    
    0 讨论(0)
提交回复
热议问题