【WP8.1】HttpClient网络请求、进度以及终止

工作这么长时间,起初还是喜欢用面向程序过程的思路去写代码。

慢慢的才会用面向对象的思路分析、解决问题。也算是一点点进步吧。

最近在做一个下载音乐的功能。用到了HttpClient类。

于是就简单的写了一个文件处理类。主要实现了Get请求,Post还很不完善(Post看到过别人写的很不错的类,以后会贴出)。

还有能够实时的显示下载进度,中断下载。

贴出代码,在代码里解释:

    public class HttpRequest
    {
        #region Instance Field

        private readonly string _url;  //请求的url  
        private readonly string _body;  //Post/Get时的数据
        private HttpClient _httpClient;  
        private CancellationTokenSource _cts;  //用于取消请求
        private IProgress<HttpProgress> _httpProgressDownload;  //用于下载进度
        private IProgress<HttpProgress> _httpProgressUpload;
        private double progressUpload = 0;
        private double progressDownload = 0;  //下载进度

        #endregion
        
        #region Delegates
     
        public delegate void OnFailedEventHandle(string error, WebExceptionStatus status);
        public delegate void OnSucceedEventHandle(InMemoryRandomAccessStream randomAccessStream);
        public delegate void OnCancelEventHandle(string message);
        public delegate void OnProgressChangedEventHandle(double progress);

        #endregion

        #region Events
     //事件  分别用来处理获取失败、成功、取消、进度信息
        public event OnFailedEventHandle FailedEvent;
        public event OnSucceedEventHandle SucceedEvent;
        public event OnCancelEventHandle CancelEvent;
        public event OnProgressChangedEventHandle ProgressChangedEvent;

        #endregion
      //构造函数
        public HttpRequest(string url, string body = null)
        {
            this._url = url;
            this._body = body;
            _httpClient = new HttpClient();
            _cts = new CancellationTokenSource();
        }
     //开始运行 
public void Run() { DoHttpClientRequest(); }      public async void DoHttpClientRequest() {
       //根据是否存在body判断是Get请求还是Post请求 RequestType method
= string.IsNullOrEmpty(_body) ? RequestType.Get : RequestType.Post; var request = CreateHttp(_url, method); if (_httpClient != null) { try { HttpResponseMessage response = null; if (method == RequestType.Post) { //POST //_httpProgressUpload = new Progress<HttpProcess>(ProgressUploadHandler); //response = await _httpClient.SendRequestAsync(request).AsTask(_cts.Token, _progressUpload); response = await _httpClient.SendRequestAsync(request).AsTask(_cts.Token); } else if (method == RequestType.Get) { //GET
              //下载进度状态信息 _httpProgressDownload = new Progress<HttpProgress>(ProgressDownloadHandler);  try { response = await _httpClient.SendRequestAsync(request).AsTask(_cts.Token, _httpProgressDownload); //HttpCompletionOption.ResponseHeadersRead多了这个参数    在接受到头之后完成。  于是就不继续进行了
                           //response = await _httpClient.SendRequestAsync(request, HttpCompletionOption.ResponseHeadersRead).AsTask(_cts.Token, _httpProgressDownload);

                 _cts.Token.ThrowIfCancellationRequested();                 
                 //处理流
using (Stream responseStream = (await response.Content.ReadAsInputStreamAsync()).AsStreamForRead()) { //将Stream转换为IRandomAccessStream var randomAccessStream = new InMemoryRandomAccessStream(); var outputStream = randomAccessStream.GetOutputStreamAt(0); await RandomAccessStream.CopyAsync(responseStream.AsInputStream(), outputStream); if (randomAccessStream != null) { if (SucceedEvent != null) SucceedEvent(randomAccessStream); //获取到源的回调方法,并返回获取的内容 } } }
               //中断Task时候会抛出异常,所以要通过try catch这种方法来获取是否终止。
catch (TaskCanceledException) { //请求被取消 CancelEvent("下载已停止"); } } } catch (WebException e) { FailedEvent(e.Message, e.Status); } } } public HttpRequestMessage CreateHttp(string url, RequestType type = RequestType.Get) { HttpRequestMessage request = null; try { if (type == RequestType.Get) { request = new HttpRequestMessage(HttpMethod.Get, new Uri(url, UriKind.Absolute)); } else { request = new HttpRequestMessage(HttpMethod.Post, new Uri(url, UriKind.Absolute)); request.Content = SetPostContent(this._body); }
          SetHeaders();
} catch (WebException e) { FailedEvent(e.Message, e.Status); } return request; }
     //Post请求内容
public HttpStreamContent SetPostContent(string body) { byte[] subData = new byte[body.Length]; MemoryStream stream = new MemoryStream(subData); HttpStreamContent streamContent = new HttpStreamContent(stream.AsInputStream()); return streamContent; }
     public void SetHeaders()
        {
           
//略
        }      public void ProgressDownloadHandler(HttpProgress progress) {
       //处理进度 包括了很多状态 如ConnectingToServerWaitingForResponse等
string infoState = progress.Stage.ToString(); double totalByteToRecive = 0; if (progress.TotalBytesToSend.HasValue) { //要发送的数据 } if (progress.TotalBytesToReceive.HasValue) { //接收数据 获取总接收数据 totalByteToRecive = progress.TotalBytesToReceive.Value; } if (progress.Stage == HttpProgressStage.ReceivingContent) { progressUpload = progress.BytesReceived / totalByteToRecive; if (ProgressChangedEvent != null) { ProgressChangedEvent(progressUpload * 100); } } } public void Cancel() { if (_cts.Token.CanBeCanceled) {
          //取消请求并且释放资源 _cts.Cancel(); _cts.Dispose(); } } }    //枚举变量 来判断是Get请求还是Post请求
public enum RequestType { Post, Get }

 后台代码:

 1        url = "http://mxd.766.com/sdo/music/data/1/m1.mp3"
 2        HttpRequest httpRequest = new HttpRequest(url);
 3 
 4             httpRequest.Run();
 5             httpRequest.SucceedEvent += async (result) =>
 6             {
 7                 try
 8                 {
 9                     await this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
10                         {
11                             //设置源
12                             MediaControl.SetDownloadSource(result);
13                         });
14                 }
15                 catch(Exception e)
16                 {
17                     
18                 }
19           //保存文件到音乐
20                 IBuffer buffer = new Windows.Storage.Streams.Buffer((uint)result.Size);
21                 await result.ReadAsync(buffer, (uint)result.Size, InputStreamOptions.None);
22                 await StorageHelper.SaveToStorage(this.Classify.Name, selectItem.Name + ".mp3", buffer);
23 
24                 CommonHelper.ShowToast(selectItem.Name +  ".mp3 下载成功");
25             };
26             httpRequest.FailedEvent += async (ss, ee) =>
27             {
28                 await new MessageDialog("获取音乐失败").ShowAsync();
29             };
30             httpRequest.CancelEvent += async (ss1) =>
31             {
32                 await new MessageDialog(ss1).ShowAsync();
33             };
34             httpRequest.ProgressChangedEvent += (progress) =>
35             {
36                 selectItem.DownProgress = progress;
37           //progress去绑定对象,就能够实时的显示进度
38             };

这样就能够实现下载、中断了。    我发现,在中断后再点击下载,进度条还是会接着走的。  

这里并没有主动的去实现续传。


注:HttpClient类发起的网络请求都是基于任务的异步方法,所以要取消其异步的操作可以通过异步任务的取消对象CancellationTokenSource对象来取消。

如果使用CancellationTokenSource对象来取消异步的请求会触发TaskCanceledException异常,这个异常需要我们用try
catch语句来捕获,便可以识别到请求是被取消的。

posted @ 2015-08-11 11:26  汪小饭  阅读(1930)  评论(0编辑  收藏  举报