【问题标题】:How do I make calls to a REST API using C#?如何使用 C# 调用 REST API?
【发布时间】:2012-03-26 02:10:26
【问题描述】:

这是我目前的代码:

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

        }
    }

问题是我认为异常块被触发(因为当我删除 try-catch 时,我收到服务器错误(500)消息。但我没有看到我放入的 Console.Out 行捕获块。

我的控制台:

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

【问题讨论】:

标签: c# .net rest .net-4.5


【解决方案1】:

ASP.NET Web API 已经取代了前面提到的WCF Web API。

我想我会发布一个更新的答案,因为这些回复中的大多数来自 2012 年初,并且这个帖子是在 Google 搜索“call restful service C#”时的最佳结果之一。

Microsoft 当前的指导是使用 Microsoft ASP.NET Web API 客户端库来使用 RESTful 服务。这可作为 NuGet 包 Microsoft.AspNet.WebApi.Client 获得。您需要将此 NuGet 包添加到您的解决方案中。

以下是使用 ASP.NET Web API 客户端库实现示例时的外观:

using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Headers;

namespace ConsoleProgram
{
    public class DataObject
    {
        public string Name { get; set; }
    }

    public class Class1
    {
        private const string URL = "https://sub.domain.com/objects.json";
        private string urlParameters = "?api_key=123";

        static void Main(string[] args)
        {
            HttpClient client = new HttpClient();
            client.BaseAddress = new Uri(URL);

            // Add an Accept header for JSON format.
            client.DefaultRequestHeaders.Accept.Add(
            new MediaTypeWithQualityHeaderValue("application/json"));

            // List data response.
            HttpResponseMessage response = client.GetAsync(urlParameters).Result;  // Blocking call! Program will wait here until a response is received or a timeout occurs.
            if (response.IsSuccessStatusCode)
            {
                // Parse the response body.
                var dataObjects = response.Content.ReadAsAsync<IEnumerable<DataObject>>().Result;  //Make sure to add a reference to System.Net.Http.Formatting.dll
                foreach (var d in dataObjects)
                {
                    Console.WriteLine("{0}", d.Name);
                }
            }
            else
            {
                Console.WriteLine("{0} ({1})", (int)response.StatusCode, response.ReasonPhrase);
            }

            // Make any other calls using HttpClient here.

            // Dispose once all HttpClient calls are complete. This is not necessary if the containing object will be disposed of; for example in this case the HttpClient instance will be disposed automatically when the application terminates so the following call is superfluous.
            client.Dispose();
        }
    }
}

如果您计划发出多个请求,您应该重用您的 HttpClient 实例。有关在这种情况下为什么没有在 HttpClient 实例上使用 using 语句的更多详细信息,请参阅此问题及其答案:Do HttpClient and HttpClientHandler have to be disposed between requests?

如需了解更多详情,包括其他示例,请参阅Call a Web API From a .NET Client (C#)

这篇博文也可能有用:Using HttpClient to Consume ASP.NET Web API REST Services

【讨论】:

  • 谢谢!我需要安装 WebApi 客户端 NuGet 包才能为我工作:Install-Package Microsoft.AspNet.WebApi.Client
  • 如果您需要模拟您的 REST 集成,即使使用客户端库,这仍然不容易。试试 RestSharp?
  • 为了使这个答案比现在更好,您应该将 HttpClient 声明包装到 using 语句中以更好地管理您的资源:)
  • 尝试使用但无法使用 ReadAsAsync(),出现错误“HttpContent 不包含 'ReadAsAsync' 的定义并且没有扩展方法。
  • @RobertGreenMBA:要获取扩展方法ReadAsAsync(),请添加对System.Net.Http.Formatting.dll 的引用。 (直觉,对吧?)
【解决方案2】:

我的建议是使用RestSharp。您可以调用 REST 服务并将它们转换为 POCO 对象,只需很少的样板代码实际上必须解析响应。这不会解决您的特定错误,但它会回答您关于如何调用 REST 服务的总体问题。必须更改代码才能使用它应该会在易用性和稳健性方面得到回报。不过,这只是我的两分钱。

例子:

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

【讨论】:

  • RestSharp 和 JSON.NET 绝对是要走的路。我发现缺少 MS 工具集并且可能会失败。
  • 对 RestSharp 再投一票,因为您可以模拟它进行测试,比 WebApi 客户端库更容易。
  • 对于单声道用户 - RestSharp 似乎正在使用 System.Net WebRequest api - 根据我的经验,它不如 .net 实现可靠。 (“随机”挂起)
  • 请在这个答案中有一个例子。
  • 缺少示例使这篇文章没有帮助!
【解决方案3】:

我敢肯定,这无关紧要,但请务必将您的 IDisposable 对象包装在 using 块中以确保正确处理:

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

【讨论】:

  • 不错的答案,它不使用常规 .NET 环境之外的任何额外包。
  • @Jesse C. Slicer..为什么我在 WebResponse webResponse = request.GetResponse() 中遇到错误 404;
  • 因为找不到资源?获得 404 的原因有很多。
  • 这是一个很好的解决方案@JesseC.Slicer。我可以应用此代码来提取令牌并从控制台查看它。您有什么提示可以让我现在将此令牌用于身份验证/登录吗?我想使用 GET 来提取一些数据,但只有在我登录后才能使用。我在哪里可以了解更多信息?谢谢!
  • 使用系统两次 :)
