一、說明
1) 這個類 是我 在真實項目中,優化解決真實問題 時,不參考第三方代碼,完全由自己查閱MSDN官方文檔 , 完成的一個真實生產環境中使用的功能類
2) 讀者在使用此類時,請尊重原創,在代碼中加上原創注釋:// Author -- Meng.NET (cnblogs.com) ,同時歡迎 二次改進、二次創作 以共同進步
3) 此代碼以【面向對象】、【C#閉包】、【異步回調】、【超時】、【等待】、【自動重試】方式實現及完成,且可以配置擴展
二、代碼
廢話不多說,上干貨,代碼如下:
1 /// <summary> 2 /// 異步 Http 3 /// </summary> 4 public class Remoter 5 { 6 /* 7 * LM,2016/08/18 8 * C#閉包化,異步化,Web操作 9 * 以便支持POS多接口多操作同時使用 10 */ 11 12 /// <summary> 13 /// 請求地址 14 /// </summary> 15 public string URL { get; set; } 16 17 /// <summary> 18 /// 請求方式 19 /// </summary> 20 public string RequestMethod { get; set; } 21 22 /// <summary> 23 /// 請求數據 24 /// </summary> 25 public string JsonContent { get; set; } 26 27 // 28 private byte[] Buffer { get; set; } 29 private Stream RequestStream { get; set; } 30 private HttpWebRequest Request { get; set; } 31 private bool ResponseFlag { get; set; } 32 private string Result { get; set; } 33 private bool TimeoutFlag { get; set; } 34 private int TimeoutTime { get; set; } 35 private bool RetryFlag { get; set; } 36 private int RetryCount { get; set; } 37 private int WaitSleep { get; set; } 38 private int TrySleep { get; set; } 39 40 // 初始化 41 public Remoter() 42 { 43 // 44 ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Ssl3; 45 ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback((object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors) => true); 46 47 // 48 this.URL = string.Empty; 49 this.Request = default(HttpWebRequest); 50 this.JsonContent = string.Empty; 51 this.Buffer = default(byte[]); 52 this.RequestStream = default(Stream); 53 this.ResponseFlag = false; 54 this.Result = string.Empty; 55 this.TimeoutFlag = false; 56 this.TimeoutTime = 10 * 1000; 57 this.RetryFlag = false; 58 this.RetryCount = 3; 59 this.WaitSleep = 10; 60 this.RequestMethod = "POST"; 61 this.TrySleep = 2000; 62 } 63 64 /// <summary> 65 /// 獲取響應數據 66 /// </summary> 67 public string GetRemoteData() 68 { 69 // 70 if(string.IsNullOrWhiteSpace(this.URL)) 71 { 72 throw new Exception("HttpAsync.URL,未賦值!"); 73 } 74 75 // 76 RemoteNew(SetResult); 77 78 // 79 var timeNum = 0; 80 while (true) 81 { 82 if (ResponseFlag) 83 { 84 break; 85 } 86 if (TimeoutFlag) 87 { 88 throw new Exception(string.Format("請求超時!超時時間:{0}S", TimeoutTime / 1000)); 89 } 90 timeNum += WaitSleep; 91 if (timeNum >= TimeoutTime) 92 { 93 TimeoutFlag = true; 94 } 95 Thread.Sleep(WaitSleep); 96 } 97 98 // 99 return Result; 100 } 101 102 // 103 private void RemoteNew(Action<Remoter, string> action) 104 { 105 // 106 var reNum = 0; 107 for (var i = 0; i < this.RetryCount; i++) 108 { 109 try 110 { 111 // 112 var uri = URL; 113 114 // 115 this.Request = WebRequest.Create(uri) as HttpWebRequest; 116 this.Request.KeepAlive = false; 117 this.Request.Method = this.RequestMethod; 118 this.Request.Credentials = CredentialCache.DefaultCredentials; 119 if (this.RequestMethod.Equals("POST", StringComparison.OrdinalIgnoreCase)) 120 { 121 this.Buffer = Encoding.UTF8.GetBytes(this.JsonContent); 122 this.Request.ContentLength = this.Buffer.Length; 123 this.Request.ContentType = "application/json"; 124 this.RequestStream = this.Request.GetRequestStream(); 125 this.RequestStream.Write(this.Buffer, 0, this.Buffer.Length); 126 this.RequestStream.Close(); 127 } 128 129 // 130 this.Request.BeginGetResponse((arr) => 131 { 132 // 133 var state = arr.AsyncState as Remoter; 134 // 135 var response = state.Request.EndGetResponse(arr) as HttpWebResponse; 136 var respStream = new StreamReader(response.GetResponseStream(), Encoding.GetEncoding("UTF-8")); 137 action(state, respStream.ReadToEnd()); 138 respStream.Close(); 139 response.Close(); 140 }, this); 141 // 142 break; 143 } 144 catch (Exception ex) 145 { 146 Thread.Sleep(this.TrySleep); 147 reNum++; 148 if (reNum == this.RetryCount) 149 { 150 throw new Exception(string.Format("重試失敗!重試次數:{0}次,失敗原因:{1}", this.RetryCount, ex.Message)); 151 } 152 continue; 153 } 154 } 155 } 156 private void SetResult(Remoter state, string jsonData) 157 { 158 if (!string.IsNullOrWhiteSpace(jsonData)) 159 { 160 state.Result = jsonData; 161 state.ResponseFlag = true; 162 } 163 } 164 } Remoter.cs使用方式:
GET:
1 var remoter = new Remoter(); 2 remoter.RequestMethod = "GET"; 3 remoter.URL = "這裡是你要請求的URL"; 4 var response = remoter.GetRemoteData(); View CodePOST:
1 var remoter = new Remoter(); 2 remoter.RequestMethod = "POST"; 3 remoter.URL = "你要請求的URL"; 4 remoter.JsonContent = "你要想URL發送的JSON數據"; 5 var response = remoter.GetRemoteData(); View Code三、代碼解析
public Remoter() 初始化本類,可配置到 App.config/Web.config 中
1 // 2 this.URL = string.Empty; 3 this.Request = default(HttpWebRequest); 4 this.JsonContent = string.Empty; 5 this.Buffer = default(byte[]); 6 this.RequestStream = default(Stream); 7 this.ResponseFlag = false; 8 this.Result = string.Empty; 9 this.TimeoutFlag = false; 10 this.TimeoutTime = 10 * 1000; 11 this.RetryFlag = false; 12 this.RetryCount = 3; 13 this.WaitSleep = 10; 14 this.RequestMethod = "POST"; 15 this.TrySleep = 2000; 可從配置文件讀取部分public string URL 要請求的地址
public string RequestMethod HTTP 動詞
public string JsonContent POST 請求時,發送的json數據
private byte[] Buffer 設置請求流的byte數組
private Stream RequestStream 請求流
private HttpWebRequest Request HTTP請求對象
private bool ResponseFlag 與請求對應的響應是否成功標識
private string Result 回調狀態保持對象,保存響應結果用
private bool TimeoutFlag 總超時時間是否超時標識
private int TimeoutTime 總超時時間(包含若干次重試),默認10s
private int RetryCount 總URL調用(失敗)自動重試次數,默認3次
private int WaitSleep 主線程,仿Ajax回調等待時間,默認10ms
private int TrySleep 每次請求地址失敗後,重試時間間隔,默認2s
public string GetRemoteData() 解析:
1 // 2 var timeNum = 0; 3 while (true) 4 { 5 if (ResponseFlag) 6 { 7 break; 8 } 9 if (TimeoutFlag) 10 { 11 throw new Exception(string.Format("請求超時!超時時間:{0}S", TimeoutTime / 1000)); 12 } 13 timeNum += WaitSleep; 14 if (timeNum >= TimeoutTime) 15 { 16 TimeoutFlag = true; 17 } 18 Thread.Sleep(WaitSleep); 19 } 主線程,仿Ajax回調等待private void RemoteNew(Action<Remoter, string> action) 解析:
1 private void RemoteNew(Action<Remoter, string> action) 2 { 3 // 4 var reNum = 0; 5 for (var i = 0; i < this.RetryCount; i++) 6 { 7 try 8 { 9 // 此處省略 10 //... ... 11 12 // 13 break; 14 } 15 catch (Exception ex) 16 { 17 Thread.Sleep(this.TrySleep); 18 reNum++; 19 if (reNum == this.RetryCount) 20 { 21 throw new Exception(string.Format("重試失敗!重試次數:{0}次,失敗原因:{1}", this.RetryCount, ex.Message)); 22 } 23 continue; 24 } 25 } 26 } 調用URL失敗,自動重試機制 1 // 2 this.Request.BeginGetResponse((arr) => 3 { 4 // 5 var state = arr.AsyncState as Remoter; 6 // 7 var response = state.Request.EndGetResponse(arr) as HttpWebResponse; 8 var respStream = new StreamReader(response.GetResponseStream(), Encoding.GetEncoding("UTF-8")); 9 action(state, respStream.ReadToEnd()); 10 respStream.Close(); 11 response.Close(); 12 }, this); 異步響應回調,閉包與自狀態保持private void SetResult(Remoter state, string jsonData) 解析:
1 state.Result = jsonData; 2 state.ResponseFlag = true; 異步響應成功後,在狀態保持中賦值結果四、計劃中的開源項目...
計劃後續會將生產中解決問題的諸多地方匯集成一個項目【Meng.Net.dll】並開源至GitHub上,歡迎交流,共同提高~~
至於本文所講的類會在哪個命名空間中,還沒想好,項目的整體結構及主打方向,敬請期待......
蒙
2016-09-24 22:37 周六
支付寶打賞: 微信打賞: