热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

背水一战Windows10(120)后台任务:后台上传任务

背水一战Windows10之后台任务

[源码下载]


背水一战 Windows 10 (120) - 后台任务: 后台上传任务



作者:webabcd


介绍
背水一战 Windows 10 之 后台任务

  • 后台上传任务



示例
演示 uwp 的后台上传任务
BackgroundTask/TransferModel.cs

/*
 * 扩展了 DownloadOperation 和 UploadOperation,用于 MVVM 绑定数据
 */

using System;
using System.ComponentModel;
using Windows.Networking.BackgroundTransfer;

namespace Windows10.BackgroundTask
{
    public class TransferModel : INotifyPropertyChanged
    {
        public DownloadOperation DownloadOperation { get; set; }
        public UploadOperation UploadOperation { get; set; }

        public string Source { get; set; }
        public string Destination { get; set; }

        private string _progress;
        public string Progress
        {
            get { return _progress; }
            set
            {
                _progress = value;
                RaisePropertyChanged("Progress");
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
        protected void RaisePropertyChanged(string name)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(name));
            }
        }
    }
}

BackgroundTask/TransferUpload.xaml

<Page
    x:Class="Windows10.BackgroundTask.TransferUpload"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:Windows10.BackgroundTask"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <Grid Background="Transparent">
        <StackPanel Margin="10 0 10 10">

            <ScrollViewer Name="scrollViewer" Height="100" Margin="5">
                <TextBlock Name="lblMsg" TextWrapping="Wrap" />
            ScrollViewer>

            <Button Name="btnAddUpload" Content="新增一个上传任务(一次请求上传一个文件)" Margin="5" Click="btnAddUpload_Click" />
            <Button Name="btnAddMultiUpload" Content="新增一个上传任务(一次请求上传多个文件)" Margin="5" Click="btnAddMultiUpload_Click" />
            <Button Name="btnCancel" Content="取消所有上传任务" Margin="5" Click="btnCancel_Click" />

            <ListView Name="listView" Height="286" Padding="5">
                <ListView.ItemTemplate>
                    <DataTemplate>
                        <StackPanel Margin="0 5" Background="Blue">
                            <TextBlock Text="{Binding Source}" Margin="5" />
                            <TextBlock Text="{Binding Destination}" Margin="5" />
                            <TextBlock Text="{Binding Progress}" Margin="5" />
                        StackPanel>
                    DataTemplate>
                ListView.ItemTemplate>
            ListView>

        StackPanel>
    Grid>
Page>

BackgroundTask/TransferUpload.xaml.cs

