首页 > 代码库 > 重新想象 Windows 8.1 Store Apps (89) - 通信的新特性: 下载数据, 上传数据, 上传文件

重新想象 Windows 8.1 Store Apps (89) - 通信的新特性: 下载数据, 上传数据, 上传文件

原文:重新想象 Windows 8.1 Store Apps (89) - 通信的新特性: 下载数据, 上传数据, 上传文件

[源码下载]


重新想象 Windows 8.1 Store Apps (89) - 通信的新特性: 下载数据, 上传数据, 上传文件



作者:webabcd


介绍
重新想象 Windows 8.1 Store Apps 之通信的新特性

  • 下载数据(显示下载进度,将下载数据保存到本地)
  • 上传数据(显示上传进度)
  • 上传文件



示例
HTTP 服务端
WebServer/HttpDemo.aspx.cs

/* * 用于响应 http 请求 */using System;using System.IO;using System.Threading;using System.Web;namespace WebServer{    public partial class HttpDemo : System.Web.UI.Page    {        protected void Page_Load(object sender, EventArgs e)        {            // 停 3 秒,以方便测试 http 请求的取消            Thread.Sleep(3000);            var action = Request.QueryString["action"];            switch (action)            {                case "getString": // 响应 http get string                     Response.Write("hello webabcd: " + DateTime.Now.ToString("hh:mm:ss"));                    break;                case "getStream": // 响应 http get stream                     Response.Write("hello webabcd hello webabcd hello webabcd hello webabcd hello webabcd hello webabcd hello webabcd hello webabcd hello webabcd hello webabcd hello webabcd hello webabcd");                    break;                case "postString": // 响应 http post string                     Response.Write(string.Format("param1:{0}, param2:{1}, referrer:{2}", Request.Form["param1"], Request.Form["param2"], Request.UrlReferrer));                    break;                case "postStream": // 响应 http post stream                     using (StreamReader reader = new StreamReader(Request.InputStream))                    {                        if (Request.InputStream.Length > 1024 * 100)                        {                            // 接收的数据太大,则显示“数据接收成功”                            Response.Write("数据接收成功");                        }                        else                        {                            // 显示接收到的数据                            string body = reader.ReadToEnd();                            Response.Write(Server.HtmlEncode(body));                        }                    }                     break;                case "uploadFile": // 处理上传文件的请求                    for (int i = 0; i < Request.Files.Count; i++)                    {                        string key = Request.Files.GetKey(i);                        HttpPostedFile file = Request.Files.Get(key);                        string savePath = @"d:\" + file.FileName;                        // 保存文件                        file.SaveAs(savePath);                        Response.Write(string.Format("key: {0}, fileName: {1}, savePath: {2}", key, file.FileName, savePath));                        Response.Write("\n");                    }                    break;                case "outputCookie": // 用于显示服务端获取到的 cookie 信息                    for (int i = 0; i < Request.Cookies.Count; i++)                    {                        HttpCookie cookie = Request.Cookies[0];                        Response.Write(string.Format("cookieName: {0}, cookieValue: {1}", cookie.Name, cookie.Value));                        Response.Write("\n");                    }                    break;                case "outputCustomHeader": // 用于显示一个自定义的 http header                    Response.Write("myRequestHeader: " + Request.Headers["myRequestHeader"]);                    break;                default:                    break;            }            Response.End();        }    }}


1、演示如何通过新的 HttpClient(Windows.Web.Http)获取下载进度,并将下载数据保存到本地
Download.xaml.cs

/* * 本例演示如何通过新的 HttpClient(Windows.Web.Http)获取下载进度,并将下载数据保存到本地 *  *  * 注:在 win8 时代要想获取下载进度只能依靠后台任务来完成 */using System;using System.Threading;using System.Threading.Tasks;using Windows.Storage;using Windows.UI.Xaml;using Windows.UI.Xaml.Controls;using Windows.UI.Xaml.Navigation;using Windows.Web.Http;namespace Windows81.Communication.HTTP{    public sealed partial class Download : Page    {        private HttpClient _httpClient;        private CancellationTokenSource _cts;        public Download()        {            this.InitializeComponent();        }        protected override void OnNavigatedFrom(NavigationEventArgs e)        {            // 释放资源            if (_httpClient != null)            {                _httpClient.Dispose();                _httpClient = null;            }            if (_cts != null)            {                _cts.Dispose();                _cts = null;            }        }        private async void btnDownload_Click(object sender, RoutedEventArgs e)        {            _httpClient = new HttpClient();            _cts = new CancellationTokenSource();            try            {                // 用于获取下载进度                IProgress<HttpProgress> progress = new Progress<HttpProgress>(ProgressHandler);                HttpResponseMessage response = await _httpClient.GetAsync(                    new Uri("http://files.cnblogs.com/webabcd/WindowsPhone.rar?ll"),                    HttpCompletionOption.ResponseContentRead).AsTask(_cts.Token, progress); // 把 progress 放到 task 里,以便获取下载进度                lblMsg.Text += ((int)response.StatusCode) + " " + response.ReasonPhrase;                lblMsg.Text += Environment.NewLine;                // 将下载好的数据保存到本地                StorageFolder storageFolder = KnownFolders.DocumentsLibrary;                StorageFile storageFile = await storageFolder.CreateFileAsync("WindowsPhone.rar", CreationCollisionOption.ReplaceExisting);                using (StorageStreamTransaction transaction = await storageFile.OpenTransactedWriteAsync())                {                    lblMsg.Text = "文件已下载,写入到磁盘中...";                    /*                     * IHttpContent.WriteToStreamAsync() - 用于保存数据                     */                    await response.Content.WriteToStreamAsync(transaction.Stream);                    await transaction.CommitAsync();                    lblMsg.Text = "文件已写入到磁盘";                }            }            catch (TaskCanceledException)            {                lblMsg.Text += "取消了";                lblMsg.Text += Environment.NewLine;            }            catch (Exception ex)            {                lblMsg.Text += ex.ToString();                lblMsg.Text += Environment.NewLine;            }        }        private void btnCancel_Click(object sender, RoutedEventArgs e)        {            // 取消 http 请求            if (_cts != null)            {                _cts.Cancel();                _cts.Dispose();                _cts = null;            }        }        // 下载进度发生变化时调用的处理器        private void ProgressHandler(HttpProgress progress)        {            /*             * HttpProgress - http 通信的进度             *     BytesReceived - 已收到的字节数             *     BytesSent - 已发送的字节数             *     TotalBytesToReceive - 总共需要收到的字节数             *     TotalBytesToSend - 总共需要发送的字节数             *     Retries - 重试次数             *     Stage - 当前通信的阶段(HttpProgressStage 枚举)             */            string result = "BytesReceived: {0}\nBytesSent: {1}\nRetries: {2}\nStage: {3}\nTotalBytesToReceive: {4}\nTotalBytesToSend: {5}\n";            result = string.Format(result, progress.BytesReceived, progress.BytesSent, progress.Retries, progress.Stage, progress.TotalBytesToReceive, progress.TotalBytesToSend);            lblMsg.Text = result;        }    }}


2、演示如何通过新的 HttpClient(Windows.Web.Http)获取上传进度
Upload.xaml.cs

/* * 本例演示如何通过新的 HttpClient(Windows.Web.Http)获取上传进度 *  *  * 注:在 win8 时代要想获取上传进度只能依靠后台任务来完成 */using System;using System.IO;using System.Runtime.InteropServices.WindowsRuntime;using System.Threading;using System.Threading.Tasks;using Windows.Foundation;using Windows.Storage.Streams;using Windows.UI.Xaml;using Windows.UI.Xaml.Controls;using Windows.UI.Xaml.Navigation;using Windows.Web.Http;namespace Windows81.Communication.HTTP{    public sealed partial class Upload : Page    {        private HttpClient _httpClient;        private CancellationTokenSource _cts;        public Upload()        {            this.InitializeComponent();        }        protected override void OnNavigatedFrom(NavigationEventArgs e)        {            // 释放资源            if (_httpClient != null)            {                _httpClient.Dispose();                _httpClient = null;            }            if (_cts != null)            {                _cts.Dispose();                _cts = null;            }        }        private async void btnUpload_Click(object sender, RoutedEventArgs e)        {            _httpClient = new HttpClient();            _cts = new CancellationTokenSource();            try            {                Uri resourceAddress = new Uri("http://localhost:39630/HttpDemo.aspx?action=postStream");                // 模拟一个比较大的比较慢的流,供 http 上传                const uint streamLength = 10000000;                HttpStreamContent streamContent = new HttpStreamContent(new SlowInputStream(streamLength));                streamContent.Headers.ContentLength = streamLength; // 必须要指定请求数据的 ContentLength,否则就是 chunked 了                // 用于获取上传进度                IProgress<HttpProgress> progress = new Progress<HttpProgress>(ProgressHandler);                HttpResponseMessage response = await _httpClient.PostAsync(resourceAddress, streamContent).AsTask(_cts.Token, progress); // 把 progress 放到 task 里,以便获取上传进度                lblMsg.Text += ((int)response.StatusCode) + " " + response.ReasonPhrase;                lblMsg.Text += Environment.NewLine;                lblMsg.Text += await response.Content.ReadAsStringAsync();                lblMsg.Text += Environment.NewLine;            }            catch (TaskCanceledException)            {                lblMsg.Text += "取消了";                lblMsg.Text += Environment.NewLine;            }            catch (Exception ex)            {                lblMsg.Text += ex.ToString();                lblMsg.Text += Environment.NewLine;            }        }        // 生成一个指定大小的内存流        private static MemoryStream GenerateSampleStream(int size)        {            byte[] subData = http://www.mamicode.com/new byte[size];            for (int i = 0; i < subData.Length; i++)            {                subData[i] = (byte)(97 + i % 26); // a-z            }            return new MemoryStream(subData);        }        private void btnCancel_Click(object sender, RoutedEventArgs e)        {            // 取消 http 请求            if (_cts != null)            {                _cts.Cancel();                _cts.Dispose();                _cts = null;            }        }        // 上传进度发生变化时调用的处理器        private void ProgressHandler(HttpProgress progress)        {            /*             * HttpProgress - http 通信的进度             *     BytesReceived - 已收到的字节数             *     BytesSent - 已发送的字节数             *     TotalBytesToReceive - 总共需要收到的字节数             *     TotalBytesToSend - 总共需要发送的字节数             *     Retries - 重试次数             *     Stage - 当前通信的阶段(HttpProgressStage 枚举)             */            string result = "BytesReceived: {0}\nBytesSent: {1}\nRetries: {2}\nStage: {3}\nTotalBytesToReceive: {4}\nTotalBytesToSend: {5}\n";            result = string.Format(result, progress.BytesReceived, progress.BytesSent, progress.Retries, progress.Stage, progress.TotalBytesToReceive, progress.TotalBytesToSend);            lblMsg.Text = result;        }    }    // 模拟一个比较慢的输入流    class SlowInputStream : IInputStream    {        uint length;        uint position;        public SlowInputStream(uint length)        {            this.length = length;            position = 0;        }        public IAsyncOperationWithProgress<IBuffer, uint> ReadAsync(IBuffer buffer, uint count, InputStreamOptions options)        {            return AsyncInfo.Run<IBuffer, uint>(async (cancellationToken, progress) =>            {                if (length - position < count)                {                    count = length - position;                }                byte[] data = http://www.mamicode.com/new byte[count];                for (uint i = 0; i < count; i++)                {                    data[i] = 64;                }                // 延迟 10 毫秒再继续,以模拟一个比较慢的输入流                await Task.Delay(10);                position += count;                progress.Report(count);                return data.AsBuffer();            });        }        public void Dispose()        {        }    }}


3、演示如何通过新的 HttpClient(Windows.Web.Http)上传文件(通过 multipart/form-data 的方式)
UploadFile.xaml.cs

/* * 本例演示如何通过新的 HttpClient(Windows.Web.Http)上传文件(通过 multipart/form-data 的方式) */using System;using System.Threading;using System.Threading.Tasks;using Windows.Storage;using Windows.Storage.Streams;using Windows.UI.Xaml;using Windows.UI.Xaml.Controls;using Windows.UI.Xaml.Navigation;using Windows.Web.Http;namespace Windows81.Communication.HTTP{    public sealed partial class UploadFile : Page    {        private HttpClient _httpClient;        private CancellationTokenSource _cts;        public UploadFile()        {            this.InitializeComponent();        }        protected override void OnNavigatedFrom(NavigationEventArgs e)        {            // 释放资源            if (_httpClient != null)            {                _httpClient.Dispose();                _httpClient = null;            }            if (_cts != null)            {                _cts.Dispose();                _cts = null;            }        }        private async void btnUploadFile_Click(object sender, RoutedEventArgs e)        {            _httpClient = new HttpClient();            _cts = new CancellationTokenSource();            try            {                // 构造需要上传的文件数据                StorageFile file1 = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Assets/Son.jpg", UriKind.Absolute));                IRandomAccessStreamWithContentType stream1 = await file1.OpenReadAsync();                HttpStreamContent streamContent1 = new HttpStreamContent(stream1);                // 构造需要上传的文件数据                StorageFile file2 = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Assets/Son.jpg", UriKind.Absolute));                IRandomAccessStreamWithContentType stream2 = await file1.OpenReadAsync();                HttpStreamContent streamContent2 = new HttpStreamContent(stream2);                // 通过 HttpMultipartFormDataContent 来指定需要“multipart/form-data”上传的文件                HttpMultipartFormDataContent fileContent = new HttpMultipartFormDataContent();                // 第 1 个参数:需要上传的文件数据                // 第 2 个参数:对应 asp.net 服务的 Request.Files 中的 key(参见:WebServer 项目中的 HttpDemo.aspx.cs)                // 第 3 个参数:对应 asp.net 服务的 Request.Files 中的 fileName(参见:WebServer 项目中的 HttpDemo.aspx.cs)                fileContent.Add(streamContent1, "file1", "file1.jpg");                 fileContent.Add(streamContent2, "file2", "file2.jpg");                HttpResponseMessage response = await _httpClient.PostAsync(new Uri("http://localhost:39630/HttpDemo.aspx?action=uploadFile"), fileContent).AsTask(_cts.Token);                lblMsg.Text += ((int)response.StatusCode) + " " + response.ReasonPhrase;                lblMsg.Text += Environment.NewLine;                lblMsg.Text += await response.Content.ReadAsStringAsync();                lblMsg.Text += Environment.NewLine;            }            catch (TaskCanceledException)            {                lblMsg.Text += "取消了";                lblMsg.Text += Environment.NewLine;            }            catch (Exception ex)            {                lblMsg.Text += ex.ToString();                lblMsg.Text += Environment.NewLine;            }        }        private void btnCancel_Click(object sender, RoutedEventArgs e)        {            // 取消 http 请求            if (_cts != null)            {                _cts.Cancel();                _cts.Dispose();                _cts = null;            }        }    }}



OK
[源码下载]

重新想象 Windows 8.1 Store Apps (89) - 通信的新特性: 下载数据, 上传数据, 上传文件