與眾不同 windows phone (13) - Background Task(后台任務)之后台文件傳輸(上傳和下載)


[索引頁]
[源碼下載]


與眾不同 windows phone (13) - Background Task(后台任務)之后台文件傳輸(上傳和下載)



作者:webabcd


介紹
與眾不同 windows phone 7.5 (sdk 7.1) 之后台任務

  • 后台文件傳輸(下載)
  • 后台文件傳輸(上傳)



示例
1、演示如何實現后台文件傳輸(下載)
BackgroundTransferDownload.xaml

<phone:PhoneApplicationPage 
    x:Class="Demo.BackgroundTask.BackgroundTransferDownload"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
    xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    SupportedOrientations="Portrait" Orientation="Portrait"
    mc:Ignorable="d" d:DesignHeight="768" d:DesignWidth="480"
    shell:SystemTray.IsVisible="True">

    <Grid x:Name="LayoutRoot" Background="Transparent">
        <StackPanel Orientation="Vertical">
            
            <Button x:Name="btnDownloadSilverlightDemo" Content="下載 Silverlight Demo 壓縮包" Click="btnDownloadSilverlightDemo_Click" />
            <Button x:Name="btnDownloadXNADemo" Content="下載 XNA Demo 壓縮包" Click="btnDownloadXNADemo_Click" />
            <Button x:Name="btnDownloadWindowsPhoneDemo" Content="下載 WindowsPhone Demo 壓縮包" Click="btnDownloadWindowsPhoneDemo_Click" />

            <TextBlock Text="下載任務列表:" Margin="0 15 0 0" />
            <ListBox Name="listBox">
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <Grid Margin="0 15" Width="480">
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="8*"/>
                                <ColumnDefinition Width="2*"/>
                            </Grid.ColumnDefinitions>
                            
                            <Grid>
                                <StackPanel Orientation="Vertical">
                                    <StackPanel Orientation="Horizontal">
                                        <TextBlock Text="文件名: "/>
                                        <TextBlock Text="{Binding Tag}"/>
                                    </StackPanel>
                                    <StackPanel Orientation="Horizontal">
                                        <TextBlock Text="下載狀態: "/>
                                        <TextBlock Text="{Binding TransferStatus}" />
                                    </StackPanel>
                                    <StackPanel Orientation="Horizontal">
                                        <TextBlock Text="已接收字節數: "/>
                                        <TextBlock Text="{Binding BytesReceived}" />
                                    </StackPanel>
                                    <StackPanel Orientation="Horizontal">
                                        <TextBlock Text="總共字節數: "/>
                                        <TextBlock Text="{Binding TotalBytesToReceive}" />
                                    </StackPanel>
                                </StackPanel>

                            </Grid>
                            <Grid Grid.Column="1">
                                <Button x:Name="btnCancel" Tag="{Binding RequestId}" Click="btnCancel_Click" Content="刪除任務"></Button>
                            </Grid>
                        </Grid>
                    </DataTemplate>
                </ListBox.ItemTemplate>
            </ListBox>
            
        </StackPanel>        
    </Grid>
 
</phone:PhoneApplicationPage>

BackgroundTransferDownload.xaml.cs