/*
 * 演示 uwp 的后台上传任务
 * 
 * BackgroundUploader - 后台上传任务管理器
 *     CreateUpload(Uri uri, IStorageFile sourceFile) - 创建一个上传任务,返回 UploadOperation 对象
 *     CreateUploadFromStreamAsync(Uri uri, IInputStream sourceStream) - 以流的方式创建一个上传任务
 *     CreateUploadAsync(Uri uri, IEnumerable parts) - 创建一个包含多个上传文件的上传任务
 *     SetRequestHeader(string headerName, string headerValue) - 设置 http 请求头
 *     Method - 用于上传的 http method(默认 post)
 *     static GetCurrentUploadsAsync() - 获取当前 app 的未与组关联的所有上传任务
 *     CostPolicy - 上传的成本策略,BackgroundTransferCostPolicy 枚举
 *         Default - 不允许在高成本(比如 4G)网络上传输
 *         UnrestrictedOnly - 允许在高成本(比如 4G)网络上传输
 *         Always - 无论如何均可传输,即使在漫游时
 *     ServerCredential - 与服务端通信时的凭据
 *     ProxyCredential - 使用代理时的身份凭据
 *     SuccessToastNotification, SuccessTileNotification, FailureToastNotification, FailureTileNotification - 上传任务成功或失败后的 toast 或 tile 通知
 *     static GetCurrentUploadsForTransferGroupAsync(BackgroundTransferGroup group) - 获取指定组的所有上传任务
 *     TransferGroup - 设置或获取分组对象(BackgroundTransferGroup 类型)
 *     BackgroundUploader(BackgroundTransferCompletionGroup completionGroup) - 通过指定的 BackgroundTransferCompletionGroup 对象实例化 BackgroundUploader 对象
 *     CompletionGroup - 获取关联的 BackgroundTransferCompletionGroup 对象
 *     
 * UploadOperation - 上传任务对象
 *     Guid - 获取此上传任务的标识
 *     CostPolicy - 上传的成本策略,BackgroundTransferCostPolicy 枚举
 *     RequestedUri - 上传任务所请求的服务端地址
 *     SourceFile - 需要上传的文件,如果是一次上传多个文件则此属性为 null
 *     Method - 获取用于上传的 http method(get, post 之类的)
 *     GetResponseInformation() - 上传完成后获取到的服务端响应信息,返回 ResponseInformation 对象
 *         ActualUri - 上传服务的真实 URI
 *         Headers - 服务端响应的 HTTP 头
 *         StatusCode - 服务端响应的状态码
 *     StartAsync() - 新增一个上传任务,返回 IAsyncOperationWithProgress 对象
 *     AttachAsync() - 监视已存在的上传任务,返回 IAsyncOperationWithProgress 对象
 *     Progress - 获取上传进度,返回 BackgroundUploadProgress 对象
 *     Priority - 上传的优先级,BackgroundTransferPriority 枚举
 *         Default 或 High
 *     TransferGroup - 获取此上传任务的分组对象(BackgroundTransferGroup 类型)
 *     
 * BackgroundUploadProgress - 后台上传任务的上传进度对象
 *     BytesSent - 已上传的字节数
 *     TotalBytesToSend - 总共需要上传的字节数
 *     BytesReceived - 已下载的字节数
 *     TotalBytesToReceive - 总共需要下载的字节数,未知则为 0 
 *     Status - 上传状态,BackgroundTransferStatus 枚举
 *         Idle, Running, PausedByApplication, PausedCostedNetwork, PausedNoNetwork, Completed, Canceled, Error
 *     HasResponseChanged - 服务端响应了则为 true
 *     HasRestarted - 当上传连接断掉后,系统会重新上传,此种情况则为 true
 *     
 * BackgroundTransferGroup - 后台上传任务的分组对象
 *     static BackgroundTransferGroup CreateGroup(string name) - 创建指定分组标识的 BackgroundTransferGroup 对象
 *     Name - 分组标识(只读)
 *     TransferBehavior - 组内上传任务的执行方式,BackgroundTransferBehavior 枚举
 *         Parallel - 并行
 *         Serialized - 串行
 * 
 * BackgroundTransferCompletionGroup - 分组对象(用于实现“组任务全部完成后触发后台任务”)
 *     Enable() - 启用“组任务全部完成后触发后台任务”的功能
 *     IsEnabled - 是否启用了“组任务全部完成后触发后台任务”的功能(只读)
 *     Trigger - “组任务全部完成后触发后台任务”的触发器
 *     
 * BackgroundTransferContentPart - 当一次上传多个文件时,将每个需要上传的文件构造成一个 BackgroundTransferContentPart 对象
 *     BackgroundTransferContentPart(string name, string fileName) - 通过一个标识和文件名称实例化 BackgroundTransferContentPart 对象
 *     SetFile(IStorageFile value) - 指定需要上传的文件
 *     
 * 
 * 注:关于上传任务的“任务分组,并行或串行执行,组完成后通知”和“任务分组,组完成后触发后台任务”的实现方式与下载任务是一样的,请参见下载任务的相关演示示例(TransferGroup.xaml.cs 和 TransferBackground.xaml.cs)
 */

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Windows.Data.Xml.Dom;
using Windows.Networking.BackgroundTransfer;
using Windows.Storage;
using Windows.UI.Notifications;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.Web;

namespace Windows10.BackgroundTask
{
    public sealed partial class TransferUpload : Page
    {
        // 上传任务的集合
        private ObservableCollection _transfers = new ObservableCollection();

        // 所有上传任务的关联的 CancellationTokenSource 对象
        private CancellationTokenSource _cancelToken = new CancellationTokenSource();

        public TransferUpload()
        {
            this.InitializeComponent();

            Init();
        }

        private async void Init()
        {
            listView.ItemsSource = _transfers;

            // 加载全部上传任务
            await LoadUploadAsync();
        }

        // 加载全部上传任务
        private async Task LoadUploadAsync()
        {
            IReadOnlyList uploads = null;
            try
            {
                // 获取所有后台上传任务
                uploads = await BackgroundUploader.GetCurrentUploadsAsync();
            }
            catch (Exception ex)
            {
                WriteLine(ex.ToString());
                return;
            }

            if (uploads.Count > 0)
            {
                List tasks = new List();
                foreach (UploadOperation upload in uploads)
                {
                    // 监视指定的后台上传任务
                    tasks.Add(HandleUploadAsync(upload, false));
                }

                await Task.WhenAll(tasks);
            }
        }

