相信大家对HttpWebRequest这个类应该非常熟悉了吧。主要用它来模拟http请求,在有些时候我们需要用到它的异步处理,每次用的时候都要写很多代码,于是今天把它简单的封装了一下。虽然在C#4和C#5中它提供了很新方法是的异步更加简单,但是在一些老项目(还在用vs2005)上我们只能用C#2.0的语法来实现它的异步功能。
如图1,这里的RequestInfo类是请求信息的一个封装,ResponseInfo类是返回对象的一个封装,StateObject是一个内部状态保存对象类(我们不需要关心),RequestHttpWebRequest是HttpWebRequest的一个封装类,只有一个公共方法:
public void GetResponseAsync(RequestInfo info, Action<ResponseInfo> act)
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Data;
using System.Data.OleDb;
using System.Net;
using System.Xml;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
[Serializable]
public class RequestInfo
{
public RequestInfo(string url)
{
Url = url;
AllowAutoRedirect = true;
}
public string Url { set; get; }
public byte[] PostData { set; get; }
public WebHeaderCollection Headers { set; get; }
public bool AllowAutoRedirect { set; get; }
public Dictionary<string, string> ExternalData { set; get; }
}
[Serializable]
public class ResponseInfo
{
public RequestInfo RequestInfo { set; get; }
public Stream ResponseContent { set; get; }
public HttpStatusCode StatusCode { set; get; }
public WebHeaderCollection Headers { set; get; }
public string GetString(Encoding coding)
{
StringBuilder str = new StringBuilder();
Stream sr = ResponseContent;
sr.Seek(0, SeekOrigin.Begin);
byte[] data = new byte[1024 * 1024];
int readcount = sr.Read(data, 0, data.Length);
while (readcount > 0)
{
str.Append(coding.GetString(data, 0, readcount));
readcount = sr.Read(data, 0, data.Length);
}
return str.ToString();
}
}
internal class StateObject
{
public byte[] Buffer { set; get; }
public ResponseInfo ResponseInfo { set; get; }
public Stream ReadStream { set; get; }
public HttpWebRequest HttpWebRequest { set; get; }
public Action<ResponseInfo> Action { set; get; }
}
public class RequestHttpWebRequest
{
static RequestHttpWebRequest()
{
ServicePointManager.DefaultConnectionLimit = 100;
}
public RequestHttpWebRequest()
{
ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CheckValidationResult);
}
private bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)
{
//直接确认,否则打不开
return true;
}
public void GetResponseAsync(RequestInfo info, Action<ResponseInfo> act)
{
HttpWebRequest webRequest;
StateObject state;
InitWebRequest(info, act, out webRequest, out state);
try
{
if (info.PostData != null && info.PostData.Length > 0)
{
webRequest.Method = "POST";
webRequest.ContentType = "application/x-www-form-urlencoded";
webRequest.BeginGetRequestStream(EndRequest, state);
}
else
{
webRequest.BeginGetResponse(EndResponse, state);
}
}
catch (Exception ex)
{
HandException(ex, state);
}
}
void EndRequest(IAsyncResult ar)
{
StateObject state = ar.AsyncState as StateObject;
try
{
HttpWebRequest webRequest = state.HttpWebRequest as HttpWebRequest;
using (Stream stream = webRequest.EndGetRequestStream(ar))
{
byte[] data = state.ResponseInfo.RequestInfo.PostData;
stream.Write(data, 0, data.Length);
}
webRequest.BeginGetResponse(EndResponse, state);
}
catch (Exception ex)
{
HandException(ex, state);
}
}
void EndResponse(IAsyncResult ar)
{
StateObject state = ar.AsyncState as StateObject;
try
{
HttpWebResponse webResponse = state.HttpWebRequest.EndGetResponse(ar) as HttpWebResponse;
state.ResponseInfo.StatusCode = webResponse.StatusCode;
state.ResponseInfo.Headers = new WebHeaderCollection();
foreach (string key in webResponse.Headers.AllKeys)
{
state.ResponseInfo.Headers.Add(key, webResponse.Headers[key]);
}
state.ReadStream = webResponse.GetResponseStream();
state.ReadStream.BeginRead(state.Buffer, 0, state.Buffer.Length, ReadCallBack, state);
}
catch (Exception ex)
{
HandException(ex, state);
}
}
void ReadCallBack(IAsyncResult ar)
{
StateObject state = ar.AsyncState as StateObject;
try
{
int read = state.ReadStream.EndRead(ar);
if (read > 0)
{
state.ResponseInfo.ResponseContent.Write(state.Buffer, 0, read);
state.ReadStream.BeginRead(state.Buffer, 0, state.Buffer.Length, ReadCallBack, state);
}
else
{
state.ReadStream.Close();
state.HttpWebRequest.Abort();
if (state.Action != null)
{
state.Action(state.ResponseInfo);
}
}
}
catch (Exception ex)
{
HandException(ex, state);
}
}
private void InitWebRequest(RequestInfo info, Action<ResponseInfo> act, out HttpWebRequest webRequest, out StateObject state)
{
webRequest = HttpWebRequest.CreateDefault(new Uri(info.Url)) as HttpWebRequest;
webRequest.KeepAlive = true;
webRequest.AllowAutoRedirect = info.AllowAutoRedirect;
if (info.Headers != null && info.Headers.Count > 0)
{
foreach (string key in info.Headers.Keys)
{
webRequest.Headers.Add(key, info.Headers[key]);
}
}
//webRequest.Proxy = WebProxy.GetDefaultProxy();
//webRequest.Proxy.Credentials = CredentialCache.DefaultCredentials;
// webResponse.Headers.Get("Set-Cookie");
state = new StateObject
{
Buffer = new byte[1024 * 1024],
HttpWebRequest = webRequest,
Action = act,
ResponseInfo = new ResponseInfo
{
RequestInfo = info,
ResponseContent = new MemoryStream()
}
};
}
private void HandException(Exception ex, StateObject state)
{
string message = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + " : " + state.ResponseInfo.RequestInfo.Url + " : " + ex.Message;
Console.WriteLine(message);
}
}
这里的几个类及其属性都很好明白,我就不说了。只是大家要注意一点的是ResponseInfo中ResponseContent属性是服务器返回的数据流,这里它是一个MemoryStream对象。
说说简单的调用吧
整个调用是不是很简单啊!有不对的地方欢迎大家拍砖!