通过 ResourcePath API 支持文件和文件夹中的 % 和 #
对文件和文件夹中 % 和 # 的支持已部署到 SharePoint Online 中。 遗憾的是,由于现有的 API 结构和调用模式,有时不确定是否可以使用这些文件名。 你可以在我们的开发人员博客上找到此问题的更多背景知识。
总而言之,新的 API 已添加到 SharePoint Online 客户端对象模型 (CSOM) 外围,以提供对 # 和 % 字符的支持。
新的 ResourcePath 类
回顾一下,值得注意的是,基于字符串的现有 SharePoint API(例如 SPFileCollection.GetByUrl)通过自动假设路径中的 % 和 # 字符表示 URL 已编码,从而处理已编码和已解码的 URL。 新增对文件和文件夹中 % 和 # 的支持后,这种自动处理现在是存在问题的,因为它可能导致下游代码忽略或不当处理带有 % 和 # 的文件名。
已向 API 添加一个新类:Microsoft.SharePoint.Client.ResourcePath
。 ResourcePath 类是支持这些新字符的基础。 它提供了一种明确的全新方式来解决 SharePoint 和 OneDrive for Business 中的一个问题,这是因为它假定 URL 已解码并且仅使用已解码 URL。 它代替基于字符串的路径来表示网站集、站点、文件、文件夹或其他项目以及 OneDrive for Business 的完整(绝对)或部分(相对)URL。 要正确支持 URL 中的 % 和 #,必须使用基于 ResourcePath 的 API 以及已解码 URL。
ResourcePath 只需通过调用静态函数 ResourcePath.FromDecodedUrl(string)
即可进行构造。 可以通过调用属性 DecodedUrl 从 ResourcePath 对象访问传入的输入值。
对于需要使用基于字符串的 URL 的现有调用,必须确定是否已使用编码或解码的 URL 提供代码路径来促成基于字符串的 URL 调用,以及这些代码路径是否也允许定位标记链接(即在文件 URL 基础之上添加 # 书签。)
注意
不要简单地使用 ResourcePath.FromDecodedUrl
查找和替换基于字符串的 URL API 的现有用法。 使用 ResourcePath.FromDecodedUrl(string)
API 前,需要先正确确定 URL 并解码 URL(若可能)。
如果促成基于字符串的 SharePoint API 调用的代码路径使用了已解码 URL(例如“FY17 Report.docx”),可以直接使用本文稍后介绍的 ResourcePath.FromDecodedUrl(string)
以及等效 ResourcePath 方法替代这些调用。
请注意,在许多情况下,通过 API 从 SharePoint 读取 URL 时,还会提供 ResourcePath 使这些代码模式更加一致,从而可使用 ResourcePath 替代 URL。
另请注意,此更改同样适用于基于 SharePoint REST 的调用。 请阅读下面的方案,以查看 REST 中这些新 API 的示例。
基于 ResourcePath 且支持 # 和 % 的新 API
下表展示我们引入以替代现有 API 的新 API,用于支持 # 和 %。 为便于对比,我们并排列出了旧 API 和新 API。 这些 API 的核心功能不会改变,但是表示项目位置的方式会。
有关新 API 的文档,请参阅 SharePoint Online 的 .NET 客户端 API 参考。 我们列出了 .NET CSOM API,但是我们的 JavaScript CSOM 库中也提供了相同形式的新方法。
程序集 Microsoft.SharePoint.Client.dll
类型 | 旧方法 | 新方法 |
---|---|---|
Microsoft.SharePoint.SPList | AddItem(Microsoft.SharePoint.SPListItemCreationInformation) | AddItemUsingPath(SPListItemCreationInformationUsingPath parameters) |
Microsoft.SharePoint.SPFile | MoveTo(System.String, Microsoft.SharePoint.SPMoveOperations) | MoveToUsingPath(SPResourcePath newPath, SPMoveOperations moveOperations) |
Microsoft.SharePoint.SPFile | CopyTo(System.String, Boolean) | CopyToUsingPath(SPResourcePath newPath, bool overwrite) |
Microsoft.SharePoint.SPFileCollection | GetByUrl(System.String) | GetByPath(SPResourcePath) |
Microsoft.SharePoint.SPFileCollection | Add(System.String, Microsoft.SharePoint.SPTemplateFileType) | AddUsingPath(SPResourcePath, SPFileCollectionAddWithTemplateParameters) |
Microsoft.SharePoint.SPFolder | MoveTo(System.String) | MoveToUsingPath(SPResourcePath newPath) |
Microsoft.SharePoint.SPFolder | AddSubFolder(System.String) | AddSubFolderUsingPath(SPResourcePath leafPath) |
Microsoft.SharePoint.SPFolderCollection | GetByUrl(System.String) | GetByPath(SPResourcePath path) |
Microsoft.SharePoint.SPFolderCollection | Add(System.String) | AddUsingPath(SPResourcePath path, SPFolderCreationInformation parameters) |
AddWithOverwrite(string url, bool overwrite) | ||
Microsoft.SharePoint.SPRemoteWeb | GetFileByServerRelativeUrl(System.String) | GetFileByServerRelativePath(SPResourcePath path) |
Microsoft.SharePoint.SPWeb | GetList(System.String) | GetListUsingPath(SPResourcePath) |
Microsoft.SharePoint.SPWeb | GetListItem(System.String) | GetListItemUsingPath(SPResourcePath) |
以下 CSOM 对象返回可以在这些 API 中使用的 ResourcePath 属性。 虽然旧属性也返回已解码 URL,但为了方便、简单和明确地调用这些 API,提供了新的 ResourcePath 属性。 一个例外情况是 SPFolder.WelcomePage 属性,它以前返回已编码和未编码的 URL;现在明确通过 WelcomePagePath 属性返回。
类型 | 旧属性 | 新属性 |
---|---|---|
Microsoft.SharePoint.SPList | DefaultViewUrl | DefaultViewPath |
Microsoft.SharePoint.SPList | DefaultEditFormUrl | DefaultEditFormPath |
Microsoft.SharePoint.SPList | DefaultNewFormUrl | DefaultNewFormPath |
Microsoft.SharePoint.SPList | DefaultDisplayFormUrl | DefaultDisplayFormPath |
Microsoft.SharePoint.SPAttachment | ServerRelativeUrl | ServerRelativePath |
Microsoft.SharePoint.SPFile | ServerRelativeUrl | ServerRelativePath |
Microsoft.SharePoint.SPFolder | ServerRelativeUrl | ServerRelativePath |
Microsoft.SharePoint.SPFolder | WelcomePage | WelcomePagePath/WelcomePageParameters |
Microsoft.SharePoint.SPView | ServerRelativeUrl | ServerRelativePath |
Microsoft.SharePoint.SPDocumentLibraryInformation | ServerRelativeUrl | ServerRelativePath |
确定 URL 格式并可支持 # 和 % 的现有 API
以下 API 仅接受正确编码的 URL 作为输入。 它们还支持正在编码的 URL,只要 URL 可以在没有任何歧义的情况下使用即可。 也就是说,至少要对 URL 路径中的 # 或 % 字符进行 % 编码。 这些 API 将以现有方式继续运行。 URL 中的 #
被视为片段分隔符,但不是 URL 路径的一部分。
类型 | 旧属性 |
---|---|
Microsoft.SharePoint.SPWeb | GetFileByUrl(System.String) |
Microsoft.SharePoint.SPWeb | GetFileByWOPIFrameUrl(System.String) |
Microsoft.SharePoint.SPWeb | GetFileByLinkingUrl(System.String) |
添加以下 C# 属性以返回明确编码的 System.Uri,以与上述 API 一起使用。 以下 API 的较旧变体返回已解码的 URL,由于它们从不包含 # 或 % 字符,因此 URL 非常明确。 我们不想在以后中断较旧变体的已解码行为,以在路径中编码 % 和 # 字符。 因此创建了新的 API。
类型 | 旧属性 | 新属性 |
---|---|---|
Microsoft.SharePoint.SPFile | LinkingUrl | LinkingUri |
Microsoft.SharePoint.SPFile | ServerRedirectedEmbedUrl | ServerRedirectedEmbedUri |
示例代码
CSOM 方案
将文件添加到文件夹 (.net)
ClientContext context = new ClientContext("http://site");
Web web = context.Web;
// Get the parent folder
ResourcePath folderPath = ResourcePath.FromDecodedUrl("/Shared Documents");
Folder parentFolder = web.GetFolderByServerRelativePath(folderPath);
// Create the parameters used to add a file
ResourcePath filePath = ResourcePath.FromDecodedUrl("/Shared Documents/hello world.txt");
byte[] fileContent = System.Text.Encoding.UTF8.GetBytes("sample file content");
FileCollectionAddParameters fileAddParameters = new FileCollectionAddParameters();
fileAddParameters.Overwrite = true;
using (MemoryStream contentStream = new MemoryStream(fileContent))
{
// Add a file
Microsoft.SharePoint.Client.File addedFile = parentFolder.Files.AddUsingPath(filePath, fileAddParameters, contentStream);
// Select properties of added file to inspect
context.Load(addedFile, f => f.UniqueId, f1 => f1.ServerRelativePath);
// Perform the actual operation
context.ExecuteQuery();
// Print the results
Console.WriteLine(
"Added File [UniqueId:{0}] [ServerRelativePath:{1}]",
addedFile.UniqueId,
addedFile.ServerRelativePath.DecodedUrl);
}
将子文件夹添加到文件夹 (.net)
ClientContext context = new ClientContext("http://site");
Web web = context.Web;
// Get the parent folder
ResourcePath folderPath = ResourcePath.FromDecodedUrl("Shared Documents");
Folder parentFolder = web.GetFolderByServerRelativePath(folderPath);
// Create the parameters used to add a folder
ResourcePath subFolderPath = ResourcePath.FromDecodedUrl("Shared Documents/sub folder");
FolderCollectionAddParameters folderAddParameters = new FolderCollectionAddParameters();
folderAddParameters.Overwrite = true;
// Add a sub folder
Folder addedFolder = parentFolder.Folders.AddUsingPath(subFolderPath, folderAddParameters);
// Select properties of added file to inspect
context.Load(addedFolder, f => f.UniqueId, f1 => f1.ServerRelativePath);
// Perform the actual operation
context.ExecuteQuery();
// Print the results
Console.WriteLine(
"Added Folder [UniqueId:{0}] [ServerRelativePath:{1}]",
addedFolder.UniqueId,
addedFolder.ServerRelativePath.DecodedUrl);
获取 Web 中的文件 (.net)
ClientContext context = new ClientContext("http://site");
Web web = context.Web;
// Get the file
ResourcePath filePath = ResourcePath.FromDecodedUrl("/Shared Documents/hello world.txt");
File file = web.GetFileByServerRelativePath(filePath);
// Select properties of the file
context.Load(file, f => f.UniqueId, f1 => f1.ServerRelativePath);
// Perform the actual operation
context.ExecuteQuery();
// Print the results
Console.WriteLine(
"File Properties [UniqueId:{0}] [ServerRelativePath:{1}]",
file.UniqueId,
file.ServerRelativePath.DecodedUrl);
REST 方案
获取文件夹
url: http://site url/_api/web/GetFolderByServerRelativePath(decodedUrl='library name/folder name')
method: GET
headers:
Authorization: "Bearer " + accessToken
accept: "application/json;odata=verbose" or "application/atom+xml"
创建文件夹
url: http://site url/_api/web/Folders/AddUsingPath(decodedurl='/document library relative url/folder name')
method: POST
headers:
Authorization: "Bearer " + accessToken
X-RequestDigest: form digest value
accept: "application/json;odata=verbose"
content-type: "application/json;odata=verbose"
获取文件
url: http://site url/_api/web/GetFileByServerRelativePath(decodedUrl='folder name/file name')
method: GET
Headers:
Authorization: "Bearer " + accessToken
accept: "application/json;odata=verbose" or "application/atom+xml"
添加文件
url: http://site url/_api/web/GetFolderByServerRelativePath(decodedUrl='folder name')/Files/AddStubUsingPath(decodedurl='testfile.txt')
methods: POST
Headers:
Authorization: "Bearer " + accessToken
X-RequestDigest: form digest value
accept: "application/json;odata=verbose"
content-type: "application/json;odata=verbose"
Content-Length: length