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

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

最近在做一个下载音乐的功能。用到了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语句来捕获,便可以识别到请求是被取消的。

04-13 15:47