WebClient实际上是一个在HttpWebRequest之上的库,它的主要优点就是使用起来比较简单,但是它有两个致命缺陷,一是程序的回调在UI线程执行,会导致程序性能下降。另外一个,他没有实现本地缓存的控制策略。
那么HttpWebRequest呢,虽然它仍然无法支持GET方法下的本地缓存策略控制,但是它的性能实在是要好的太多,而且由于HttpWebRequest是个比WebClient更低级的库,你可以更好的对传输进行控制,所以我强烈推荐大家用HttpWebRequest,至少在微软对WebClient进行了改善之前是这样。
应为HttpWebRequest的异步回调函数会在自己的线程中执行,所以随之而来会带来一个问题,就是跨线程调用问题,这个问题可以通过这个方式,调用:
System.Windows.Deployment.Current.Dispatcher.BeginInvoke方法来在主线程中执行代码,这样就可以解决这个问题,并且我们可以通过封装HttpWebRequest来得到一个与WebClient使用方法类似的新类,下面我就把在项目中实现的这个类的代码给大家看看
publicclass DownloadStringCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs
{
public DownloadStringCompletedEventArgs(string result, bool cancelled, Exception error, object userState)
: base(error, cancelled, userState)
{
Result = result;
}
publicstring Result
{
get;
privateset;
}
}
publicclass OpenReadCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs
{
public OpenReadCompletedEventArgs(Stream result,bool cancelled,Exception error,object userState)
: base(error, cancelled, userState)
{
Result = result;
}
public Stream Result
{
get;
privateset;
}
}
publicdelegatevoid DownloadStringCompletedEventHandler(Object sender, DownloadStringCompletedEventArgs e);
publicdelegatevoid OpenReadCompletedEventHandler(object sender, OpenReadCompletedEventArgs e);
publicclass NoCacheWebClient
{
HttpWebRequest _webRequest = null;
privatestring _result = "";
privatebyte[] _buffer;
constint BUFFER_SIZE = 1024;
MemoryStream _memStream = null;
object _userToken = null;
staticstring cache = Guid.NewGuid().ToString();
public NoCacheWebClient()
{
_buffer = newbyte[BUFFER_SIZE];
Encoding = Encoding.UTF8;
_memStream = new MemoryStream();
}
publicevent DownloadStringCompletedEventHandler DownloadStringCompleted;
publicevent OpenReadCompletedEventHandler OpenReadCompleted;
publicvoid CancelAsync()
{
if (_webRequest != null)
{
_webRequest.Abort();
_result = "";
_userToken = null;
}
}
public Encoding Encoding
{
get;
set;
}
private Uri RequestUri
{
set;
get;
}
publicvoid OpenReadAsync(Uri address)
{
RequestUri = address;
_webRequest = (HttpWebRequest)HttpWebRequest.Create(address.AbsoluteUri);
_webRequest.BeginGetResponse(StreamRespCallback, null);
}
privatevoid StreamRespCallback(IAsyncResult asynchronousResult)
{
try
{
HttpWebResponse response = (HttpWebResponse)_webRequest.EndGetResponse(asynchronousResult);
Stream responseStream = response.GetResponseStream();
if (OpenReadCompleted != null)
{
System.Windows.Deployment.Current.Dispatcher.BeginInvoke(OpenReadCompleted, newobject[] { this, new OpenReadCompletedEventArgs(responseStream, false, null, _userToken) });
}
}
catch (WebException e)
{
string message = e.Message;
}
}
publicvoid DownloadStringAsync(Uri address)
{
_result = "";
_memStream = new MemoryStream();
string cacheValue = "";
if (address.Query.Length == 0)
{
cacheValue = "?Cache=" + cache;
}
else
{
cacheValue = "&Cache=" + cache;
}
Uri newAddress = new Uri(address.AbsoluteUri + cacheValue, UriKind.RelativeOrAbsolute);
RequestUri = newAddress;
_webRequest = (HttpWebRequest)HttpWebRequest.Create(newAddress.AbsoluteUri);
_webRequest.BeginGetResponse(RespCallback, null);
}
publicvoid DownloadStringAsync(Uri address,object userToken)
{
_result = "";
_userToken = userToken;
_memStream = new MemoryStream();
string cacheValue = "";
if (address.Query.Length == 0)
{
cacheValue = "?Cache=" + cache;
}
else
{
cacheValue = "&Cache=" + cache;
}
Uri newAddress = new Uri(address.AbsoluteUri + cacheValue, UriKind.RelativeOrAbsolute);
RequestUri = newAddress;
_webRequest = (HttpWebRequest)HttpWebRequest.Create(newAddress.AbsoluteUri);
_webRequest.BeginGetResponse(RespCallback, userToken);
}
privatevoid RespCallback(IAsyncResult asynchronousResult)
{
try
{
HttpWebResponse response = (HttpWebResponse)_webRequest.EndGetResponse(asynchronousResult);
Stream responseStream = response.GetResponseStream();
responseStream.BeginRead(_buffer, 0, BUFFER_SIZE, new AsyncCallback(ReadCallback), responseStream);
}
catch (WebException e)
{
string message = e.Message;
}
}
privatevoid ReadCallback(IAsyncResult asyncResult)
{
try
{
Stream stream = (Stream)asyncResult.AsyncState;
int read = stream.EndRead(asyncResult);
if (read > 0)
{
_memStream.Write(_buffer, 0, read);
stream.BeginRead(_buffer, 0, BUFFER_SIZE, new AsyncCallback(ReadCallback), stream);
}
else
{
_result = Encoding.GetString(_memStream.ToArray(), 0, (int)_memStream.Length);
stream.Close();
_memStream.Close();
if (DownloadStringCompleted != null)
{
System.Windows.Deployment.Current.Dispatcher.BeginInvoke(DownloadStringCompleted, newobject[] { this, new DownloadStringCompletedEventArgs(_result, false, null, _userToken) });
}
}
}
catch (System.Exception ex)
{
string message = ex.Message;
}
}
privatevoid WriteCallBack(IAsyncResult asyncResult)
{
try
{
_memStream.EndWrite(asyncResult);
Stream stream = (Stream)asyncResult.AsyncState;
stream.BeginRead(_buffer, 0, BUFFER_SIZE, new AsyncCallback(ReadCallback), stream);
}
catch (System.Exception ex)
{
string message = ex.Message;
}
}
}
public class DownloadStringCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { public DownloadStringCompletedEventArgs(string result, bool cancelled, Exception error, object userState) : base(error, cancelled, userState) { Result = result; } public string Result { get; private set; } } public class OpenReadCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { public OpenReadCompletedEventArgs(Stream result,bool cancelled,Exception error,object userState) : base(error, cancelled, userState) { Result = result; } public Stream Result { get; private set; } } public delegate void DownloadStringCompletedEventHandler(Object sender, DownloadStringCompletedEventArgs e); public delegate void OpenReadCompletedEventHandler(object sender, OpenReadCompletedEventArgs e); public class NoCacheWebClient { HttpWebRequest _webRequest = null; private string _result = ""; private byte[] _buffer; const int BUFFER_SIZE = 1024; MemoryStream _memStream = null; object _userToken = null; static string cache = Guid.NewGuid().ToString(); public NoCacheWebClient() { _buffer = new byte[BUFFER_SIZE]; Encoding = Encoding.UTF8; _memStream = new MemoryStream(); } public event DownloadStringCompletedEventHandler DownloadStringCompleted; public event OpenReadCompletedEventHandler OpenReadCompleted; public void CancelAsync() { if (_webRequest != null) { _webRequest.Abort(); _result = ""; _userToken = null; } } public Encoding Encoding { get; set; } private Uri RequestUri { set; get; } public void OpenReadAsync(Uri address) { RequestUri = address; _webRequest = (HttpWebRequest)HttpWebRequest.Create(address.AbsoluteUri); _webRequest.BeginGetResponse(StreamRespCallback, null); } private void StreamRespCallback(IAsyncResult asynchronousResult) { try { HttpWebResponse response = (HttpWebResponse)_webRequest.EndGetResponse(asynchronousResult); Stream responseStream = response.GetResponseStream(); if (OpenReadCompleted != null) { System.Windows.Deployment.Current.Dispatcher.BeginInvoke(OpenReadCompleted, new object[] { this, new OpenReadCompletedEventArgs(responseStream, false, null, _userToken) }); } } catch (WebException e) { string message = e.Message; } } public void DownloadStringAsync(Uri address) { _result = ""; _memStream = new MemoryStream(); string cacheValue = ""; if (address.Query.Length == 0) { cacheValue = "?Cache=" + cache; } else { cacheValue = "&Cache=" + cache; } Uri newAddress = new Uri(address.AbsoluteUri + cacheValue, UriKind.RelativeOrAbsolute); RequestUri = newAddress; _webRequest = (HttpWebRequest)HttpWebRequest.Create(newAddress.AbsoluteUri); _webRequest.BeginGetResponse(RespCallback, null); } public void DownloadStringAsync(Uri address,object userToken) { _result = ""; _userToken = userToken; _memStream = new MemoryStream(); string cacheValue = ""; if (address.Query.Length == 0) { cacheValue = "?Cache=" + cache; } else { cacheValue = "&Cache=" + cache; } Uri newAddress = new Uri(address.AbsoluteUri + cacheValue, UriKind.RelativeOrAbsolute); RequestUri = newAddress; _webRequest = (HttpWebRequest)HttpWebRequest.Create(newAddress.AbsoluteUri); _webRequest.BeginGetResponse(RespCallback, userToken); } private void RespCallback(IAsyncResult asynchronousResult) { try { HttpWebResponse response = (HttpWebResponse)_webRequest.EndGetResponse(asynchronousResult); Stream responseStream = response.GetResponseStream(); responseStream.BeginRead(_buffer, 0, BUFFER_SIZE, new AsyncCallback(ReadCallback), responseStream); } catch (WebException e) { string message = e.Message; } } private void ReadCallback(IAsyncResult asyncResult) { try { Stream stream = (Stream)asyncResult.AsyncState; int read = stream.EndRead(asyncResult); if (read > 0) { _memStream.Write(_buffer, 0, read); stream.BeginRead(_buffer, 0, BUFFER_SIZE, new AsyncCallback(ReadCallback), stream); } else { _result = Encoding.GetString(_memStream.ToArray(), 0, (int)_memStream.Length); stream.Close(); _memStream.Close(); if (DownloadStringCompleted != null) { System.Windows.Deployment.Current.Dispatcher.BeginInvoke(DownloadStringCompleted, new object[] { this, new DownloadStringCompletedEventArgs(_result, false, null, _userToken) }); } } } catch (System.Exception ex) { string message = ex.Message; } } private void WriteCallBack(IAsyncResult asyncResult) { try { _memStream.EndWrite(asyncResult); Stream stream = (Stream)asyncResult.AsyncState; stream.BeginRead(_buffer, 0, BUFFER_SIZE, new AsyncCallback(ReadCallback), stream); } catch (System.Exception ex) { string message = ex.Message; } } }
这个类的使用方法基本与WebClient类似,当然我只实现了部分函数和属性,而且这个程序会通过设置guid来强制刷新url避免缓存问题,这也实在是一个没有办法的办法,希望微软在下一个版本中能够改善这个问题。
http://blog.csdn.net/oldmanzhao/article/details/7294697