【解决方案4】:

以下是在 C# 中调用外部 API 的几种不同方式(2019 年更新)。

.NET 的内置方式:

  • WebRequest& WebClient - 冗长的 API 和微软的文档不太容易理解
  • HttpClient - .NET 的最新成员,使用起来比上面的简单得多。

免费的开源 NuGet 包,坦率地说,它比 .NET 的内置客户端具有更好的开发者体验:

  • ServiceStack.Text(1,000 个 GitHub 星,700 万次 NuGet 下载)(*) - 快速、轻便且有弹性。
  • RestSharp(6000 个 GitHub 星,2300 万次 NuGet 下载)(*) - 简单的 REST 和 HTTP API 客户端
  • Flurl(1,700 个 GitHub 星,300 万次 NuGet 下载)(*)- 一个流畅、可移植、可测试的 HTTP 客户端库

以上所有软件包都提供了出色的开发人员体验(即简洁、简单的 API)并且维护良好。

(*) 截至 2019 年 8 月

示例:使用 ServiceStack.Text 从 Fake Rest API 获取 Todo 项。 其他库的语法非常相似。

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

}

在 .NET Core 控制台应用程序中运行上述示例,会产生以下输出。

使用 NuGet 安装这些包

Install-Package ServiceStack.Text, or

Install-Package RestSharp, or

Install-Package Flurl.Http

【讨论】:

  • 请记住,ServiceStack 不是免费开源的!免费版使用受限 - 详情请点击此处:servicestack.net/download#free-quotas
  • @Tomasz - ServiceStack.Text 和上面显示的 HttpUtils 是免费的、开源的github.com/ServiceStack/ServiceStack.Text
  • 是的,你没看错,其中的ServiceStack.Text部分是FOSS,谢谢指正。
  • 使用 IHttpClientFactory 和 GetFromJsonAsync ?
【解决方案5】:

请为您的 REST API 请求使用以下代码:

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 是一个托管平台,但 HttpClient 是非托管的(这意味着您必须使用 using 来告诉它何时可以处理这些非托管指针)。没有它,您的代码将无法扩展到几个用户(是的,这很重要,非常重要,以至于语言有一个特定的关键字来处理它)。
  • @JCKödel - 你不是绝对正确,应该阅读这个stackoverflow.com/a/22561368 - HttpClient 被设计为可重复用于多次调用
  • 是的@JCKödel 请阅读这篇文章stackoverflow.com/questions/15705092/…
  • 我认为@JCKödel 绝对正确!在上面发布的代码中,HttpClient 被一遍又一遍地实例化,这是不正确。请注意以下几点:“HttpClient 旨在被实例化一次并在应用程序的整个生命周期中重复使用。为每个请求实例化一个 HttpClient 类将耗尽重负载下可用的套接字数量。这将导致 SocketException错误。下面是正确使用 HttpClient 的示例。"来自Microsoft Docs
【解决方案6】:

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

要发布,请使用以下内容:

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

删除示例:

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

获取列表的示例:

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

仅获取一个的示例:

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

