如果找的是core的HttpClientFactory 出门右转。
Dispose 不是马上关闭tcp连接
主动关闭的一方为什么不能马上close而是进入timewait状态:TCP四次挥手客户端关闭链接为什么要等待2倍MSL
正确写法一个域(一个地址) 保证一个静态httpclient操作,保证重用tcp连接。
HttpClient有个接口SendAsync。看源码知道其实HttpClient内部get,post,put,delete最终都是调用SendAsync。
这个方法可以允许用户传递HttpRequestMessage,内部包含(HttpRequestHeaders)
关于Task同步上下文 造成死锁问题就不多解释。避免方法就是ConfigureAwait(false)或者await always。最好是await always。传送门
说下不用await 而使用类似HttpClient.GetStringAsync(uri).Result 直接同步获取为什么没有死锁
因为HttpClient源码里面用到async await的地方几乎都加了ConfigureAwait(false)。233333
其实这是嘴巴dudu园长大人在很久以前就做分析过 传送门
我们一般的请求流程:发起请求,获取返回的string对象,然后反序列化成我们想要的对象。而其实可以利用stream直接反序列化成我们想要的对象。
而且可以是在HttpCompletionOption.ResponseHeadersRead的情况下。传送门
HttpClient封印:
1 public class HttpAsyncSender 2 { 3 private static readonly ILogger Logger = LoggerManager.GetLogger(typeof(HttpAsyncSender)); 4 //静态 重用tcp连接 长连接(not dispose)https://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/ 5 private static readonly HttpClient HttpClient = new HttpClient(); 6 7 public HttpAsyncSender(Uri baseUri, int timeoutSecOnds= 0, bool keepAlive = true, bool preheating = false, long maxRespOnseContentBufferSize= 0) 8 { 9 //基础地址 10 HttpClient.BaseAddress = baseUri; 11 //超时 12 if (timeoutSeconds != 0) 13 { 14 HttpClient.Timeout = TimeSpan.FromSeconds(timeoutSeconds); 15 } 16 //response最大接收字节 默认2gbmstsc 17 if (maxResponseContentBufferSize != 0) 18 { 19 HttpClient.MaxRespOnseContentBufferSize= maxResponseContentBufferSize; 20 } 21 //长连接 //https://www.cnblogs.com/lori/p/7692152.html http 1.1 default set keep alive 22 if (keepAlive) 23 { 24 HttpClient.DefaultRequestHeaders.Connection.Add("keep-alive"); 25 } 26 //httpclient 预热 the first request //https://www.cnblogs.com/dudu/p/csharp-httpclient-attention.html 27 if (preheating) 28 { 29 HttpClient.SendAsync(new HttpRequestMessage 30 { 31 Method = new HttpMethod("HEAD"), 32 RequestUri = new Uri(baseUri + "/") 33 }).Result.EnsureSuccessStatusCode(); 34 } 35 } 36 37 #region 异步 38 39 ///40 /// GetAsync 注意 await always 41 /// 42 /// 43 /// 44 /// 45 public async Task GetAsync (string url, CancellationToken cancellationToken) 46 { 47 try 48 { 49 //https://johnthiriet.com/efficient-api-calls/ 减少内存开销 利用stream特性 加快反序列化 50 using (var request = new HttpRequestMessage(HttpMethod.Get, url)) 51 { 52 var res = await SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); 53 var resStesam = await res.Content.ReadAsStreamAsync().ConfigureAwait(false); 54 if (res.IsSuccessStatusCode) 55 { 56 return DeserializeJsonFromStream (resStesam); 57 } 58 var resStr = await StreamToStringAsync(resStesam).ConfigureAwait(false); 59 Logger.Error($"HttpAsyncSender, GetAsync ,response fail StatusCode:{res.StatusCode} resStr:{resStr} BaseAddress:{HttpClient.BaseAddress},Url:{url}"); 60 } 61 } 62 catch (JsonSerializationException je) 63 { 64 Logger.Error($"HttpAsyncSender,GetAsync JsonSerializationException,BaseAddress:{HttpClient.BaseAddress},Url:{url},je:{je.Message}"); 65 throw; 66 } 67 catch (AggregateException ae) 68 { 69 Logger.Error($"HttpAsyncSender,GetAsync AggregateException,BaseAddress:{HttpClient.BaseAddress},Url:{url} ae:{ae.Flatten()}"); 70 throw; 71 72 } 73 catch (Exception e) 74 { 75 Logger.Error($"HttpAsyncSender,GetAsync Exception,BaseAddress:{HttpClient.BaseAddress},Url:{url},ex:{e.Message}"); 76 throw; 77 } 78 79 return default(T); 80 } 81 82 /// 83 /// PostAsync 注意 await always 84 /// 85 /// 86 /// 87 /// 88 /// 89 public async Task PostAsync (string url, TReq content, CancellationToken cancellationToken) 90 { 91 try 92 { 93 //https://johnthiriet.com/efficient-api-calls/ 减少内存开销 利用stream特性 加快反序列化 94 using (var request = new HttpRequestMessage(HttpMethod.Post, url)) 95 using (var httpCOntent= CreateHttpContent(content)) 96 { 97 request.COntent= httpContent; 98 var res = await SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); 99 var resStesam = await res.Content.ReadAsStreamAsync().ConfigureAwait(false); 100 if (res.IsSuccessStatusCode) 101 { 102 return DeserializeJsonFromStream (resStesam); 103 } 104 var resStr = await StreamToStringAsync(resStesam).ConfigureAwait(false); 105 Logger.Error($"HttpAsyncSender, PostAsync ,response fail StatusCode:{res.StatusCode} resStr:{resStr} BaseAddress:{HttpClient.BaseAddress},Url:{url}"); 106 } 107 } 108 catch (JsonSerializationException je) 109 { 110 Logger.Error($"HttpAsyncSender,PostAsync JsonSerializationException,BaseAddress:{HttpClient.BaseAddress},Url:{url},je:{je.Message}"); 111 throw; 112 } 113 catch (AggregateException ae) 114 { 115 Logger.Error($"HttpAsyncSender,PostAsync AggregateException,BaseAddress:{HttpClient.BaseAddress},Url:{url} ae:{ae.Flatten()}"); 116 throw; 117 118 } 119 catch (Exception e) 120 { 121 Logger.Error($"HttpAsyncSender,PostAsync Exception,BaseAddress:{HttpClient.BaseAddress},Url:{url},ex:{e.Message}"); 122 throw; 123 } 124 125 return default(TRes); 126 } 127 128 /// 129 /// SendAsync 注意 await always 当需要动态改变request head的时候 调用此方法。 解决 "集合已修改;可能无法执行枚举操作" 130 /// 131 /// 132 /// 133 /// 134 /// 135 public async Task SendAsync(HttpRequestMessage httpRequestMessage, HttpCompletionOption completionOption, CancellationToken cancellationToken) 136 { 137 try 138 { 139 return await HttpClient.SendAsync(httpRequestMessage, completionOption, cancellationToken).ConfigureAwait(false); 140 } 141 catch (AggregateException ae) 142 { 143 Logger.Error( 144 $"HttpAsyncSender,SendAsync AggregateException,BaseAddress:{HttpClient.BaseAddress},Url:{httpRequestMessage.RequestUri} ae:{ae.Flatten()}"); 145 throw; 146 147 } 148 catch (Exception e) 149 { 150 Logger.Error($"HttpAsyncSender,SendAsync Exception,BaseAddress:{HttpClient.BaseAddress},Url:{httpRequestMessage.RequestUri},ex:{e.Message}"); 151 throw; 152 } 153 } 154 155 #endregion 156 157 158 private static T DeserializeJsonFromStream (Stream stream) 159 { 160 if (stream == null || stream.CanRead == false) 161 return default(T); 162 163 using (var sr = new StreamReader(stream)) 164 using (var jtr = new JsonTextReader(sr)) 165 { 166 var js = new JsonSerializer(); 167 var searchResult = js.Deserialize (jtr); 168 return searchResult; 169 } 170 } 171 172 private static async Task<string> StreamToStringAsync(Stream stream) 173 { 174 string cOntent= null; 175 176 if (stream != null) 177 using (var sr = new StreamReader(stream)) 178 cOntent= await sr.ReadToEndAsync(); 179 180 return content; 181 } 182 183 public static void SerializeJsonIntoStream(object value, Stream stream) 184 { 185 using (var sw = new StreamWriter(stream, new UTF8Encoding(false), 1024, true)) 186 using (var jtw = new JsonTextWriter(sw) { Formatting = Formatting.None }) 187 { 188 var js = new JsonSerializer(); 189 js.Serialize(jtw, value); 190 jtw.Flush(); 191 } 192 } 193 194 private static HttpContent CreateHttpContent (T content) 195 { 196 HttpContent httpCOntent= null; 197 if (content != null) 198 { 199 var ms = new MemoryStream(); 200 SerializeJsonIntoStream(content, ms); 201 ms.Seek(0, SeekOrigin.Begin); 202 httpCOntent= new StreamContent(ms); 203 httpContent.Headers.COntentType= new MediaTypeHeaderValue("application/json"); 204 } 205 206 return httpContent; 207 } 208 }
HttpWebRequest封印
1 public class HttpSyncSender 2 { 3 private static readonly int DefaultCOnnectionLimit= 100; 4 private static readonly ILogger Logger = LoggerManager.GetLogger(typeof(HttpSyncSender)); 5 6 static HttpSyncSender() 7 { 8 ServicePointManager.DefaultCOnnectionLimit= DefaultConnectionLimit; 9 ServicePointManager.UseNagleAlgorithm = false; 10 ServicePointManager.MaxServicePointIdleTime = 500 * 1000; 11 } 12 13 public static void SetDefaultConnectionLimit(int connectionLimit) 14 { 15 ServicePointManager.DefaultCOnnectionLimit= connectionLimit; 16 } 17 18 #region 同步 HttpWebRequest 19 20 ///21 /// 同步发送POST请求 默认表单提交方式 22 /// 23 /// T类型 24 /// URL 25 /// POST数据 26 /// 返回值类型:JSON、XML 27 /// 超时时间(单位:毫秒) 28 /// 请求头 29 /// 内容类型 默认"application/x-www-form-urlencoded" 30 /// 来源 31 /// 代理地址 32 /// T类型实例 33 public static T HttpPost (string url, EnumRequestType type, NameValueCollection formData, int timeout, NameValueCollection headers, string cOntentType= "application/x-www-form-urlencoded", string referer = "", string proxyUrl = null) where T : new() 34 { 35 T t = default(T); 36 HttpWebRequest webrequest = null; 37 var headerStr = headers == null ? string.Empty : JsonConvert.SerializeObject(headers); 38 try 39 { 40 webrequest = (HttpWebRequest)WebRequest.Create(url); 41 webrequest.Method = "POST"; 42 webrequest.UserAgent = "Mozilla/5.0 (Windows; U; Windows NT 5.2; zh-CN; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 GTB5"; 43 webrequest.AllowAutoRedirect = true; 44 webrequest.Timeout = timeout; 45 SetRequest(webrequest, true, proxyUrl); 46 47 if (headers != null) 48 { 49 foreach (var item in headers.Keys) 50 { 51 webrequest.Headers.Add(item.ToString(), Convert.ToString(headers[item.ToString()])); 52 } 53 } 54 byte[] byteArray = Encoding.UTF8.GetBytes(CreateForm(formData)); 55 webrequest.COntentType= contentType; 56 webrequest.COntentLength= byteArray.Length; 57 if (!string.IsNullOrWhiteSpace(referer)) 58 { 59 webrequest.Referer = referer; 60 } 61 using (var dataStream = webrequest.GetRequestStream()) 62 { 63 dataStream.Write(byteArray, 0, byteArray.Length); 64 } 65 66 using (var webRespOnse= (HttpWebResponse)webrequest.GetResponse()) 67 { 68 using (var resStream = UnzipStream(webResponse)) 69 { 70 var sr = new StreamReader(resStream, Encoding.UTF8); 71 var result = sr.ReadToEnd(); 72 if (webResponse.StatusCode == HttpStatusCode.OK && !string.IsNullOrEmpty(result)) 73 { 74 t = CreateInstance (result, type); 75 } 76 else 77 { 78 Logger.Error($"HttpSyncSender, Post,返回异常:{webResponse.StatusCode} result:{result} ,Url:{url},cotentType:{contentType} formData:{JsonConvert.SerializeObject(formData)},header:{headerStr}"); 79 } 80 sr.Close(); 81 } 82 } 83 84 } 85 catch (Exception ex) 86 { 87 Logger.Error($"HttpSyncSender,Post,Url:{url},cotentType:{contentType} formData:{JsonConvert.SerializeObject(formData)},header:{headerStr} ex:{ex.Message}"); 88 } 89 finally 90 { 91 webrequest?.Abort(); 92 } 93 return t; 94 } 95 96 /// 97 /// 同步发送POST请求 json提交方式 98 /// 99 /// T类型 100 /// URL 101 /// POST数据 102 /// 返回值类型:JSON、XML 103 /// 超时时间(单位:毫秒) 104 /// 请求头 105 /// 来源 106 /// 代理地址 107 /// T类型实例 108 public static T HttpPost (string url, object jsonModel, EnumRequestType type, int timeout, NameValueCollection headers, string referer = "", string proxyUrl = null) where T : new() 109 { 110 T t = default(T); 111 var headerStr = headers == null ? string.Empty : JsonConvert.SerializeObject(headers); 112 if (jsOnModel== null) 113 { 114 return t; 115 } 116 HttpWebRequest webrequest = null; 117 try 118 { 119 webrequest = (HttpWebRequest)WebRequest.Create(url); 120 webrequest.Method = "POST"; 121 webrequest.UserAgent = "Mozilla/5.0 (Windows; U; Windows NT 5.2; zh-CN; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 GTB5"; 122 webrequest.AllowAutoRedirect = true; 123 webrequest.Timeout = timeout; 124 SetRequest(webrequest, true, proxyUrl); 125 126 if (headers != null) 127 { 128 foreach (var item in headers.Keys) 129 { 130 webrequest.Headers.Add(item.ToString(), Convert.ToString(headers[item.ToString()])); 131 } 132 } 133 byte[] byteArray = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(jsonModel)); 134 webrequest.COntentType= "application/json"; 135 webrequest.COntentLength= byteArray.Length; 136 if (!string.IsNullOrWhiteSpace(referer)) 137 { 138 webrequest.Referer = referer; 139 } 140 using (Stream dataStream = webrequest.GetRequestStream()) 141 { 142 dataStream.Write(byteArray, 0, byteArray.Length); 143 } 144 using (var webRespOnse= (HttpWebResponse)webrequest.GetResponse()) 145 { 146 using (var resStream = UnzipStream(webResponse)) 147 { 148 var sr = new StreamReader(resStream, System.Text.Encoding.UTF8); 149 var result = sr.ReadToEnd(); 150 if (webResponse.StatusCode == HttpStatusCode.OK && !string.IsNullOrEmpty(result)) 151 { 152 t = CreateInstance (result, type); 153 } 154 else 155 { 156 Logger.Error($"HttpSyncSender, Post,返回异常:{webResponse.StatusCode} result:{result} ,Url:{url},cotentType:application/json jsonModel:{JsonConvert.SerializeObject(jsonModel)},header:{headerStr}"); 157 } 158 sr.Close(); 159 } 160 } 161 162 } 163 catch (Exception ex) 164 { 165 Logger.Error($"HttpSyncSender, Post,Url:{url},cotentType:application/json jsonModel:{JsonConvert.SerializeObject(jsonModel)},header:{headerStr}", ex); 166 } 167 finally 168 { 169 webrequest?.Abort(); 170 } 171 return t; 172 } 173 174 /// 175 /// 同步发送post请求 文件上传 multipart 176 /// 177 /// 178 /// 179 /// 180 /// 181 /// 182 /// 183 /// 184 /// 185 /// https://docs.microsoft.com/en-us/aspnet/web-api/overview/advanced/sending-html-form-data-part-2 186 /// 187 public static T HttpPost (string url, string[] files, EnumRequestType type, int timeout, NameValueCollection formFields = null, string referer = "", string proxyUrl = null) where T : new() 188 { 189 T t = default(T); 190 HttpWebRequest webrequest = null; 191 if (files == null || files.Length <= 0) 192 { 193 Logger.Error($"HttpPost,multipart Post,Url:{url},files 地址为空"); 194 } 195 var filesStr = JsonConvert.SerializeObject(files); 196 try 197 { 198 var boundary = $"----------------------------{DateTime.Now.Ticks:x}"; 199 webrequest = (HttpWebRequest)WebRequest.Create(url); 200 webrequest.COntentType= "multipart/form-data; boundary=" + boundary; 201 webrequest.Timeout = timeout; 202 webrequest.Method = "POST"; 203 204 var memStream = new MemoryStream(); 205 var boundarybytes = Encoding.ASCII.GetBytes("\r\n--" + boundary + "\r\n"); 206 var endBoundaryBytes = Encoding.ASCII.GetBytes("\r\n--" + boundary + "--"); 207 208 if (formFields != null) 209 { 210 var formdataTemplate = "\r\n--" + boundary + "\r\nContent-Disposition: form-data; name=\"{0}\";\r\n\r\n{1}"; 211 foreach (string key in formFields.Keys) 212 { 213 var formitem = string.Format(formdataTemplate, key, formFields[key]); 214 byte[] formitembytes = Encoding.UTF8.GetBytes(formitem); 215 memStream.Write(formitembytes, 0, formitembytes.Length); 216 } 217 } 218 219 var headerTemplate = "Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\nContent-Type: application/octet-stream\r\n\r\n"; 220 221 foreach (var file in files) 222 { 223 memStream.Write(boundarybytes, 0, boundarybytes.Length); 224 var header = string.Format(headerTemplate, "uplTheFile", t); 225 var headerbytes = Encoding.UTF8.GetBytes(header); 226 227 memStream.Write(headerbytes, 0, headerbytes.Length); 228 229 using (var fileStream = new FileStream(file, FileMode.Open, FileAccess.Read)) 230 { 231 var buffer = new byte[1024]; 232 int bytesRead; 233 while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0) 234 { 235 memStream.Write(buffer, 0, bytesRead); 236 } 237 } 238 } 239 240 memStream.Write(endBoundaryBytes, 0, endBoundaryBytes.Length); 241 webrequest.COntentLength= memStream.Length; 242 243 using (var requestStream = webrequest.GetRequestStream()) 244 { 245 memStream.Position = 0; 246 byte[] tempBuffer = new byte[memStream.Length]; 247 memStream.Read(tempBuffer, 0, tempBuffer.Length); 248 memStream.Close(); 249 requestStream.Write(tempBuffer, 0, tempBuffer.Length); 250 } 251 using (var webRespOnse= (HttpWebResponse)webrequest.GetResponse()) 252 { 253 using (var resStream = UnzipStream(webResponse)) 254 { 255 var sr = new StreamReader(resStream, System.Text.Encoding.UTF8); 256 var result = sr.ReadToEnd(); 257 if (webResponse.StatusCode == HttpStatusCode.OK && !string.IsNullOrEmpty(result)) 258 { 259 t = CreateInstance (result, type); 260 } 261 else 262 { 263 Logger.Error($"HttpSyncSender,multipart Post,返回异常:{webResponse.StatusCode} result:{result} ,Url:{url},Url:{url},header:{filesStr}"); 264 } 265 sr.Close(); 266 } 267 } 268 } 269 catch (Exception ex) 270 { 271 Logger.Error($"HttpSyncSender,multipart Post,Url:{url},header:{filesStr}", ex); 272 } 273 finally 274 { 275 webrequest?.Abort(); 276 } 277 return t; 278 279 } 280 281 /// 282 /// 同步发送GET请求 283 /// 284 /// T类型 285 /// URL 286 /// 请求类型 287 /// 参数 288 /// 超时时间 289 /// 请求头 290 /// 291 /// 代理地址 292 /// T类型实例 293 public static T HttpGet (string url, EnumRequestType type, NameValueCollection parameters, int timeout, NameValueCollection headers, string callback = "", string proxyUrl = null) where T : new() 294 { 295 T t = default(T); 296 HttpWebRequest webrequest = null; 297 var headerStr = headers == null ? string.Empty : JsonConvert.SerializeObject(headers); 298 var parametersStr = parameters == null ? string.Empty : JsonConvert.SerializeObject(parameters); 299 try 300 { 301 webrequest = (HttpWebRequest)WebRequest.Create(CreateUrl(url, parameters)); 302 webrequest.Method = "GET"; 303 webrequest.UserAgent = "Mozilla/5.0 (Windows; U; Windows NT 5.2; zh-CN; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 GTB5"; 304 webrequest.AllowAutoRedirect = true; 305 webrequest.Timeout = timeout; 306 SetRequest(webrequest, false, proxyUrl); 307 308 if (headers != null) 309 { 310 foreach (var item in headers.Keys) 311 { 312 webrequest.Headers.Add(item.ToString(), Convert.ToString(headers[item.ToString()])); 313 } 314 } 315 using (var webRespOnse= (HttpWebResponse)webrequest.GetResponse()) 316 { 317 using (Stream resStream = UnzipStream(webResponse)) 318 { 319 string result; 320 using (var sr = new StreamReader(resStream, Encoding.UTF8)) 321 { 322 result = sr.ReadToEnd(); 323 } 324 if (webResponse.StatusCode == HttpStatusCode.OK && !string.IsNullOrEmpty(result)) 325 { 326 if (!string.IsNullOrEmpty(callback)) 327 { 328 result = result.TrimStart((callback + "(").ToCharArray()).TrimEnd(')'); 329 } 330 t = CreateInstance (result, type); 331 } 332 else 333 { 334 335 Logger.Error($"HttpSyncSender, Get,返回异常:{webResponse.StatusCode} result:{result} Url:{url},parameters:{parametersStr},header:{headerStr}"); 336 } 337 } 338 } 339 340 } 341 catch (JsonSerializationException je) 342 { 343 Logger.Error($"HttpSyncSender,Get JsonSerializationException,Url:{url},parameters:{parametersStr},header:{headerStr},je:{je.Message}"); 344 throw; 345 } 346 catch (Exception ex) 347 { 348 Logger.Error($"HttpSyncSender, Get,Url:{url},parameters:{parametersStr},header:{headerStr} ex:{ex.Message}"); 349 throw; 350 } 351 finally 352 { 353 webrequest?.Abort(); 354 } 355 return t; 356 } 357 358 private static void SetRequest(HttpWebRequest httpWebRequest, bool post, string proxyUrl = null) 359 { 360 httpWebRequest.MaximumAutomaticRedirectiOns= 3; 361 httpWebRequest.Headers.Add(HttpRequestHeader.AcceptEncoding, "gzip,deflate"); 362 httpWebRequest.KeepAlive = true; 363 httpWebRequest.AllowWriteStreamBuffering = false; 364 if (!string.IsNullOrWhiteSpace(proxyUrl)) 365 { 366 httpWebRequest.Proxy = new WebProxy(proxyUrl); 367 } 368 if (post) 369 { 370 //post 较大数据 先进行一次握手,避免资源浪费 371 httpWebRequest.ServicePoint.Expect100COntinue= false; 372 } 373 } 374 375 private static Stream UnzipStream(HttpWebResponse httpResponse) 376 { 377 var resStream = httpResponse.GetResponseStream(); 378 if (httpResponse.ContentEncoding.ToLower().Contains("gzip")) 379 { 380 return new GZipStream(resStream, CompressionMode.Decompress); 381 } 382 if (httpResponse.ContentEncoding.ToLower().Contains("deflate")) 383 { 384 return new DeflateStream(resStream, CompressionMode.Decompress); 385 } 386 return resStream; 387 } 388 389 private static T CreateInstance (string text, EnumRequestType type) where T : new() 390 { 391 T t = default(T); 392 if (!string.IsNullOrEmpty(text)) 393 { 394 if (type == EnumRequestType.Json) 395 { 396 t = JsonConvert.DeserializeObject (text); 397 } 398 else 399 { 400 using (Stream stream = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(text))) 401 { 402 XElement element = XElement.Load(stream); 403 if (element != null) 404 { 405 t = new T(); 406 foreach (var item in t.GetType().GetProperties()) 407 { 408 var ele = element.Descendants().SingleOrDefault(c => c.Name.LocalName.ToLower() == item.Name.ToLower()); 409 if (ele != null && !string.IsNullOrEmpty(ele.Value)) 410 { 411 item.SetValue(t, Convert.ChangeType(ele.Value, item.PropertyType), null); 412 } 413 } 414 } 415 } 416 } 417 } 418 return t; 419 } 420 421 private static string CreateUrl(string url, NameValueCollection parameters) 422 { 423 string result = string.Empty; 424 if (!string.IsNullOrEmpty(url)) 425 { 426 result = url; 427 if (parameters != null && parameters.Count > 0) 428 { 429 430 foreach (string key in parameters.Keys) 431 { 432 if (result.IndexOf("?") > -1) 433 { 434 result += "&" + key + "=" + parameters[key]; 435 } 436 else 437 { 438 result += "?" + key + "=" + parameters[key]; 439 } 440 } 441 } 442 } 443 return result; 444 } 445 446 private static string CreateForm(NameValueCollection parameters) 447 { 448 string _form = string.Empty; 449 if (parameters != null && parameters.Count > 0) 450 { 451 foreach (string key in parameters.Keys) 452 { 453 _form += key + "=" + parameters[key] + "&"; 454 } 455 _form = _form.TrimEnd('&'); 456 } 457 return _form; 458 } 459 460 #endregion 461 }