天天看點

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避免緩存問題,這也實在是一個沒有辦法的辦法,希望微軟在下一個版本中能夠改善這個問題。

繼續閱讀