【讨论】:

  • 这是一段非常棒的代码,虽然你不应该在 using 块中使用 httpclient。见aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong
  • 你最好使用这个代码块而不是“result.EnsureSuccessStatusCode();” if (result.IsSuccessStatusCode) { // 处理成功 } else { // 处理失败 }
【解决方案7】:

使用 .NET 4.5 或 .NET Core 时调用 REST API

我建议DalSoft.RestClient(注意:我创建了它)。原因是,因为它使用动态类型,您可以将所有内容封装在一个流畅的调用中,包括序列化/反序列化。下面是一个有效的PUT 示例:

dynamic client = new RestClient("http://jsonplaceholder.typicode.com");

var post = new Post { title = "foo", body = "bar", userId = 10 };

var result = await client.Posts(1).Put(post);

【讨论】:

    【解决方案8】:

    获取:

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

    注意:为了序列化和反序列化 JSON,我使用了 Newtonsoft.Json NuGet 包。

    【讨论】:

      【解决方案9】:

      查看Refit 以从 .NET 调用 REST 服务。我发现它非常易于使用:

      Refit:适用于 .NET Core、Xamarin 和 .NET

      Refit 是一个深受 Square 的 Retrofit 库启发的库,并且 它将您的 REST API 变成一个实时界面:

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

      【讨论】:

      • 你知道Refit是否使用反射来实现这一点吗?我在任何地方都找不到信息。
      • 对不起@tfrascaroli,我不确定。
      【解决方案10】:

      这是肯定有效的示例代码。我花了一天的时间从 REST 服务中读取一组对象:

      RootObject 是我从 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();
      

      【讨论】:

        【解决方案11】:

        我使用 Web API 2.0 以这种简单的方式完成了它。您可以删除 UseDefaultCredentials。我将它用于我自己的用例。

        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;
        

        【讨论】:

          【解决方案12】:
              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();
          

          【讨论】:

            【解决方案13】:

            此处标记的答案建议直接使用 HttpClient 并将其处理掉。这可能有效,但如果使用不当,很容易使用 HttpClient run in to problems

            如果您要使用 HttpClient,最好将 HttpClients 的创建/处置交给使用 factory pattern 的第三方库。 RestClient.Net 就是这样一个库。

            它带有一个非常基本的 HttpClient 工厂,这样你就不会遇到套接字耗尽的问题,

            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
            }
            

            但是微软的 IHttpClientFactory 实现也可以用于最新最好的:

                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 考虑了依赖注入、模拟、IoC 容器、单元可测试性,最重要的是速度很快。我四处寻找,似乎以类似能力工作的唯一另一个客户端是 Flurl.Http。

            【讨论】:

              【解决方案14】:

              我们已经开始使用speakeasy。太好了:

              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)
              

              【讨论】:

                【解决方案15】:

                由于您使用的是 Visual Studio 11 Beta,因此您将希望使用最新最好的。新的 Web API 包含用于此的类。

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

                【讨论】:

                • 链接(实际上)已损坏。它重定向到https://archive.codeplex.com/?p=wcf
                【解决方案16】:

                HTTP GET 请求

                    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) });
                                    }
                                }
                            }
                    
                
                • 从 HttpResponseMessage 读取字符串如下
                     var client = await this.httpClientService.GetAsync(url, logger, Convert.ToInt32(Id, CultureInfo.InvariantCulture)).ConfigureAwait(false);
                     var response = await client.Content.ReadAsStringAsync();
                

                HTTP POST 请求

                     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;
                

                【讨论】:

                  【解决方案17】:

                  第一步是为 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;
                          }
                      }
                  }
                  

                  那么你就可以在你的代码中使用这个类了。

                  这是一个示例,说明如何使用上述类在无承载的情况下调用 REST API。

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

                  这是一个如何调用需要承载的 REST API 的示例。

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

                  如果您想查看其工作原理的工作示例,也可以参考以下存储库。

                  https://github.com/mokh223/callApi

                  【讨论】:

                  • 你说的“无承载”是什么意思(在“...调用无承载的REST API”
                  猜你喜欢
                  • 1970-01-01
                  • 2023-03-07
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2018-05-10
                  • 1970-01-01
                  相关资源
                  最近更新 更多