2016 年 2 月

第 31 卷,第 2 期

此文章由机器翻译。

Windows 10 - 使用官方 OneDrive SDK 实现 UWP 应用

通过 Laurent Bugnion | 2016 年 2 月

在第一部分的这两篇系列文章 (msdn.com/magazine/mt614268),我谈到直接从通用 Windows 平台 (UWP) 应用程序,通过 HTTP 使用 OneDrive Api 使用 HttpClient 将放在调用。这样就有了转非常深入探讨 REST 的基础知识以及查看如何.NET 应用程序可以充分利用现代编程技术,如 async/await 关键字和 HttpClient 库可以呼叫,对现代 Web Api 的机会。我还介绍了身份验证机制使用 OAuth 协议,允许用户承载网页中输入其凭据,以便在用户和凭据服务之间的通信是完全透明的宿主应用程序的工作方式。我实现这一用法的 XAML 页面中承载 web 视图。

实现身份验证和 REST 调用不是非常困难,但工作,尤其是当你想要跟踪您的库的所有最新的更改和添加最新。这是 Microsoft 发布了 OneDrive SDK,您可以将添加到您的应用程序以轻松的方式 (使用 NuGet 程序包管理器) 的原因。这是一个非常有用的组件和 true"新增功能 Microsoft"的方式,该库是打开源,以及在 GitHub 上发布 bit.ly/1WX0Y03

为了说明这篇文章,完整的示例,请参阅 1drv.ms/1ObySnz

使用新的 SDK 进行身份验证

以前的文章和官方 SDK 中所述的"低级"实现之间的最大差异之一是身份验证机制。以前,我手动实现 OAuth,必须创建多个部件,必须一起播放:

  • WebView 向用户显示与 Microsoft 身份验证服务,发送的网页,以便用户名和密码将直接发送到该服务,而不知道此应用程序。
  • XAML 页面承载 WebView,并且等待分析过程成功时由服务返回的身份验证令牌。
  • 一种负责确定身份验证令牌是否可用且有效,并显示身份验证页上,是否不这样的客户端身份验证服务。

新的 SDK 简化了这很大差别,为开发人员和用户。

开发人员的的身份验证

对于开发人员,则身份验证过程已几乎普通。由 SDK 进行处理整个工作流。更为可喜的是,在后台,SDK 将使用名为 OnlineIdAuthenticator 的 Windows 应用商店应用的一项功能。此类处理在操作系统级别的身份验证机制,因此不再需要解析的身份验证令牌。

除了 OnlineIdAuthenticator,适用于 Windows 10 的 OneDrive SDK 还支持 WebAuthenticationBroker 类,该类提供了更多"经典"中的日志记录通过输入用户名和密码,但还负责分析身份验证令牌和与服务的所有对话框。您将看到这些本文后面的两种身份验证模式的示例。

用户的身份验证

对于最终用户的主要优点是凭据的 OnlineIdAuthenticator 利用已有在操作系统级别的登录的 Windows 用户。如果 Windows 用户登录到使用他的 Windows 帐户 (这通常是这种情况) 相关联的 OneDrive 帐户,他甚至不需要重新输入其用户名和密码。整个身份验证机制是他的透明的。

注意: 除了 Microsoft 帐户 (MSA) 对于用户来说,如 Outlook.com、 Live.com 或 Hotmail.com 地址 OneDrive SDK 还支持 Azure Active Directory (Azure AD) 的业务用户。这非常适用于企业中管理其用户这种方式。MSA 是可用于 Microsoft.NET Framework 4.5.1 (如 Windows Presentation Foundation 应用程序或 Windows 窗体)、 Windows 应用商店和 Windows Phone 应用程序。Azure AD 是可用于 Windows 窗体、 Windows 应用商店 8.1 和 UWP 应用程序。

将新的 UWP 应用程序在 Windows 应用商店相关联