        // 新增一个上传任务(一次请求上传一个文件)
        private async void btnAddUpload_Click(object sender, RoutedEventArgs e)
        {
            // 上传服务的地址
            Uri serverUri = new Uri("http://localhost:44914/api/Upload", UriKind.Absolute);

            StorageFile sourceFile;
            try
            {
                // 需要上传的文件
                sourceFile = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Assets/hololens.jpg", UriKind.Absolute));
            }
            catch (Exception ex)
            {
                WriteLine(ex.ToString());
                return;
            }

            // 实例化 BackgroundUploader,并设置 http header
            BackgroundUploader backgroundUploader = new BackgroundUploader();
            backgroundUploader.SetRequestHeader("Filename", "hololens.jpg");

            // 任务成功后弹出指定的 toast 通知(类似的还有 SuccessTileNotification, FailureToastNotification, FailureTileNotification)
            backgroundUploader.SuccessToastNotification = GetToastNotification();

            // 创建一个后台上传任务,此任务包含一个上传文件
            UploadOperation upload = backgroundUploader.CreateUpload(serverUri, sourceFile);

            // 以流的方式创建一个后台上传任务
            // await backgroundUploader.CreateUploadFromStreamAsync(Uri uri, IInputStream sourceStream);

            // 处理并监视指定的后台上传任务
            await HandleUploadAsync(upload, true);
        }

        // 新增一个上传任务(一次请求上传多个文件)
        private async void btnAddMultiUpload_Click(object sender, RoutedEventArgs e)
        {
            // 上传服务的地址
            Uri serverUri = new Uri("http://localhost:44914/api/Upload", UriKind.Absolute);

            // 需要上传的文件源集合
            List sourceFiles = new List();
            for (int i = 0; i <3; i++)
            {
                StorageFile sourceFile = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Assets/hololens.jpg", UriKind.Absolute));
                sourceFiles.Add(sourceFile);
            }

            // 构造需要上传 BackgroundTransferContentPart 集合
            List cOntentParts= new List();
            for (int i = 0; i )
            {
                BackgroundTransferContentPart contentPart = new BackgroundTransferContentPart("File" + i, sourceFiles[i].Name);
                contentPart.SetFile(sourceFiles[i]);
                contentParts.Add(contentPart);
            }
            
            BackgroundUploader backgroundUploader = new BackgroundUploader();

            // 任务成功后弹出指定的 toast 通知(类似的还有 SuccessTileNotification, FailureToastNotification, FailureTileNotification)
            backgroundUploader.SuccessToastNotification = GetToastNotification();

            // 创建一个后台上传任务,此任务包含多个上传文件
            UploadOperation upload = await backgroundUploader.CreateUploadAsync(serverUri, contentParts);

            // 处理并监视指定的后台上传任务
            await HandleUploadAsync(upload, true);
        }

        /// 
        /// 处理并监视指定的后台上传任务
        /// 
        /// 后台上传任务
        /// 是否是新增的任务
        private async Task HandleUploadAsync(UploadOperation upload, bool isNew)
        {
            try
            {
                // 将 UploadOperation 附加到 TransferModel,以便上传进度可通知
                TransferModel transfer = new TransferModel();
                transfer.UploadOperation = upload;
                transfer.Source = "多个文件";
                transfer.Destination = upload.RequestedUri.ToString();
                transfer.Progress = upload.Progress.Status.ToString() + "0 / 0";

                _transfers.Add(transfer);

                WriteLine("Task Count: " + _transfers.Count.ToString());

                // 当上传进度发生变化时的回调函数
                Progress progressCallback = new Progress(UploadProgress);

                if (isNew)
                    await upload.StartAsync().AsTask(_cancelToken.Token, progressCallback); // 启动一个后台上传任务
                else
                    await upload.AttachAsync().AsTask(_cancelToken.Token, progressCallback); // 监视已存在的后台上传任务

                // 上传完成后获取服务端的响应信息
                ResponseInformation respOnse= upload.GetResponseInformation();
                WriteLine("Completed: " + response.ActualUri + ", HttpStatusCode: " + response.StatusCode.ToString());
            }
            catch (TaskCanceledException) // 调用 CancellationTokenSource.Cancel() 后会抛出此异常
            {
                WriteLine("Canceled: " + upload.Guid);
            }
            catch (Exception ex)
            {
                // 将异常转换为 WebErrorStatus 枚举,如果获取到的是 WebErrorStatus.Unknown 则说明此次异常不是涉及 web 的异常
                WebErrorStatus error = BackgroundTransferError.GetStatus(ex.HResult);

                WriteLine(ex.ToString());
            }
            finally
            {
                _transfers.Remove(_transfers.First(p => p.UploadOperation == upload));
            }
        }

        // 进度发生变化时,更新 TransferModel 的 Progress
        private void UploadProgress(UploadOperation upload)
        {
            TransferModel transfer = _transfers.First(p => p.UploadOperation == upload);
            transfer.Progress = upload.Progress.Status.ToString() + ": " + upload.Progress.BytesSent.ToString("#,0") + " / " + upload.Progress.TotalBytesToSend.ToString("#,0");
        }