/*
 * 演示如何實現后台文件傳輸(下載)
 * 
 * 
 * BackgroundTransferRequest - 后台文件傳輸請求
 *     BackgroundTransferRequest(Uri) - 構造函數。參數解釋:下載時其為需要下載的文件的遠程地址;上傳時其為接收文件的遠程服務地址
 *     RequestId - 后台文件傳輸請求的唯一 ID,只讀
 *     RequestUri - 請求的地址,只讀。其需要在構造函數中設置
 *     Method - 請求的 http 方法,GET - 下載;POST - 上傳
 *     Headers - 請求的 http 頭,有一些頭信息不能自定義,如 Range 等
 *     StatusCode - http 請求回應的狀態碼
 *     Tag - 自定義此對象的關聯信息,即上下文數據
 *     TransferPreferences - 傳輸的啟動條件(Microsoft.Phone.BackgroundTransfer.TransferPreferences 枚舉)
 *         None - 僅在外部電源 + WiFi 環境下允許傳輸
 *         AllowCellular - 允許在手機網絡環境下傳輸
 *         AllowBattery - 允許在電池做電源的環境下傳輸
 *         AllowCellularAndBattery - 允許在電池電源 + 手機網絡的環境下傳輸
 *     TransferError - 錯誤信息
 *     TransferStatus - 傳輸狀態(Microsoft.Phone.BackgroundTransfer.TransferStatus 枚舉)
 *         None - 傳輸任務尚未加入到傳輸隊列
 *         Waiting - 在傳輸隊列,等待傳輸
 *         Transferring - 傳輸中
 *         Paused - 暫停
 *         Completed - 傳輸任務已完成,如果傳輸成功則 TransferError 為 null
 *         WaitingForWiFi - WiFi 網絡
 *         WaitingForExternalPower - 需要接上外接電源
 *         WaitingForExternalPowerDueToBatterySaverMode - 需要接上外接電源,或者禁用節電模式
 *         WaitingForNonVoiceBlockingNetwork - 不能使用無法和語音並發的網絡(如 2G、EDGE 和標准 GPRS)
 *     DownloadLocation - 下載到的目標位置
 *     UploadLocation - 需要上傳的文件的地址
 *     BytesReceived - 文件已下載的字節數
 *     BytesSent - 文件已上傳的字節數
 *     TotalBytesToReceive - 需要下載的文件的總字節數(-1 則文件大小未知)
 *     TotalBytesToSend - 需要上傳的文件的總字節數(-1 則文件大小未知)
 *     
 *     TransferProgressChanged - 傳輸進度改變時所觸發的事件
 *     TransferStatusChanged - 屬性 TransferStatus 發生改變時所觸發的事件
 * 
 * 
 * BackgroundTransferService - 對后台文件傳輸請求的管理
 *     Add() - 添加一個 BackgroundTransferRequest
 *     Find() - 通過 RequestId 查找指定的 BackgroundTransferRequest
 *     Remove - 通過 RequestId 刪除指定的 BackgroundTransferRequest
 *     
 * 
 * 注意:
 * 后台文件傳輸既支持 http 又支持 https
 * 傳輸的文件必須在 /shared/transfers 目錄下
 * 上傳文件最大 5 MB,手機網絡下載文件最大 20 MB,WiFi+電池電源下載文件最大 100 MB,WiFi+外接電源下載文件則允許大於 100 MB
 * 下載文件超過 5 MB 時,系統會向服務端發 Range 頭分段下載(不會多線程下載,但是會斷點續傳)
 * 每個應用程序的傳輸任務隊列,最大支持 5 個任務,設備支持 500 個任務
 * 設備上最大並發傳輸數為 2 個
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;

using Microsoft.Phone.BackgroundTransfer;
using System.IO.IsolatedStorage;

namespace Demo.BackgroundTask
{
    public partial class BackgroundTransferDownload : PhoneApplicationPage
    {
        public BackgroundTransferDownload()
        {
            InitializeComponent();
        }

        protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
        {
            // 為每個 BackgroundTransferRequest 注冊相關事件
            foreach (var transfer in BackgroundTransferService.Requests)
            {
                transfer.TransferStatusChanged += new EventHandler<BackgroundTransferEventArgs>(transfer_TransferStatusChanged);
                transfer.TransferProgressChanged += new EventHandler<BackgroundTransferEventArgs>(transfer_TransferProgressChanged);
            }

            UpdateUI(); 
        }

        private void ProcessTransfer(BackgroundTransferRequest transfer)
        {
            switch (transfer.TransferStatus)
            {
                case TransferStatus.Completed:
                    // 200 - 下載完成;206 - 分塊下載完成
                    if (transfer.StatusCode == 200 || transfer.StatusCode == 206)
                    {
                        // 下載完成后不會自動從隊列中刪除,需要手動刪除
                        RemoveTransferRequest(transfer.RequestId);

                        // 將下載完成后的文件移動到獨立存儲的根目錄下
                        using (IsolatedStorageFile isoStore = IsolatedStorageFile.GetUserStoreForApplication())
                        {
                            string filename = transfer.Tag;
                            if (isoStore.FileExists(filename))
                            {
                                isoStore.DeleteFile(filename);
                            }
                            isoStore.MoveFile(transfer.DownloadLocation.OriginalString, filename);
                        }
                    }
                    else
                    {
                        // 如果回應的不是 200 或 206 則意味着出現了問題
                        // 將任務其移出隊列
                        RemoveTransferRequest(transfer.RequestId);

                        // 發生了異常,做一些相關處理
                        if (transfer.TransferError != null)
                        {
                            MessageBox.Show(transfer.TransferError.ToString());
                        }
                    }
                    break;

                // 注:以下 4 個狀態最好做一下判斷和處理,然后呈現給用戶
                case TransferStatus.WaitingForExternalPower:
                    break;
                case TransferStatus.WaitingForExternalPowerDueToBatterySaverMode:
                    break;
                case TransferStatus.WaitingForNonVoiceBlockingNetwork:
                    break;
                case TransferStatus.WaitingForWiFi:
                    break;
            }
        }

        void transfer_TransferStatusChanged(object sender, BackgroundTransferEventArgs e)
        {
            ProcessTransfer(e.Request);

            UpdateUI();
        }

        void transfer_TransferProgressChanged(object sender, BackgroundTransferEventArgs e)
        {
            UpdateUI();
        }

        private void btnCancel_Click(object sender, EventArgs e)
        {
            string transferId = ((Button)sender).Tag as string;
            RemoveTransferRequest(transferId);

            UpdateUI();
        }

        // 從 BackgroundTransferService 中刪除指定的傳輸請求
        private void RemoveTransferRequest(string transferId)
        {
            BackgroundTransferRequest transfer = BackgroundTransferService.Find(transferId);

            try
            {
                if (transfer != null)
                    BackgroundTransferService.Remove(transfer);
            }
            catch (Exception ex)
            {
                MessageBox.Show("RemoveTransferRequest: " + ex.ToString());
            }
        }

        private void UpdateUI()
        {
            // 更新 UI
            listBox.ItemsSource = BackgroundTransferService.Requests;
        }

        private void btnDownloadSilverlightDemo_Click(object sender, RoutedEventArgs e)
        {
            // 如果 url 中有特殊字符,如漢字等,建議使用 Uri.EscapeUriString 編碼
            AddBackgroundTransfer("Silverlight.rar", new Uri("http://files.cnblogs.com/webabcd/Silverlight.rar", UriKind.Absolute));

            UpdateUI();
        }

        private void btnDownloadXNADemo_Click(object sender, RoutedEventArgs e)
        {
            AddBackgroundTransfer("XNA.rar", new Uri("http://files.cnblogs.com/webabcd/XNA.rar", UriKind.Absolute));

            UpdateUI();
        }

        private void btnDownloadWindowsPhoneDemo_Click(object sender, RoutedEventArgs e)
        {
            AddBackgroundTransfer("WindowsPhone.rar", new Uri("http://files.cnblogs.com/webabcd/WindowsPhone.rar", UriKind.Absolute));

            UpdateUI();
        }

        /// <summary>
        /// 添加后台傳輸任務到隊列
        /// </summary>
        /// <param name="fileName">需要在本地保存的文件名</param>
        /// <param name="fileUri">需要下載的文件的遠程地址</param>
        private void AddBackgroundTransfer(string fileName, Uri fileUri)
        {
            // 做一下相關判斷
            if (BackgroundTransferService.Requests.Count() >= 5)
            {
                MessageBox.Show("每個應用程序的后台傳輸隊列最多只能有 5 個任務");
                return;
            }
            if (BackgroundTransferService.Requests.Any(p => p.RequestUri == fileUri))
            {
                MessageBox.Show("任務已在隊列中");
                return;
            }

            BackgroundTransferRequest transferRequest = new BackgroundTransferRequest(fileUri);
            transferRequest.Method = "GET"; // 下載
            transferRequest.TransferPreferences = TransferPreferences.None; // 僅在外部電源 + WiFi 環境下允許下載

            transferRequest.TransferStatusChanged += new EventHandler<BackgroundTransferEventArgs>(transfer_TransferStatusChanged);
            transferRequest.TransferProgressChanged += new EventHandler<BackgroundTransferEventArgs>(transfer_TransferProgressChanged);

            transferRequest.Tag = fileName; // 給 TransferRequest 賦值一個上下文數據
            transferRequest.DownloadLocation = new Uri("shared/transfers/" + fileName, UriKind.Relative);

            try
            {
                BackgroundTransferService.Add(transferRequest);
            }
            catch (Exception ex)
            {
                MessageBox.Show("AddBackgroundTransfer: " + ex.ToString());
            }
        }
    }
}



2、演示如何實現后台文件傳輸(上傳)
BackgroundTransferUpload.xaml

<phone:PhoneApplicationPage 
    x:Class="Demo.BackgroundTask.BackgroundTransferUpload"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
    xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    SupportedOrientations="Portrait" Orientation="Portrait"
    mc:Ignorable="d" d:DesignHeight="768" d:DesignWidth="480"
    shell:SystemTray.IsVisible="True">

    <Grid x:Name="LayoutRoot" Background="Transparent">
        <StackPanel Orientation="Vertical">

            <Button x:Name="btnUpload" Content="上傳 Demo.mp4 文件到服務端" Click="btnUpload_Click" />

        </StackPanel>
    </Grid>
 
</phone:PhoneApplicationPage>

BackgroundTransferUpload.xaml.cs

/*
 * 演示如何實現后台文件傳輸(上傳)
 * 
 * BackgroundTransferRequest、BackgroundTransferService 及相關注意事項詳見:BackgroundTask/BackgroundTransferDownload.xaml.cs
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;

using Microsoft.Phone.BackgroundTransfer;
using System.IO.IsolatedStorage;
using System.Windows.Resources;
using System.IO;

namespace Demo.BackgroundTask
{
    public partial class BackgroundTransferUpload : PhoneApplicationPage
    {
        public BackgroundTransferUpload()
        {
            InitializeComponent();
        }

        protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
        {
            // 為每個 BackgroundTransferRequest 注冊相關事件
            foreach (var transfer in BackgroundTransferService.Requests)
            {
                transfer.TransferStatusChanged += new EventHandler<BackgroundTransferEventArgs>(transfer_TransferStatusChanged);
                transfer.TransferProgressChanged += new EventHandler<BackgroundTransferEventArgs>(transfer_TransferProgressChanged);
            }
        }

        private void ProcessTransfer(BackgroundTransferRequest transfer)
        {
            switch (transfer.TransferStatus)
            {
                case TransferStatus.Completed:
                    // 200 代表上傳成功
                    if (transfer.StatusCode == 200)
                    {
                        MessageBox.Show("上傳成功");
                    }
                    else
                    {
                        // 發生了異常,做一些相關處理
                        if (transfer.TransferError != null)
                        {
                            MessageBox.Show(transfer.TransferError.ToString());
                        }
                    }
                    RemoveTransferRequest(transfer.RequestId);
                    break;

                // 注:以下 4 個狀態最好做一下判斷和處理,然后呈現給用戶
                case TransferStatus.WaitingForExternalPower:
                    break;
                case TransferStatus.WaitingForExternalPowerDueToBatterySaverMode:
                    break;
                case TransferStatus.WaitingForNonVoiceBlockingNetwork:
                    break;
                case TransferStatus.WaitingForWiFi:
                    break;
            }
        }

        void transfer_TransferStatusChanged(object sender, BackgroundTransferEventArgs e)
        {
            ProcessTransfer(e.Request);
        }

        void transfer_TransferProgressChanged(object sender, BackgroundTransferEventArgs e)
        {
            // 上傳進度發生改變
        }

        private void btnCancel_Click(object sender, EventArgs e)
        {
            string transferId = ((Button)sender).Tag as string;
            RemoveTransferRequest(transferId);
        }

        // 從 BackgroundTransferService 中刪除指定的傳輸請求
        private void RemoveTransferRequest(string transferId)
        {
            BackgroundTransferRequest transfer = BackgroundTransferService.Find(transferId);

            try
            {
                if (transfer != null)
                    BackgroundTransferService.Remove(transfer);
            }
            catch (Exception ex)
            {
                MessageBox.Show("RemoveTransferRequest: " + ex.ToString());
            }
        }

        private void btnUpload_Click(object sender, RoutedEventArgs e)
        {
            // 將 Demo.mp4 文件從程序包復制到獨立存儲的 shared/transfers 目錄,以備上傳
            StreamResourceInfo sr = Application.GetResourceStream(new Uri("Assets/Demo.mp4", UriKind.Relative));
            using (BinaryReader br = new BinaryReader(sr.Stream))
            {
                byte[] data = br.ReadBytes((int)sr.Stream.Length);

                IsolatedStorageFile isf = IsolatedStorageFile.GetUserStoreForApplication();
                using (var isfs = new IsolatedStorageFileStream(@"shared/transfers/Demo.mp4", FileMode.Create, isf))
                {
                    using (var bw = new BinaryWriter(isfs))
                    {
                        bw.Write(data);
                    }
                }
            }

            AddBackgroundTransfer("Demo.mp4", new Uri(@"shared/transfers/Demo.mp4", UriKind.Relative));
        }

        /// <summary>
        /// 添加后台傳輸任務到隊列
        /// </summary>
        /// <param name="fileName">需要在服務端保存的文件名</param>
        /// <param name="fileUri">需要上傳的文件的本地地址</param>
        private void AddBackgroundTransfer(string fileName, Uri fileUri)
        {
            BackgroundTransferRequest transferRequest = new BackgroundTransferRequest(new Uri("http://localhost:15482/UploadFile.aspx?fileName=" + fileName, UriKind.Absolute));
            transferRequest.Method = "POST"; // 上傳
            transferRequest.TransferPreferences = TransferPreferences.None; // 僅在外部電源 + WiFi 環境下允許上傳

            transferRequest.TransferStatusChanged += new EventHandler<BackgroundTransferEventArgs>(transfer_TransferStatusChanged);
            transferRequest.TransferProgressChanged += new EventHandler<BackgroundTransferEventArgs>(transfer_TransferProgressChanged);

            transferRequest.UploadLocation = fileUri;

            try
            {
                BackgroundTransferService.Add(transferRequest);
            }
            catch (Exception ex)
            {
                MessageBox.Show("AddBackgroundTransfer: " + ex.ToString());
            }
        }
    }
}

UploadFile.aspx.cs(用於保存上傳文件的服務端代碼)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.IO;

namespace Web
{
    public partial class UploadFile : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            if (Request.TotalBytes > 0)
            {
                // 保存上傳過來的文件
                byte[] data = Request.BinaryRead(Request.TotalBytes);
                File.WriteAllBytes(@"C:\" + Request.QueryString["fileName"], data);
            }
        }
    }
}

 


OK
[源碼下載]


免責聲明!

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



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