十二、.net core(.NET 6)新增通用的訪問webapi的方法(包括HttpClient和HttpWebRequest)

WeskyNet發表於2021-06-06

 

開發通用的訪問webapi方法。

 

common工具資料夾下,新建一個類庫專案:Wsk.Core.WebHelper,並引用Package包專案,然後新建一個類HttpClientHelper,用於使用HttpClient方法進行訪問webapi:

 

 

新建一個介面IHttpClientHelper,用於HttpClientHelper繼承該介面。然後介面內新增一個返回泛型型別的通用的POST訪問webapi的方法:

 

 

接著,在HttpClientHelper類裡面,進行對該方法的實現:

 

說明:雖然使用了using,可以自動釋放資源;但是難免還是需要一點時間。在finally下面通過手動釋放資源,比自動釋放資源,資源釋放率會更快,在併發場景下,效能會更好一點點。當然,此處可以不適用using,因為手動釋放了,以上純屬個人喜好的風格寫法。

再來一個使用Basic加密進行訪問的通用方法,寫法如上,具體請看程式碼示例。先新建帶使用者名稱和密碼引數的介面:

 

 

然後,在HttpClientHelper裡面進行對應的實現:

 

 

以上為使用POST的方式進行,如果需要使用例如GETPUT等,可以自行嘗試,寫法類似。

介面程式碼:

十二、.net core(.NET 6)新增通用的訪問webapi的方法(包括HttpClient和HttpWebRequest)
public interface IHttpClientHelper
    {
        /// <summary>
        /// 通用訪問webapi方法
        /// </summary>
        /// <param name="url"></param>
        /// <param name="data"></param>
        /// <returns></returns>
        T Post<T>(string url, string data);

        /// <summary>
        /// 帶使用者名稱和密碼的通用訪問webapi方法
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="url"></param>
        /// <param name="data"></param>
        /// <param name="account">使用者名稱</param>
        /// <param name="pwd">密碼</param>
        /// <returns></returns>
        T Post<T>(string url, string data, string account, string pwd);

    }
View Code

 

實現類程式碼:

十二、.net core(.NET 6)新增通用的訪問webapi的方法(包括HttpClient和HttpWebRequest)
  public class HttpClientHelper:IHttpClientHelper
    {

        readonly ILogger<HttpClientHelper> _logger;

        public HttpClientHelper(ILogger<HttpClientHelper> logger)
        {
            _logger = logger;
        }

        public T Post<T>(string url, string data)
        {
            var result = default(T);
            using (HttpClient client = new HttpClient())
            {
                try
                {
                    client.Timeout = new TimeSpan(0, 0, 10); // 10是秒數,用於設定超時時長
                    HttpContent content = new StringContent(data);
                    content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json");
                    client.DefaultRequestHeaders.Connection.Add("keep-alive");
                    Task<HttpResponseMessage> res = client.PostAsync(url, content);
                    if (res.Result.StatusCode == System.Net.HttpStatusCode.OK)
                    {
                        result = JsonConvert.DeserializeObject<T>(res.Result.Content.ReadAsStringAsync().Result);
                    }
                    else
                    {
                        _logger.LogError($"訪問webapi方法狀態碼錯誤:\r url:{url} \r data:{data} \r 狀態碼:{res.Result.StatusCode}");
                    }
                }
                catch (Exception ex)
                {
                    _logger.LogError($"訪問webapi方法異常:\r url:{url} \r data:{data} \r 異常資訊:{ex.Message}");
                }
                finally
                {
                    client.Dispose();
                }
            }
            return result;
        }

        public T Post<T>(string url, string data, string account, string pwd)
        {
            var result = default(T);
            using (HttpClient client = new HttpClient())
            {
                try
                {
                    string authorization = "Basic " + Convert.ToBase64String(Encoding.UTF8.GetBytes(account + ":" + pwd));
                    client.DefaultRequestHeaders.Add("authorization", authorization);

                    client.Timeout = new TimeSpan(0, 0, 10);
                    HttpContent content = new StringContent(data);
                    content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json");
                    Task<HttpResponseMessage> res = client.PostAsync(url, content);
                    if (res.Result.StatusCode == System.Net.HttpStatusCode.OK)
                    {
                        result = JsonConvert.DeserializeObject<T>(res.Result.Content.ReadAsStringAsync().Result);
                    }
                    else
                    {
                        _logger.LogError($"訪問帶使用者名稱引數的webapi方法狀態碼錯誤:\r url:{url} \r data:{data} \r 狀態碼:{res.Result.StatusCode}");
                    }
                }
                catch (Exception ex)
                {
                    _logger.LogError($"訪問帶使用者名稱引數的webapi方法異常:\r url:{url} \r data:{data} \r 異常資訊:{ex.Message}");
                }
                finally
                {
                    client.Dispose();
                }
            }
            return result;
        }

    }
View Code

 

 

現在再新建一個使用HttpWebRequest的通用訪問webapi的方式。在WebHelper專案下面,新建 HttpWebRequestHelper類,以及IHttpWebRequestHelper介面:

 

 

在介面裡面,新建一個通用的泛型型別的訪問webapi的請求介面:

 

 