对于工作 OnlineIdAuthenticator,很有必要向 Windows 应用商店注册新应用程序。请注意,您无需实际提交您的应用程序的 Windows 应用商店,以便使用 OneDrive 的 SDK。注册将创建一些对于您的应用程序,必须在文本框中输入应用程序清单 (Package.appxmanifest) 的唯一 Id。当用户尝试向 OneDrive 服务验证自身身份时,这些 Id 用于唯一标识该应用程序。在这种情况下,Windows 应用商店中注册您的应用程序的过程将替换已从 OneDrive 开发人员中心前面获取的客户端 ID。

若要在 Windows 应用商店注册你的应用程序,您需要先转到 Windows 开发人员中心 dev.windows.com 和登录您的 Windows 开发人员帐户来访问仪表板。具体取决于您的状态,您可能需要的帐户注册并提供付款信息。

登录后的仪表板上,查找"提交您的应用程序"链接。这将转到概述页可从中查看现有应用程序,并提交新的活动,并将其注册到 Windows 应用商店获取。创建新的 Windows 应用商店应用程序需要唯一的应用程序名称,单击创建新的应用按钮后将输入。然后,单击复选的可用性,以确保你选择的应用程序名称是独一无二的。将保留您选择的名称,因为很好的做法,使用临时名称将永远不会发布的测试应用程序。这样一来避免阻止另一个开发人员的应用程序名称。此外,请确保你拥有对要保留以避免法律行动从品牌所有者的名称的权限。最后请注意,是否未提交应用程序一年中的,名称保留将会丢失。此示例中,以便我保留 TestOneDriveSdk_001,碰巧是可用的名称。

实现和测试身份验证

现在是时候创建应用程序并添加 OneDrive SDK。首先,使用 Visual Studio,创建一个新 UWP 应用 Windows 10。应用程序无需具有与在 Windows 应用商店中保留相同的名称,但很好的做法使用相同的名称。

创建的应用程序后,通过右键单击解决方案资源管理器中的项目并从上下文菜单中选择管理 NuGet 包打开 NuGet 程序包管理器。选择浏览之上程序包管理器,搜索 Microsoft.OneDriveSDK 包并将其添加到应用程序。

现在您将添加身份验证到应用程序使用以下步骤:

  • 打开 MainPage.xaml 并向页面添加一个按钮并将其命名为 AuthenticateButton。
  • 在 MainPage.xaml.cs 中,实现单击事件处理程序中所示 图 1

图 1 实现单击事件处理程序

private IOneDriveClient _client;
public MainPage()
{
  InitializeComponent();
  AuthenticateButton.Click += async (s, e) =>
  {
    var scopes = new[]
    {
      "onedrive.readwrite",
      "onedrive.appfolder",
      "wl.signin"
    };
    _client = OneDriveClientExtensions.GetClientUsingOnlineIdAuthenticator(
      _scopes);
    var session = await client.AuthenticateAsync();
    Debug.WriteLine($"Token: {session.AccessToken}");
  };
}

在代码中 图 1, ,识别已上一篇文章中的示例中使用的作用域。这将为您提供到文件,以及应用程序文件夹的读/写访问。提醒一下,此特殊文件夹直接在根目录下的应用程序文件夹中创建,并将执行与应用程序相同的名称。这是最好保存漫游设置,在线文档,依此类推。

在运行要对其进行测试的应用程序之前,您仍需要将它与之前保留的 Windows 应用商店名称相关联。为此,请按以下步骤操作:

  • 在解决方案资源管理器中右键单击该项目并选择与应用商店的应用商店/关联应用程序。这是您需要 UWP 应用程序发布到 Windows 应用商店之前的准备工作。在这种情况下,这样做是非常早在开发中由于需要生成的信息。
  • 在对话框中,将应用与 Windows 应用商店关联按下一步按钮,然后登录到应用商店。请确保使用相同的凭据用于保留该名称。
  • 在登录后,您应该看到你保留的应用程序名称。请注意,您还可以预留直接从该对话框名称是否不想使用基于 Web 的仪表板。
  • 选择名称,然后单击下一步,然后在相关联。

