.NET Core 下調用WebAPI

前言

今天我們介紹多種客戶端調用WebApi的方式,可以是原生寫的,也可以藉助.NET 框架下的其他HTTP庫。我們一起來看看它們之間的一些異同吧~

RestSharp

首先要介紹的就是這款REST 客戶端,我們先來一起看看它的簡介:

RestSharp 是一個基於 .NET 框架的 REST 客戶端,RestSharp 是一個輕量的,不依賴任何第三方的組件或者類庫的 HTTP 組件,RestSharp具有以下的優點:

01、支持.NET4.5.2+ 和 .NET Standard 2.0 平臺
02、使用NuGet輕鬆安裝開發包
03、自動 XML 和 JSON 反序列化
04、通過 ISerializer 和 IDeserializer 自定義序列化和反序列化爲
05、模糊匹配元素名稱 (例如:XML或JSON中的product_id將匹配名爲ProductId的C#屬性)
06、自動檢測返回內容的類型
07、指出 GET, POST, PUT, PATCH, HEAD, OPTIONS, DELETE 和 COPY 請求,支持其它非標準 HTTP 方法
08、OAuth 1.0、OAuth 2.0、Basic、NTLM 和基於參數的身份認證
09、通過 IAuthenticator 接口自定義身份驗證方案
10、支持異步操作

官方示例:

var client = new RestClient("https://www.xcode.me");
// client.Authenticator = new HttpBasicAuthenticator(username, password);

var request = new RestRequest("resource/{id}", Method.POST);
request.AddParameter("name", "value"); // adds to POST or URL querystring based on Method
request.AddUrlSegment("id", "123"); // replaces matching token in request.Resource

// add parameters for all properties on an object
request.AddObject(object);

// or just whitelisted properties
request.AddObject(object, "PersonId", "Name", ...);

// easily add HTTP Headers
request.AddHeader("header", "value");

// add files to upload (works with compatible verbs)
request.AddFile("file", path);

// execute the request
IRestResponse response = client.Execute(request);
var content = response.Content; // raw content as string

// or automatically deserialize result
// return content type is sniffed but can be explicitly set via RestClient.AddHandler();
IRestResponse<Person> response2 = client.Execute<Person>(request);
var name = response2.Data.Name;

// or download and save file to disk
client.DownloadData(request).SaveAs(path);

// easy async support
await client.ExecuteAsync(request);

// async with deserialization
var asyncHandle = client.ExecuteAsync<Person>(request, response => {
    Console.WriteLine(response.Data.Name);
});

// abort the request on demand
asyncHandle.Abort();

使用案例:

Setp 1

引入RestSharp包

Setp 2

新建一個API請求執行者的接口IRestSharp:

/// <summary>
    /// API請求執行者接口
    /// </summary>
    public interface IRestSharp
    {
        /// <summary>
        /// 同步執行方法
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        IRestResponse Execute(IRestRequest request);

        /// <summary>
        /// 同步執行方法
        /// </summary>
        /// <typeparam name="T">返回值</typeparam>
        /// <param name="request">請求參數</param>
        /// <returns></returns>
        T Execute<T>(IRestRequest request) where T : new();

        /// <summary>
        /// 異步執行方法
        /// </summary>
        /// <param name="request">請求參數</param>
        /// <param name="callback"></param>
        /// <returns></returns>
        RestRequestAsyncHandle ExecuteAsync(IRestRequest request, Action<IRestResponse> callback);

        /// <summary>
        /// 異步執行方法
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="request"></param>
        /// <param name="callback"></param>
        /// <returns></returns>
        RestRequestAsyncHandle ExecuteAsync<T>(IRestRequest request, Action<IRestResponse<T>> callback) where T : new();
    }

 

Setp 3

新建一個實現類RestSharpClient,實現上述接口

/// <summary>
     /// Rest接口執行者
     /// </summary>
     public class RestSharpClient : IRestSharp
     {
         /// <summary>
         /// 請求客戶端
         /// </summary>
         private RestClient client;
 
         /// <summary>
         /// 接口基地址 格式:http://www.xxx.com/
         /// </summary>
         private string BaseUrl { get; set; }
 
         /// <summary>
         /// 默認的時間參數格式
         /// </summary>
         private string DefaultDateParameterFormat { get; set; }
 
         /// <summary>
         /// 默認驗證器
         /// </summary>
         private IAuthenticator DefaultAuthenticator { get; set; }
 
         /// <summary>
         /// 構造函數
         /// </summary>
         /// <param name="baseUrl"></param>
         /// <param name="authenticator"></param>
         public RestSharpClient(string baseUrl, IAuthenticator authenticator = null)
         {
             BaseUrl = baseUrl;
             client = new RestClient(BaseUrl);
             DefaultAuthenticator = authenticator;
 
             //默認時間顯示格式
             DefaultDateParameterFormat = "yyyy-MM-dd HH:mm:ss";
 
             //默認校驗器
             if (DefaultAuthenticator != null)
             {
                 client.Authenticator = DefaultAuthenticator;
             }
         }
 
         /// <summary>
         /// 通用執行方法
         /// </summary>
         /// <param name="request">請求參數</param>
         /// <remarks>
         /// 調用實例:
         /// var client = new RestSharpClient("http://localhost:82/");
         /// var result = client.Execute(new RestRequest("api/values", Method.GET));
         /// var content = result.Content;//返回的字符串數據
         /// </remarks>
         /// <returns></returns>
         public IRestResponse Execute(IRestRequest request)
         {
             request.DateFormat = string.IsNullOrEmpty(request.DateFormat) ? DefaultDateParameterFormat : request.DateFormat;
             var response = client.Execute(request);
             return response;
         }
 
         /// <summary>
         /// 同步執行方法
         /// </summary>
         /// <typeparam name="T">返回的泛型對象</typeparam>
         /// <param name="request">請求參數</param>
         /// <remarks>
         ///  var client = new RestSharpClient("http://localhost:82/");
         ///  var result = client.Execute<List<string>>(new RestRequest("api/values", Method.GET)); 
         /// </remarks>
         /// <returns></returns>
         public T Execute<T>(IRestRequest request) where T : new()
         {
              request.DateFormat = string.IsNullOrEmpty(request.DateFormat) ? DefaultDateParameterFormat : request.DateFormat;
              var response = client.Execute<T>(request);
              return response.Data;
          }
 
         /// <summary>
         /// 異步執行方法
         /// </summary>
         /// <param name="request">請求參數</param>
         /// <param name="callback">回調函數</param>
         /// <remarks>
         /// 調用實例:
         /// var client = new RestSharpClient("http://localhost:62981/");
         /// client.ExecuteAsync<List<string>>(new RestRequest("api/values", Method.GET), result =>
         /// {
         ///      var content = result.Content;//返回的字符串數據
         /// });
         /// </remarks>
         /// <returns></returns>
         public RestRequestAsyncHandle ExecuteAsync(IRestRequest request, Action<IRestResponse> callback)
         {
             request.DateFormat = string.IsNullOrEmpty(request.DateFormat) ? DefaultDateParameterFormat : request.DateFormat;
             return client.ExecuteAsync(request, callback);
         }
 
         /// <summary>
         /// 異步執行方法
         /// </summary>
         /// <typeparam name="T">返回的泛型對象</typeparam>
         /// <param name="request">請求參數</param>
         /// <param name="callback">回調函數</param>
         /// <remarks>
         /// 調用實例:
         /// var client = new RestSharpClient("http://localhost:62981/");
         /// client.ExecuteAsync<List<string>>(new RestRequest("api/values", Method.GET), result =>
         /// {
         ///      if (result.StatusCode != HttpStatusCode.OK)
         ///      {
         ///         return;
         ///      }
         ///      var data = result.Data;//返回數據
         /// });
         /// </remarks>
         /// <returns></returns>
         

         public RestRequestAsyncHandle ExecuteAsync<T>(IRestRequest request, Action<IRestResponse<T>> callback) where T : new()
         {
            request.DateFormat = string.IsNullOrEmpty(request.DateFormat) ? DefaultDateParameterFormat : request.DateFormat;
            return client.ExecuteAsync<T>(request, callback);
        }
     }

 Setp 4

新建一個HttpHelper幫助類

public static class HttpHelper
    {
        public static T GetApi<T>(int regattaId, string apiName, string pragm = "")
        {
            var client = new RestSharpClient($"{SiteConfig.GetSite("Url")}");
            var apiNameStr = string.Format($"{SiteConfig.GetSite($"{apiName}")}", regattaId);

            var request = client.Execute(string.IsNullOrEmpty(pragm)
                ? new RestRequest(apiNameStr, Method.GET)
                : new RestRequest($"{apiNameStr}/{pragm}", Method.GET));

            if (request.StatusCode != HttpStatusCode.OK)
            {
                return (T)Convert.ChangeType(request.ErrorMessage, typeof(T));
            }

            T result = (T)Convert.ChangeType(request.Content, typeof(T));

            return result;
        }

public static T PostApi<T>(int regattaId, int id, string url, string alias)
        {var client = new RestClient($"{url}");
            IRestRequest queest = new RestRequest();
            queest.Method = Method.POST;
            queest.AddHeader("Accept", "application/json");
            queest.RequestFormat = DataFormat.Json;
            queest.AddBody(new { userid = id, Url = url, alias = alias, count = 1 }); // uses JsonSerializer
            var result = client.Execute(queest);
            if (result.StatusCode != HttpStatusCode.OK)
            {
                return (T)Convert.ChangeType(result.ErrorMessage, typeof(T));
            }

            T request = (T)Convert.ChangeType(result.Content, typeof(T));
            return request;
        }
}

Setp 5

調用

//Get
 var notificationlist = HttpHelper.GetApi<string>(regattaId, "notification");//第二個參數是配置文件中的API地址

//Post
Task.FromResult(HttpHelper.PostApi<string>(regattaId, id, url, alias))

在API端接收上述兩個請求:

 [Route("{regattaId}/[controller]")]
        [HttpGet]
        public async Task<IList<NotificationDto>> GetNotifications(int regattaId)
        {
            return await _notificationServices.GetNotifications(regattaId);
        }

[Route("{regattaId}/pageviews")]
        [HttpPost]
        // GET: /<controller>/
        public async Task PostInfo(int regattaId, [FromBody]PageViewsDto pageViewsDto)
        {
            await _pageviewServices.InsertPostInfo(regattaId, pageViewsDto);
        }

傷處PageViewDto的定義如下:

public class PageViewsDto
    {
        public int Id { get; set; }

        public string Url { get; set; }

        public string Alias { get; set; }

        public string UserId { get; set; }

        public int Count { get; set; }

        public PageViewsDto()
        {
            Id = 0;
            Count = 1;
        }
    }

 

更多詳情可訪問github:https://github.com/restsharp/RestSharp

攜帶實體參數發送Post請求

假設現在我們需要修改用戶的一些基本信息,這些信息需要通過前端 發送到API端,那麼該如何實現呢?

 public async Task<int> UpdateUser(PersonModel model)
        {
            var url = $"{SiteConfig.GetSite("Url")}{SiteConfig.GetSite("updateUserByAccount")}";
            var resultDetil = await HttpUtil.PostResultAsync<int>(model, url);
            return resultDetil;
        }

前端請求大概如上,地址URL和API名稱都再配置文件中獲取,下面我們看看PostResultAsync中是如何實現Post請求攜帶Post參數的吧

         /// <summary>
        /// 發起POST請求,並獲取請求返回值
        /// </summary>
        /// <typeparam name="T">返回值類型</typeparam>
        /// <param name="obj">數據實體</param>
        /// <param name="url">接口地址</param>
        public static async Task<T> PostResultAsync<T>(object obj, string url)
        {
            //序列化設置
            var setting = new JsonSerializerSettings();
            //解決枚舉類型序列化時,被轉換成數字的問題
            setting.Converters.Add(new StringEnumConverter());
            setting.NullValueHandling = NullValueHandling.Ignore;
            var retdata = await HttpPostAsync(url, JsonConvert.SerializeObject(obj, setting));
            return JsonConvert.DeserializeObject<T>(retdata);
        }

從上面我們可以看出,首先定義了一個泛型方法,其中接收一個參數類型是Object。另一個是url,在這個異步方法體重,我們去call了另一個請求方法

public static async Task<string> HttpPostAsync(string url, string postData, string certPath = "", string certPwd = "")
        {
            var request = CreateJsonRequest(url, HttpMethod.POST, postData, certPath, certPwd);
            return await GetResponseStringAsync(request);
        }
private static HttpWebRequest CreateJsonRequest(string url, HttpMethod method, string postData = "", string certpath = "", string certpwd = "")
        {
            var request = (HttpWebRequest)WebRequest.Create(url);
            request.Method = method.ToString();
            request.ContentType = "application/json; charset=utf-8";
            request.Accept = "*/*";
            request.Timeout = 15000;
            request.AllowAutoRedirect = false;
            ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback((a, b, c, d) => true);
            if (!string.IsNullOrEmpty(certpath) && !string.IsNullOrEmpty(certpwd))
            {
                X509Certificate2 cer = new X509Certificate2(certpath, certpwd,
                    X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.MachineKeySet);
                request.ClientCertificates.Add(cer);
            }
            if (method == HttpMethod.POST)
            {
                using (var sw = new StreamWriter(request.GetRequestStream()))
                {
                    sw.Write(postData);
                }
            }
            return request;
        }

private static async Task<string> GetResponseStringAsync(HttpWebRequest request)
        {
            using (var response = await request.GetResponseAsync() as HttpWebResponse)
            {
                using (StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.UTF8))
                {
                    return reader.ReadToEnd();//獲取響應
                }
            }
        }

上述中的HttpMethod.post爲枚舉,此枚舉中列舉了http請求常用格式

public enum HttpMethod
    {
        GET,
        POST
    }

讓我們看看上面提到的在Api端是如何接收的吧

        [Route("[controller]/UpdateUserByAccount")]
        [HttpPost]
        public async Task<int> UpdateUserByAccount([FromBody]PersonDto model)
        {
            return await _authenticationService.UpdateUserByAccount(model);
        }

這樣,我們就實現了Post請求API時攜帶實體參數

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章