        // 取消全部后台上传任务
        private void btnCancel_Click(object sender, RoutedEventArgs e)
        {
            _cancelToken.Cancel();
            _cancelToken.Dispose();

            _cancelToken = new CancellationTokenSource();
        }

        // 向 lblMsg 中追加一行文本
        private void WriteLine(string message)
        {
            lblMsg.Text += message;
            lblMsg.Text += Environment.NewLine;

            scrollViewer.ChangeView(0, scrollViewer.ScrollableHeight, 1f);
        }

        // 构造指定的 toast 通知
        private ToastNotification GetToastNotification()
        {
            string toastXml = $@"
                
                    
                        
                            toast - title
                            上传任务成功完成
                        
                    
                ";
            
            XmlDocument toastDoc = new XmlDocument();
            toastDoc.LoadXml(toastXml);

            return new ToastNotification(toastDoc);
        }
    }
}



OK
[源码下载]

背水一战 Windows 10 (120) - 后台任务: 后台上传任务


推荐阅读
  • 驱动程序的基本结构1、Windows驱动程序中重要的数据结构1.1、驱动对象(DRIVER_OBJECT)每个驱动程序会有唯一的驱动对象与之对应,并且这个驱动对象是在驱 ... [详细]
  • 本文介绍了如何使用线段树实现区间加法和区间查询操作,包括详细的代码实现和解释。 ... [详细]
  • 线段树,注 ... [详细]
  • 解决网页乱码问题的实用方法
    网页乱码问题在开发中较为常见,主要由文件编码、程序字符集设置和数据库连接字符集设置不当引起。本文将详细介绍如何逐一排查并解决这些问题。 ... [详细]
  • 本文介绍了 Oracle SQL 中的集合运算、子查询、数据处理、表的创建与管理等内容。包括查询部门号为10和20的员工信息、使用集合运算、子查询的注意事项、数据插入与删除、表的创建与修改等。 ... [详细]
  • 申请地址:https://developer.apple.com/appstore/contact/?topic=expedite 常见申请理由:1. 我们即将发布新产品,这是一个媒体活动,我们无法承担任何风险,因此在多个方面努力提升应用质量。 ... [详细]
  • Python学习day3网络基础之网络协议篇
    一、互联网协议连接两台计算机之间的Internet实际上就是一系列统一的标准,这些标准称之为互联网协议,互联网的本质就是一系列网络协议。二、为什么要有互联网协议互联网协议就相当于计 ... [详细]
  • Java EE 平台集成了多种服务、API 和协议,旨在支持基于 Web 的多层应用程序开发。本文将详细介绍 Java EE 中的 13 种关键技术规范,帮助开发者更好地理解和应用这些技术。 ... [详细]
  • Gty的二逼妹子序列 - 分块与莫队算法的应用
    Autumn 和 Bakser 正在研究 Gty 的妹子序列,但遇到了一个难题。他们希望计算某个区间内美丽度属于 [a, b] 的妹子的美丽度种类数。本文将详细介绍如何利用分块和莫队算法解决这一问题。 ... [详细]
  • 阿里云 Aliplayer高级功能介绍(八):安全播放
    如何保障视频内容的安全,不被盗链、非法下载和传播,阿里云视频点播已经有一套完善的机 ... [详细]
  • JavaSE For循环入门示例
    本文将介绍Java中For循环的基本概念和使用方法,通过几个简单的示例帮助初学者更好地理解和掌握For循环。 ... [详细]
  • SvpplyTable: 实现可扩展和可折叠的菜单动画
    SvpplyTable 是一个示例项目,旨在实现类似 Svpply 应用程序中的可扩展和可折叠的菜单动画效果。该项目托管在 GitHub 上,地址为 https://github.com/liuminqian/SvpplyTable。 ... [详细]
  • 作为一名饼干爱好者,我尝试过各种各样的饼干。虽然威化饼和消化饼都有其独特的风味,但我对柠檬夹心饼干情有独钟。这种饼干不仅口感丰富,还带有清新的柠檬香味。 ... [详细]
  • 在 PHP 中,使用 `continue` 关键字结合数字可以有效地终止嵌套的 `foreach` 循环。本文将详细介绍如何使用 `continue` 加数字来控制不同层次的循环。 ... [详细]
  • 本文介绍了一种使用CSS3和jQuery实现的35款SVG图标加载动画。这些动画不仅视觉效果出色,还能提升用户体验。通过本文,您可以了解如何在项目中应用这些动画。 ... [详细]
author-avatar
我跟孔子一个姓
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有