现在您已准备好测试身份验证机制。在调试模式下运行该应用程序并单击身份验证按钮。您应看到一个对话框,在征得您同意您的应用程序的基础上。但是,请注意,您不必输入你的 Microsoft 凭据。相反,会自动使用您的 Windows 登录凭据。

在执行中的代码后 图 1, ,您将看到 SessionToken (身份验证令牌) 在输出窗口中的。您将能够在后续的 API 调用,就像在第一篇文章中使用此令牌。如果您运行应用程序以后,并再次按下进行身份验证,您可能甚至不必再次确认,因为您同意的情况下会被缓存直至签字认可。这为用户提供无缝登录体验。

我们为什么不切换帐户?

此示例中所示 图 1 使用 SDK 的 GetClientUsingOnlineIdAuthenticator 扩展方法,它事实上,使用 OnlineIdAuthenticator 类。如我所述,此对象将使用已登录的用户凭据,从而可为大多数用户的体验非常得更为方便的登录名。

此方法的缺点但是,是将没有办法在登录时选择的其他帐户。在这种情况下,此身份验证方法非常适用于具有只能有一个使用其 Microsoft 帐户相关联的 OneDrive 帐户的基本用户。但对于具有多个 OneDrive 帐户电源用户,OnlineIdAuthenticator 可能太有限。幸运的是,您可以切换到另一种方法很容易地。

使用 WebAuthenticationBroker

如果用户需要能够使用其凭据显式 (例如,若要让其切换到比他已登录到 Windows 与不同的帐户) 登录,则最好使用 WebAuthenticationBroker 类。在这里,太,OneDrive SDK 隐藏的大部分复杂性,并可以使用下面的代码创建 OneDrive 客户端:

var client = OneDriveClientExtensions.GetClientUsingWebAuthenticationBroker(
  "[CLIENT ID]",
  _scopes);

在代码中所示 图 1, ,[客户端 ID] 字符串必须替换应用程序的客户端 id。提醒一下,这是您可以在 Windows 开发人员中心应用程序的详细信息中检索的唯一 ID。

如果此微小更改与运行该应用程序,您现在将看到不同的对话框。此对话框使用户可以切换到不同的帐户,这是很好。但是,用户需要手动输入其密码即较低比前面的工作流无缝。由于是在工程中通常,它是取决于您选择的方法最适合于您尝试解决的用例。

使用 SDK 进行访问文件夹和文件

可用且已经过身份验证客户端后,OneDrive SDK 提供了几种方法来检索有关驱动器、 文件夹和文件的信息。在上一篇文章中,您已了解如何将文件结构构成的项、 文件夹、 文件、 音频、 图像、 照片和视频。到目前为止,您必须已从服务获取 JSON 响应和反序列化其手动插入相应的 C# 类。使用 OneDrive SDK 时,这是不再必要因为它将执行该步骤为您处理。为了说明这一点,我将重新运行同一个示例应用程序,如上一篇文章中所示改为使用官方 SDK。

生成请求

若要将请求发送到 OneDrive REST API,SDK 使用对象层次结构组成,所谓"申请生成器"。 例如,获取用户的驱动器是通过 _client。驱动器,并且获得其根文件夹是通过 _client。Drive.Root。在本文后面列出的最常见的请求生成器。

有,当然,许多可能的组合。一旦已获得请求生成器,实际请求是使用请求方法中,创建,并且或者将发送包含一个 HTTP 方法,例如,GetAsync PostAsync。例如,在代码 图 2将获取位于路径 Public/Test/MyFile.txt 和其内容以流形式的文件的元信息。

图 2 下载文本文件的内容

var builder = _client.Drive.Root
  .ItemWithPath("Public/Test/MyFile.txt");
