重新想象 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
[源碼下載]


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM