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

简介: 原文:重新想象 Windows 8.1 Store Apps (89) - 通信的新特性: 下载数据, 上传数据, 上传文件[源码下载] 重新想象 Windows 8.1 Store Apps (89) - 通信的新特性: 下载数据, 上传数据, 上传文件 作者:webabcd介绍重新想象 Windows 8.
原文: 重新想象 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 = 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 = 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
[源码下载]

目录
相关文章
|
8月前
|
计算机视觉 Windows Python
windows下使用python + opencv读取含有中文路径的图片 和 把图片数据保存到含有中文的路径下
在Windows系统中,直接使用`cv2.imread()`和`cv2.imwrite()`处理含中文路径的图像文件时会遇到问题。读取时会返回空数据,保存时则无法正确保存至目标目录。为解决这些问题,可以使用`cv2.imdecode()`结合`np.fromfile()`来读取图像,并使用`cv2.imencode()`结合`tofile()`方法来保存图像至含中文的路径。这种方法有效避免了路径编码问题,确保图像处理流程顺畅进行。
689 1
|
5月前
|
C# Windows
【Azure App Service】在App Service for Windows上验证能占用的内存最大值
根据以上测验,当使用App Service内存没有达到预期的值,且应用异常日志出现OutOfMemory时,就需要检查Platform的设置是否位64bit。
84 11
|
5月前
|
数据库 数据安全/隐私保护 Windows
Windows远程桌面出现CredSSP加密数据修正问题解决方案
【10月更文挑战第30天】本文介绍了两种解决Windows系统凭据分配问题的方法。方案一是通过组策略编辑器(gpedit.msc)启用“加密数据库修正”并将其保护级别设为“易受攻击”。方案二是通过注册表编辑器(regedit)在指定路径下创建或修改名为“AllowEncryptionOracle”的DWORD值,并将其数值设为2。
5135 3
|
4月前
|
存储 缓存 安全
硬盘数据恢复:恢复硬盘数据的9个实用方法(Windows版)
无论是工作文档、家庭照片,还是其他珍贵的数字资产,数据丢失总是一件让人头疼的事情。然而,当硬盘发生问题时,不必过于慌张——只要正确应对,许多数据都可以被成功恢复。本文将从常见数据丢失原因到具体恢复方法,为您提供全面的硬盘数据恢复指导。
|
8月前
|
Java 应用服务中间件 开发工具
[App Service for Windows]通过 KUDU 查看 Tomcat 配置信息
[App Service for Windows]通过 KUDU 查看 Tomcat 配置信息
|
8月前
|
Java 应用服务中间件 Windows
【App Service for Windows】为 App Service 配置自定义 Tomcat 环境
【App Service for Windows】为 App Service 配置自定义 Tomcat 环境
|
8月前
|
PHP Windows
【Azure App Service for Windows】 PHP应用出现500 : The page cannot be displayed because an internal server error has occurred. 错误
【Azure App Service for Windows】 PHP应用出现500 : The page cannot be displayed because an internal server error has occurred. 错误
121 1
|
8月前
|
网络安全 API 数据安全/隐私保护
【Azure App Service】.NET代码实验App Service应用中获取TLS/SSL 证书 (App Service Windows)
【Azure App Service】.NET代码实验App Service应用中获取TLS/SSL 证书 (App Service Windows)
|
8月前
|
Shell PHP Windows
【Azure App Service】Web Job 报错 UNC paths are not supported. Defaulting to Windows directory.
【Azure App Service】Web Job 报错 UNC paths are not supported. Defaulting to Windows directory.