var file = await builder
  .Request()
  .GetAsync();
var contentStream = await builder.Content
  .Request()
  .GetAsync();
Debug.WriteLine($"Content for file {file.Name}:");
using (var reader = new StreamReader(contentStream))
{
  Debug.WriteLine(reader.ReadToEnd());
}

列出几个最常见的请求

列出最常见的请求作为请求生成器此处:

  • _client。合盒诀  生成访问 OneDrive 本身并获取其属性 (IDriveRequestBuilder) 的请求。如果您有多个驱动器,您还可以使用 _client。驱动器,即 IDrivesCollectionRequestBuilder。
  • _client。Drive.Root: 生成访问 OneDrive 的根文件夹 (IItemRequestBuilder) 的请求。
  • _client。Drive.Root.Children: 生成一个请求以获取根文件夹的子级 (IChildrenCollectionRequestBuilder)。之后请求执行 (使用 request ()。GetAsync()),则结果为 IChildrenCollectionPage,其中包含一个名为 NextPageRequest 属性。如果太大的子级的个数,NextPageRequest 属性可以用于访问的项目下一步页。
  • _client。Drive.Root.ItemWithPath("Public/Test"): 生成一个请求以获取该项在根文件夹 (IItemRequestBuilder) 内的公共/测试路径。
  • _client。Drive.Root.ItemWithPath("Public/Test/MyFile.txt")。内容: 生成请求来获取名为 MyFile.txt (IItemContentRequestBuilder) 文件的内容。
  • _client。Drive.Special.AppRoot: 生成访问应用程序文件夹 (IItemRequestBuilder) 的请求。
  • _client。] Drive.Items[SomeId: 生成的请求来访问的项的 id。

每个这些请求构建者可以看到示例来说明这篇文章中的操作中。

上载文件

上载文件的内容会发生情况根据 REST Api 的原则的 PUT 请求。除了这一区别,若要生成的 PUT 请求的机制是非常类似于先前使用 GET 请求。事实上,大部分所需是工作的以实际获取的流。例如,在 UWP 应用中,这可在使用 FileOpenPicker 从 Windows 文件系统加载所选的文件。中的代码 图 3 显示将所选的文件上载到应用程序文件夹 (如果没有错误处理机制) 的简单示例。可以在代码下载中找到更完整的示例。在此示例中,访问 {1>putasync 方法返回的元信息和保存项目的 ID,以便您轻松地访问保存的项更高版本;例如,若要获取指向此项目。

图 3 选择并上载文件的内容

var picker = new FileOpenPicker
{
  SuggestedStartLocation = PickerLocationId.DocumentsLibrary
};
picker.FileTypeFilter.Add("*");
var file = await picker.PickSingleFileAsync();
using (var stream = await file.OpenStreamForReadAsync())
{
  var item = await _client.Drive.Special.AppRoot
    .ItemWithPath(file.Name)
    .Content.Request()
    .PutAsync<Item>(stream);
  // Save for the GetLink demo
  _savedId = item.Id;
}

获取共享的链接

一旦创建项的请求后,此项的唯一链接可获取从 OneDrive 客户端使用返回 IItemCreateLinkRequestBuilder CreateLink 方法。下面的代码演示如何使用你前面保存时您将文件上载到 OneDrive _savedId:

link = await _client.Drive
  .Items[_savedId]
  .CreateLink("view")
  .Request().PostAsync();

当然,可以在任何项请求 (例如,若要获取链接到的文件夹等) 上调用 CreateLink 方法。请注意,该 CreateLink 方法创建的请求需要发布到该服务。CreateLink 方法需要一个参数,它可以是"查看"编辑"。 根据此参数的值,将创建一个只读的链接或读 / 写链接。

更新项

更新项的元信息发生与请求生成器和 UpdateAsync 方法。例如,如本文前面所示上载文件后,您可以使用其 ID (保存 _savedId 属性中) 来修改其名称与此处显示的代码:

var updateItem = new Item
{
  Name = "[NewNameHere]"
};
var itemWithUpdates = await _client
  .Drive
  .Items[_savedId]
  .Request()
  .UpdateAsync(updateItem);

将项移

将项移到新位置是更新其属性的一种特殊情况。在这种情况下,你将更新其 ParentReference 属性,其中包含有关在 OneDrive 中的项的位置的信息。如果您修改此属性与新位置并相应地更新 OneDrive 项,则会移动项目。

在下面的示例中,您可以执行的文件上载早期 (具有保存其 ID _savedId 属性中) 并将其从其原始位置移动到的根文件夹 (当然在现实生活中应用程序中,一些错误处理需要添加对此代码):

var newLocation = await _client.Drive.Root.Request().GetAsync();
var updateItem = new Item
{
  ParentReference = new ItemReference
  {
    Id = newLocation.Id
  }
};
var itemWithUpdates = await _client
  .Drive
  .Items[_savedId]
  .Request()
  .UpdateAsync(updateItem);

复制项目

将项目复制是比将其移稍有不同。有趣的是,当移动或重命名某个项时,异步操作的结果立即出现并具有新的元信息 (如新位置或新名称) 的项实例。复制某个项时,但是,这可能需要一段时间并且而不是等待,直到完成该操作,SDK 返回 IItemCopyAsyncMonitor 的一个实例,就立即开始复制操作。

此实例都有一个名为 CompleteOperationAsync,其轮询在 OneDrive 上的复制操作的结果、 更新的可选进度提供程序,并仅在复制操作完成时返回的项实例的方法。这提供了非常好的 UX,因为它是可以执行其他操作在同一时间,并在复制操作完成时通知用户。当然,正如同每个持续时间很长的操作,则可以取消 (但是,这将取消复制操作本身!) 的轮询。中的代码 图 4 显示已上载到应用程序文件夹的项可复制到的根文件夹的方式。首先,检索的根文件夹本身。然后,获取该文件才能构建一个新的唯一名称 (以避免冲突)。最后,创建并执行向服务器发送复制请求。请注意如何则可以使用 CompleteOperationAsync 方法等待并复制操作完成时通知用户。

图 4 将新上载的项复制到根

var newLocation = await _client.Drive.Root.Request().GetAsync();
// Get the file to access its meta info
var file = await _client.Drive.Items[_savedId].Request().GetAsync();
var newName = Path.GetFileNameWithoutExtension(file.Name)
  + "-"
  + DateTime.Now.Ticks
  + Path.GetExtension(file.Name);
var itemStatus = await _client
  .Drive
  .Items[_savedId]
  .Copy(
    newName,
    new ItemReference
    {
      Id = newLocation.Id
    })
  .Request()
  .PostAsync();
var newItem = await itemStatus.CompleteOperationAsync(
  null,
  CancellationToken.None);
var successDialog = new MessageDialog(
  $"The item has been copied with ID {newItem.Id}",
  "Done!");
await successDialog.ShowAsync();

创建一个新文件夹

在 SDK 中,可能有多个操作,但我继续讲述之前,我想提及另一个有用功能: 创建新文件夹。这一点非常有趣,因为它通过添加项然后将请求发送到 OneDrive,如中所示进行操作的集合 (父文件夹的子级) 图 5。请注意,在这种情况下该方法使用 (AddAsync) 不直接对应于 HTTP 方法 (GET、 POST、 PUT 等等)。一旦创建该文件夹,newFolderCreated 变量将包含必要的信息,尤其是文件夹的 ID:

图 5: 创建一个新的文件夹

var newFolder = new Item
{
  Name = NewFolderNameText.Text,
  Folder = new Folder()
};
var newFolderCreated = _client.Drive
  .Special.AppRoot
  .Children
  .Request()
  .AddAsync(newFolder);
var successDialog = new MessageDialog(
  $"The folder has been created with ID {newFolderCreated.Id}",
  "Done!");
await successDialog.ShowAsync();

签字及更多内容

最后,与客户端的工作完成后,用户可以选择签字认可。这很容易地使用 OneDrive 客户端的 SignOutAsync 方法来执行操作。

除了方法和属性在本文中所述,SDK 中有几个更多的功能。若要确保以获取最新和最大文档,你可以检查这两个不同的文档源:

  • GitHub 上的 OneDrive C# SDK 有相当多的可用文档。你可以找到它在 bit.ly/1k0V2AL
  • 中所述 OneDrive API 本身 bit.ly/1QniW84

错误处理

如果服务调用会发生任何错误情况,将引发 OneDriveException。但是,异常消息不包含实际的错误的信息。相反,错误详细信息包含在 OneDriveException 错误属性 (类型 Microsoft.OneDrive.Sdk.Error) 中。这是在这里可找到的错误消息,以及其他数据来帮助您解决的问题。

可以嵌套错误,因为您轻松地使用 IsMatch 方法以查找错误层次结构中的任意位置的特定错误代码为例:

theException.IsMatch(OneDriveErrorCode.InvalidRequest.ToString());

获取和生成 SDK 源

虽然可以使用 NuGet 程序包管理器添加 SDK,但是它可用于获取源代码;例如,若要进行更改,或将功能添加到代码。这可以轻松地,可以通过下载源 (的代码,或甚至更好地) 通过分叉源的代码从 GitHub 和修改你的分支。

OneDrive SDK 源代码位于 bit.ly/1WX0Y03。要获取的代码并创建一个分叉,可使用您最喜欢 GitHub 的客户端,例如 GitHub 桌面 (desktop.github.com)。一旦在本地计算机上获取的代码,可以在 Visual Studio 中生成它并将其添加到您的应用程序作为项目的引用,例如。从这一刻起,您是在同一个点在完成后添加通过 NuGet SDK。

总结

在本系列文章的第一篇文章,您已了解如何构建强大的库使用 HttpClient、 async/await 关键字和 JSON 序列化程序到 REST API 调用。但是,这要容易得多不是使用它来将这些天,同时它仍是大量工作,尤其是当您想要保留您的库安装最新的新功能。

在本文中,我采用的其他方法,就是使用由 Microsoft 构建在 OneDrive SDK。您看到了如何将库添加到 UWP 应用程序中,身份验证的工作原理 (不管是通过使用已登录的用户凭据以透明方式或通过使用 WebAuthenticationBroker 并为用户提供可能选择的其他帐户,依此类推)。我还演示了最有用的项操作,如获取由其路径或 ID 项信息、 获取文件夹的子级、 下载、 重命名、 移动或复制文件,获取到某一项,以及更多的唯一共享链接。

使用 OneDrive SDK 可在 GitHub 中打开源和 Microsoft 主动开发新功能和修复问题上时,是比以往若要访问 OneDrive 来自 UWP 应用程序更加容易。这将打开了大门各种功能,例如共享文档设备的详细信息之间的漫游设置。


Laurent Bugnion是 IdentityMine(Microsoft 技术的领先公司之一和金牌合作伙伴)的高级总监,他居住在瑞士苏黎世。他在 2010 年编写的书《Silverlight 4 Unleashed》由 Sams 出版,该书是《Silverlight 2 Unleashed》(2008) 的高级续集。他为多个刊物写作,第二年成为 Microsoft 区域总监,第九年成为 Microsoft MVP。他是已知的开放源框架 MVVM Light for Windows,WPF 中,Xamarin 和有关 MVVM Light 受欢迎的 Pluralsight 引用课程的作者。您可通过其博客 galasoft.ch 与他联系。

感谢以下的微软技术专家对本文的审阅: Gina Chernoby