【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 = ;
private double progressDownload = ; //下载进度 #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();
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)
{
//处理进度 包括了很多状态 如ConnectingToServer、WaitingForResponse等
string infoState = progress.Stage.ToString();
double totalByteToRecive = ;
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 * );
}
}
} public void Cancel()
{
if (_cts.Token.CanBeCanceled)
{
//取消请求并且释放资源
_cts.Cancel();
_cts.Dispose();
}
}
}
//枚举变量 来判断是Get请求还是Post请求
public enum RequestType
{
Post,
Get
}
后台代码:
url = "http://mxd.766.com/sdo/music/data/1/m1.mp3"
HttpRequest httpRequest = new HttpRequest(url); httpRequest.Run();
httpRequest.SucceedEvent += async (result) =>
{
try
{
await this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
//设置源
MediaControl.SetDownloadSource(result);
});
}
catch(Exception e)
{ }
//保存文件到音乐
IBuffer buffer = new Windows.Storage.Streams.Buffer((uint)result.Size);
await result.ReadAsync(buffer, (uint)result.Size, InputStreamOptions.None);
await StorageHelper.SaveToStorage(this.Classify.Name, selectItem.Name + ".mp3", buffer); CommonHelper.ShowToast(selectItem.Name + ".mp3 下载成功");
};
httpRequest.FailedEvent += async (ss, ee) =>
{
await new MessageDialog("获取音乐失败").ShowAsync();
};
httpRequest.CancelEvent += async (ss1) =>
{
await new MessageDialog(ss1).ShowAsync();
};
httpRequest.ProgressChangedEvent += (progress) =>
{
selectItem.DownProgress = progress;
//progress去绑定对象,就能够实时的显示进度
};
这样就能够实现下载、中断了。 我发现,在中断后再点击下载,进度条还是会接着走的。
这里并没有主动的去实现续传。
注:HttpClient类发起的网络请求都是基于任务的异步方法,所以要取消其异步的操作可以通过异步任务的取消对象CancellationTokenSource对象来取消。
如果使用CancellationTokenSource对象来取消异步的请求会触发TaskCanceledException异常,这个异常需要我们用try
catch语句来捕获,便可以识别到请求是被取消的。
【WP8.1】HttpClient网络请求、进度以及终止的更多相关文章
- [深入浅出WP8.1(Runtime)]网络编程之HttpClient类
12.2 网络编程之HttpClient类 除了可以使用HttpWebRequest类来实现HTTP网络请求之外,我们还可以使用HttpClient类来实现.对于基本的请求操作,HttpClient类 ...
- Flutter -------- 网络请求之HttpClient
今天来说说Flutter中的网络请求,HttpClient网络请求,包含get,post get var data; _get() async { Map newTitle; var response ...
- android4.0 HttpClient 以后不能在主线程发起网络请求
android4.0以后不能在主线程发起网络请求,该异步网络请求. new Thread(new Runnable() { @Override public void run() { // TODO ...
- Android之三种网络请求解析数据(最佳案例)
AsyncTask解析数据 AsyncTask主要用来更新UI线程,比较耗时的操作可以在AsyncTask中使用. AsyncTask是个抽象类,使用时需要继承这个类,然后调用execute()方法. ...
- iOS - Alamofire 网络请求
前言 Alamofire 是 Swift 语言的 HTTP 网络开发工具包,相当于 Swift 实现 AFNetworking 版本.当然,AFNetworking 非常稳定,在 Mac OSX 与 ...
- Swift基础之使用Alamofire库进行网络请求和断点下载
好久没有写过Swift相关的文章博客了,这里我就展示一下关于使用Alamofire库的方法 1.什么是Alamofire (1)Alamofire 的前身是 AFNetworking.AFNetwor ...
- ASI与AFN网络请求的的比较
对比 ASI AFN 更新状态 2012年10月份,已经停止更新 持续更新中,目前已更新至3.0版 介绍 ASI的直接操作对象ASIHTTPRequest,是一个实现了了NSCopying协议的NSO ...
- 网络请求及各类错误代码含义总结(包含AFN错误码大全)
碰见一个很奇葩的问题, 某些手机在设置了不知什么后, 某些 APP 死活 HTTPS 请求失败, 例如以 UMeng 统计HTTP 请求失败为例, Log如下: UMLOG: (Error App ...
- XDroidRequest网络请求框架,新开源
XDroidRequest 是一款网络请求框架,它的功能也许会适合你.这是本项目的第三版了,前两版由于扩展性问题一直不满意,思考来 思考去还是觉得Google的Volley的扩展性最强,于是借鉴了Vo ...
随机推荐
- zabbix-3.0.3 mysql表分区的方法
目的:解决mysql空间越来越大,mysql性能出现瓶颈,zabbix会无端出现大量agent超时报警 中间遇到一个mysql问题:5.1版本的mysql不支持分表(其实是支持的,需要重新编译mysq ...
- PHP求职宝典系列——PHP Web 编程篇
PHP Web 编程篇 form表单 1.简述 POST 和 GET 传输的最大容量分别是多少? GET 方法提交的表单数据被附加到 URL 上,并作为URL 的一部分发送到服务器端. URL 的长度 ...
- Linux网络编程-IO复用技术
IO复用是Linux中的IO模型之一,IO复用就是进程预先告诉内核需要监视的IO条件,使得内核一旦发现进程指定的一个或多个IO条件就绪,就通过进程进程处理,从而不会在单个IO上阻塞了.Linux中,提 ...
- POJ2104 K-th Number [分块做法]
传送:主席树做法http://www.cnblogs.com/candy99/p/6160704.html 做那倒带修改的主席树时就发现分块可以做,然后就试了试 思想和教主的魔法差不多,只不过那个是求 ...
- 扩大ubuntu虚拟机硬盘空间
一.背景: 出于测试的需要,在ubuntu 14.04系统中通过virtualbox虚拟机安装了额ubuntu 14.04系统(guest os).安装过程采用ubuntu 14.04的默认分区方法. ...
- [LeetCode] Maximum Product of Word Lengths 单词长度的最大积
Given a string array words, find the maximum value of length(word[i]) * length(word[j]) where the tw ...
- 动态生成验证码———MVC版
上面有篇博客也是写的验证码,但那个是适用于asp.net网站的. 今天想在MVC中实现验证码功能,弄了好久,最后还是看博友文章解决的,感谢那位博友. 首先引入生成验证码帮助类. ValidateCod ...
- go 常用包
标准的 Go 代码库中包含了大量的包,并且在安装 Go 的时候多数会伴随一起安 装.浏览 $GOROOT/src/pkg 目录并且查看那些包会非常有启发. fmt:包 fmt 实现了格式化的 I/O ...
- Can't find any matching row in the user table
原因 更改mysql.user表之后,没有使用flush privileges命令来更新权限. 解决方案 使用flush privileges命令更新一下. 问题描述 配置mysql远程登录时,只需要 ...
- StringHelper
/// <summary> /// 文本取左边 /// </summary> /// <param name="str"></param& ...