天天看点

Windows Phone 7 的Http网络库使用技巧

 WebClient实际上是一个在HttpWebRequest之上的库,它的主要优点就是使用起来比较简单,但是它有两个致命缺陷,一是程序的回调在UI线程执行,会导致程序性能下降。另外一个,他没有实现本地缓存的控制策略。

   那么HttpWebRequest呢,虽然它仍然无法支持GET方法下的本地缓存策略控制,但是它的性能实在是要好的太多,而且由于HttpWebRequest是个比WebClient更低级的库,你可以更好的对传输进行控制,所以我强烈推荐大家用HttpWebRequest,至少在微软对WebClient进行了改善之前是这样。

   应为HttpWebRequest的异步回调函数会在自己的线程中执行,所以随之而来会带来一个问题,就是跨线程调用问题,这个问题可以通过这个方式,调用:

System.Windows.Deployment.Current.Dispatcher.BeginInvoke方法来在主线程中执行代码,这样就可以解决这个问题,并且我们可以通过封装HttpWebRequest来得到一个与WebClient使用方法类似的新类,下面我就把在项目中实现的这个类的代码给大家看看

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避免缓存问题,这也实在是一个没有办法的办法,希望微软在下一个版本中能够改善这个问题。

继续阅读