然後,在HttpWebRequestHelper類裡面,進行有關的實現:

 

HttpWebRequest沒有Dispose方法,所以此處沒有使用using寫法,最後需要手動使用Abort方法進行釋放資源。

介面程式碼:

十二、.net core(.NET 6)新增通用的訪問webapi的方法(包括HttpClient和HttpWebRequest)
 public interface IHttpWebRequestHelper
    {
        /// <summary>
        /// 通用方法
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="url"></param>
        /// <param name="data"></param>
        /// <param name="method">預設POST</param>
        /// <returns></returns>
        T Request<T>(string url, string data, string method = "POST");
    }
View Code

介面實現程式碼:

十二、.net core(.NET 6)新增通用的訪問webapi的方法(包括HttpClient和HttpWebRequest)
   public class HttpWebRequestHelper:IHttpWebRequestHelper
    {
        readonly ILogger<HttpWebRequestHelper> _logger;

        public HttpWebRequestHelper(ILogger<HttpWebRequestHelper> logger)
        {
            _logger = logger;
        }
        public T Request<T>(string url, string data,string method="POST")
        {
            var result = default(T);
            HttpWebRequest request = null;
            try
            {
                request = (HttpWebRequest)WebRequest.Create(url);
                var byteData = Encoding.UTF8.GetBytes(data);
                request.Method = method;
                request.ContentType = "application/json"; 
                request.ContentLength = data.Length;
                request.Timeout = 10000; // 超時時間,毫秒單位
                using (var stream = request.GetRequestStream())
                {
                    stream.Write(byteData, 0, data.Length);
                }
                var response = (HttpWebResponse)request.GetResponse(); // 傳送請求
                using (var resStream = response.GetResponseStream()) // 讀取資料
                {
                    using (var reader = new StreamReader(resStream, Encoding.UTF8))
                    {
                        result = JsonConvert.DeserializeObject<T>(reader.ReadToEnd()); 
                    }
                }
            }
            catch (Exception ex)
            {
                  _logger.LogError($"使用HttpWebRequest訪問webapi方法異常:\r url:{url} \r data:{data} \r 異常資訊:{ex.Message}");
            }
            finally
            {
                if (request != null)
                {
                    request.Abort(); // 釋放資源
                }
            }
            return result;
        }
    }
View Code

 

現在開發兩個webapi進行測試。首先把該類庫專案,新增到啟動專案的專案引用裡面。然後,在啟動專案裡面的AutofacRegister裡面,新增對Wsk.Core.WebHelper類庫專案的所有介面進行依賴注入註冊:

 

 

註冊部分程式碼:

var assemblysWebhelper = Assembly.Load("Wsk.Core.WebHelper"); // 
            container.RegisterAssemblyTypes(assemblysWebhelper)
                .SingleInstance()
               .AsImplementedInterfaces() 
               .EnableInterfaceInterceptors();

 

新建一個實體類,用來當作引數和返回值的測試:

 

 

接著,在控制器裡面寫幾個測試方法進行測試,測試內容如下:

 

控制器部分程式碼:

 

十二、.net core(.NET 6)新增通用的訪問webapi的方法(包括HttpClient和HttpWebRequest)
 [Route("[controller]/[action]")]
    [ApiController]
    public class WSKController : ControllerBase
    {
        private readonly ITestAutofac _autofac;
        private readonly ILogger<WSKController> _logger;
        private readonly IRedisManage _redis;
        private readonly IHttpClientHelper _httpClient;
        private readonly IHttpWebRequestHelper _httpWebRequestHelper;

        public WSKController(ITestAutofac autofac, ILogger<WSKController> logger, IRedisManage redis, IHttpClientHelper httpClient, IHttpWebRequestHelper httpWebRequestHelper) {
            _autofac = autofac;
            _logger = logger;
            _redis = redis;
            _httpClient = httpClient;
            _httpWebRequestHelper = httpWebRequestHelper;
        }
        [HttpPost]
        public IActionResult HelloWorld(string url1,string url2)
        {
            TestWebHelperInfo info = new TestWebHelperInfo();
            info.name = "Hello";
            var value1 = _httpClient.Post<TestWebHelperInfo>(url1,JsonConvert.SerializeObject(info));

            info.name = "World";
            var value2 = _httpWebRequestHelper.Request<TestWebHelperInfo>(url2, JsonConvert.SerializeObject(info));

            return Ok($"value1:{value1.name} value2:{value2.name}");
        }
        [HttpPost]
        public IActionResult Test1([FromBody] TestWebHelperInfo info)
        {
            return Ok(info);
        }
        [HttpPost]
        public IActionResult Test2([FromBody] TestWebHelperInfo info)
        {
            return Ok(info);
        }

    }
View Code

 

執行,然後測試一下12介面是否可以使用,如果可以使用,拷貝對應的url地址,當作引數傳給主測試api裡面。

 

 

獲得到請求的url地址字首是:http://localhost:35678/WSK/,帶入引數進行驗證:

 

 

由此可見,兩個通用方法都可用。

備註:如果不適用泛型,也可以直接使用返回String即可,不需要進行型別轉換。

 

如果覺得有用,歡迎點贊、評論、推薦或打賞~~

 

相關文章