MSGraphMailbag - 复制/移动 SharePoint Online 中的文件和文件夹

本篇我们介绍如何跨 SharePoint Online 网站实现有条件的文件和文件夹的复制和移动,这其实来自一个真实的客户需求。
在这里插入图片描述

业务场景

SharePoint Online 自带的拆箱即用的复制 (Copy To) 和移动 (Move To) 功能很强大,但是可选的目的端网站内容是基于登录用户关注或常访问的网站来显示的,客户希望能够指定用户可以看见的目的端去执行复制和移动操作。

解决方案

假如我们要将文件从网站 A 复制到网站 B,例如
A:https://contoso.sharepoint.com/sites/SiteA/Documents/
B:https://contoso.sharepoint.com/sites/SiteB/Documents/

复制文件

  1. 获取源端网站 A 的网站集 ID
GET
https://graph.microsoft.com/v1.0/sites/contoso.sharepoint.com:/sites/SiteA?$select=id
Response:
{
    "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#sites(id)/$entity",
    "id": "contoso.sharepoint.com,1af9d2c5-2b3b-47d2-a167-ffd5d0c45205,e748bad1-cb75-432f-8bb1-adff3b9ef5da"
}
  1. 使用获得到的网站集 ID 去获取文档库的列表
GET https://graph.microsoft.com/v1.0/sites/contoso.sharepoint.com,1af9d2c5-2b3b-47d2-a167-ffd5d0c45205,e748bad1-cb75-432f-8bb1-adff3b9ef5da/drives?$select=id,name

Response:
{
    "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#drives(id,name)",
    "value": [
        {
            "id": "b!xdL5Gjsr0kehZ__V0MRSBdG6SOd1yy9Di7Gt_zue9dq9z2zXDxX4RYKTxY09UkQ-",
            "name": "Documents"
        },
        {
            "id": "b!xdL5Gjsr0kehZ__V0MRSBdG6SOd1yy9Di7Gt_zue9doAJ43YI-NhR6zMPnX1eLzZ",
            "name": "MyDocs1"
        },
        {
            "id": "b!xdL5Gjsr0kehZ__V0MRSBdG6SOd1yy9Di7Gt_zue9dr4572v55yoQo_RWg6MAlAR",
            "name": "MyDocs2"
        }
    ]
}
  1. 现在我们得到了文档库 (Documents) 的 ID,我们就可以对里面的文件和文件夹进行枚举了
GET https://graph.microsoft.com/v1.0/sites/contoso.sharepoint.com,1af9d2c5-2b3b-47d2-a167-ffd5d0c45205,e748bad1-cb75-432f-8bb1-adff3b9ef5da/drives/
b!xdL5Gjsr0kehZ__V0MRSBdG6SOd1yy9Di7Gt_zue9dq9z2zXDxX4RYKTxY09UkQ-/list/drive/root/children?$select=id,name,webUrl

Response:
{
    "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#sites('contoso.sharepoint.com%2C1af9d2c5-2b3b-47d2-a167-ffd5d0c45205%2Ce748bad1-cb75-432f-8bb1-adff3b9ef5da')/
drives('b%21xdL5Gjsr0kehZ__V0MRSBdG6SOd1yy9Di7Gt_zue9dq9z2zXDxX4RYKTxY09UkQ-')/list/drive/root/children(id,name,webUrl)",
    "value": [
        {
            "@odata.etag": "\"{297E7CA7-4C49-440D-8E5F-84844DA865D0},1\"",
            "id": "017LC4LMFHPR7CSSKMBVCI4X4EQRG2QZOQ",
            "name": "Decks",
            "webUrl": "https://contoso.sharepoint.com/sites/SiteA/Shared%20Documents/Decks"
        },
        {
            "@odata.etag": "\"{F3226AA0-414F-4523-8364-9E03AF05801B},1\"",
            "id": "017LC4LMFANIRPGT2BENCYGZE6AOXQLAA3",
            "name": "AuthCodePPEGuide.pdf",
            "webUrl": "https://contoso.sharepoint.com/sites/SiteA/Shared%20Documents/AuthCodePPEGuide.pdf"
        }
    ]
}
  1. 如果有更明确的要求,我们也可以将上面的查询通过 $filter Odata 参数进行优化,比如我们想要复制 AuthCodePPEGuide.pdf 这个文件,使用下面的查询获取到它的 ID
GET https://graph.microsoft.com/v1.0/sites/contoso.sharepoint.com,1af9d2c5-2b3b-47d2-a167-ffd5d0c45205,e748bad1-cb75-432f-8bb1-adff3b9ef5da/drives/
b!xdL5Gjsr0kehZ__V0MRSBdG6SOd1yy9Di7Gt_zue9dq9z2zXDxX4RYKTxY09UkQ-/list/drive/root/children?$filter=startswith(name, 'AuthCodePPEGuide.pdf')&$select=id,name,webUrl

Response:
{
    "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#sites('contoso.sharepoint.com%2C1af9d2c5-2b3b-47d2-a167-ffd5d0c45205%2Ce748bad1-cb75-432f-8bb1-adff3b9ef5da')/
drives('b%21xdL5Gjsr0kehZ__V0MRSBdG6SOd1yy9Di7Gt_zue9dq9z2zXDxX4RYKTxY09UkQ-')/list/drive/root/children(id,name,webUrl)",
    "value": [
        {
            "@odata.etag": "\"{F3226AA0-414F-4523-8364-9E03AF05801B},1\"",
            "id": "017LC4LMFANIRPGT2BENCYGZE6AOXQLAA3",
            "name": "AuthCodePPEGuide.pdf",
            "webUrl": "https://contoso.sharepoint.com/sites/SiteA/Shared%20Documents/AuthCodePPEGuide.pdf"
        }
    ]
}
  1. 现在我们能够通过 ID 获取到这个文件对象了
GET https://graph.microsoft.com/v1.0/sites/contoso.sharepoint.com,1af9d2c5-2b3b-47d2-a167-ffd5d0c45205,e748bad1-cb75-432f-8bb1-adff3b9ef5da/drive/items/
017LC4LMFANIRPGT2BENCYGZE6AOXQLAA3
  1. 使用与上面步骤 1 和 2 类似的查询,我们可以获得目的端网站的网站集 ID 和文档库 ID,类似下面的查询
https://graph.microsoft.com/v1.0/sites/contoso.sharepoint.com,1af9d2c5-2b3b-47d2-a167-ffd5d0c45205,e748bad1-cb75-432f-8bb1-adff3b9ef5da/drives/
b!w8qjV86a-EibM8Lpka5JcNG6SOd1yy9Di7Gt_zue9dq9z2zXDxX4RYKTxY09UkQ-
  1. 这里我们需要用到一个叫做 parentReference 的属性,它用来表示目的端的位置
  2. 通过执行 Microsoft Graph 查询来枚举目的端文档库,选择每个条目的 ID、Name 和 parentReference 属性
GET https://graph.microsoft.com/v1.0/sites/contoso.sharepoint.com,1af9d2c5-2b3b-47d2-a167-ffd5d0c45205,e748bad1-cb75-432f-8bb1-adff3b9ef5da/drives/
b!w8qjV86a-EibM8Lpka5JcNG6SOd1yy9Di7Gt_zue9dq9z2zXDxX4RYKTxY09UkQ-/list/drive/root/children?$select=id,name,parentReference

Response:
{
    "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#sites('contoso.sharepoint.com%2C1af9d2c5-2b3b-47d2-a167-ffd5d0c45205%2Ce748bad1-cb75-432f-8bb1-adff3b9ef5da')
/drives('b%21w8qjV86a-EibM8Lpka5JcNG6SOd1yy9Di7Gt_zue9dq9z2zXDxX4RYKTxY09UkQ-')/list/drive/root/children(id,name,parentReference)",
    "value": [
        {
            "@odata.etag": "\"{F72ACBB9-419C-41FC-965C-F90DDE31F699},1\"",
            "id": "01U7PKJ3NZZMVPPHCB7RAZMXHZBXPDD5UZ",
            "name": "DropFolder",
            "parentReference": {
                "driveId": "b!w8qjV86a-EibM8Lpka5JcNG6SOd1yy9Di7Gt_zue9dq9z2zXDxX4RYKTxY09UkQ-",
                "driveType": "documentLibrary",
                "id": "01U7PKJ3N6Y2GOVW7725BZO354PWSELRRZ",
                "path": "/drives/b!w8qjV86a-EibM8Lpka5JcNG6SOd1yy9Di7Gt_zue9dq9z2zXDxX4RYKTxY09UkQ-/root:"
            }
        },
        {
            "@odata.etag": "\"{08CB141D-4471-445B-B835-776E78A67C23},3\"",
  "id": "01U7PKJ3I5CTFQQ4KELNCLQNLXNZ4KM7BD",
            "name": "NDP462-DevPack-KB3151934-ENU.zip",
            "parentReference": {
                "driveId": "b!w8qjV86a-EibM8Lpka5JcNG6SOd1yy9Di7Gt_zue9dq9z2zXDxX4RYKTxY09UkQ-",
                "driveType": "documentLibrary",
                "id": "01U7PKJ3N6Y2GOVW7725BZO354PWSELRRZ",
                "path": "/drives/b!w8qjV86a-EibM8Lpka5JcNG6SOd1yy9Di7Gt_zue9dq9z2zXDxX4RYKTxY09UkQ-/root:"
            }
        }
    ]
}
  1. 接下来我们就可以使用上面步骤中获取到的 parentReference 属性来复制文件到文档库的根目录了
  2. 如果我们想要复制到指定的目录,需要 parentReference 属性中的文件夹 ID,例如复制到DropFolder文件夹
"parentReference": {
       "driveId": "b!w8qjV86a-EibM8Lpka5JcNG6SOd1yy9Di7Gt_zue9dq9z2zXDxX4RYKTxY09UkQ-",
       "id": "01U7PKJ3NZZMVPPHCB7RAZMXHZBXPDD5UZ"
    }
  1. 在步骤 5 中我们通过 ID 定义了要复制的文件,在步骤 10 中我们指定了要复制的目的端信息,接下来使用 POST 请求进行实际的复制操作
//To copy the file to the root of the destination library

POST https://graph.microsoft.com/v1.0/sites/contoso.sharepoint.com,1af9d2c5-2b3b-47d2-a167-ffd5d0c45205,e748bad1-cb75-432f-8bb1-adff3b9ef5da/drive/items/
017LC4LMFANIRPGT2BENCYGZE6AOXQLAA3/copy
{
    "parentReference": {
        "driveId": -"
        "id": "01U7PKJ3N6Y2GOVW7725BZO354PWSELRRZ"
    },
    "name": "AuthCodePPEGuide.pdf"
}
//To copy the file to “DropFolder” folder in the destination library
POST https://graph.microsoft.com/v1.0/sites/contoso.sharepoint.com,1af9d2c5-2b3b-47d2-a167-ffd5d0c45205,e748bad1-cb75-432f-8bb1-adff3b9ef5da/drive/items/
017LC4LMFANIRPGT2BENCYGZE6AOXQLAA3/copy
{
    "parentReference": {
       "driveId": "b!w8qjV86a-EibM8Lpka5JcNG6SOd1yy9Di7Gt_zue9dq9z2zXDxX4RYKTxY09UkQ-",
       "id": "01U7PKJ3N6Y2GOVW7725BZO354PWSELRRZ"
    },
    "name": "AuthCodePPEGuide.pdf"
}
Response:
HTTP 202 Accepted
{
    "cache-control": "no-cache",
    "client-request-id": "0ffe0ea7-85f6-402e-f504-1a8740423832",
    "location": "https://contoso.sharepoint.com/sites/SiteA/_api/v2.1/drive/operations/faa1c015-a4af-4dfb-9abf-03cd22890db3?c=ZU0xOVRzMGc4RFhJSV...",
    "request-id": "3868dff6-cdbd-45d1-bf3d-9ab98ea5491b"
}
  1. 我们可以通过返回请求的 location 属性查看复制的进度和状态
    在这里插入图片描述
    移动文件

跟复制操作类似,首先获取源端文件

https://graph.microsoft.com/v1.0/sites/contoso.sharepoint.com,bc0a0284-87ff-4fcc-b039-0b7e02823759,e748bad1-cb75-432f-8bb1-adff3b9ef5da/drive/items/
01HD766IY4YTCVBFQNOBEZUBDSXXYDAQIJ

获取 parentReference 属性

"parentReference": {
       "driveId": "b!w8qjV86a-EibM8Lpka5JcNG6SOd1yy9Di7Gt_zue9dq9z2zXDxX4RYKTxY09UkQ-",
       "id": "01U7PKJ3N6Y2GOVW7725BZO354PWSELRRZ"
    }

使用PATCH操作

PATCH https://graph.microsoft.com/v1.0/sites/contoso.sharepoint.com,bc0a0284-87ff-4fcc-b039-0b7e02823759,e748bad1-cb75-432f-8bb1-adff3b9ef5da/drive/items/
01HD766IY4YTCVBFQNOBEZUBDSXXYDAQIJ

Headers:
Prefer:respond-async
Request body:
{
    "parentReference": {
        "driveId": "b!w8qjV86a-EibM8Lpka5JcNG6SOd1yy9Di7Gt_zue9dq9z2zXDxX4RYKTxY09UkQ-",
        "id": "01U7PKJ3N6Y2GOVW7725BZO354PWSELRRZ"
    },
    "name": "ProjectYRequirements.docx"
}
Response:
{
    "cache-control": "no-cache",
    "client-request-id": "8248a200-00cc-51cc-576c-b48d16109cf4",
    "location": "https://contoso.sharepoint.com/sites/Web03/_api/v2.1/drive/operations/7e75fb87-07ea-4b85-8b40-369d1343ba38?c=T3QzNlIzOG1xdW1VOGR3OGlMZjFQYm5uR21...",
    "request-id": "9e419a03-4421-413a-9753-8d6dec74515d"
}

关于上述操作的提示:

  • 如果目标名称不匹配,我们将得到 HTTP 400 - Bad Request 错误,错误信息为"invalid request",这与文件大小无关
  • 如果匹配文件名,我们也会遇到 HTTP 400 - Bad Request,但错误代码为"Requested move requires an async response, add ‘Prefer: respond-async’ to allow",确保请求中确实添加了
  • 要成功移动,源库和目标库必须具有相同的结构,这是因为Move操作也会将文件的元数据一起带着

使用 Microsoft Graph SDK 复制文件

//Create the destination parentReference
var parentReference = new ItemReference
{
    DriveId= "b!w8qjV86a……z2zXDxX4RYKTxY09UkQ-",
    Id= "01U7PKJ3N6Y2GOV……5BZO354PWSELRRZ"
};

//File name to save as
var fileName = "AuthCodePPEGuide.pdf";

//Copy the file over to the destination library
var result = await graphClient.Sites["contoso.sharepoint.com,1af9d2c5-2b3b-47d2-a167-ffd5d0c45205,e748bad1-cb75-432f-8bb1-adff3b9ef5da"]
    .Drives["b!xdL5Gjsr0kehZ__V0MRSBd……dq9z2zXDxX4RYKTxY09UkQ-"]
    .Items["017LC4LMFANIR……CYGZE6AOXQLAA3"].Copy(fileName, parentReference)
    .Request().PostAsync();

本篇实际上介绍了不少 Microsoft Graph 相关的请求,多看多练,熟能生巧。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值