ResourcePath API 使用時にファイルとフォルダーで % と # をサポートする
% と # を含むファイルとフォルダーのサポートが SharePoint Online に展開されています。 残念ながら、既存の API の構造や呼び出しパターンのために、これらのファイル名が関係する作業はあいまいになることがあります。 開発者ブログで、この背後にある詳細な背景を紹介しています。
要約すると、# と % の文字のサポートを提供するために、SharePoint Online クライアント オブジェクト モデル (CSOM) サーフェスに新しい API が追加されました。
新しい ResourcePath クラス
要点をまとめると、既存の文字列ベースの SharePoint API (SPFileCollection.GetByUrl など) は、パスに含まれる % と # の文字は URL がエンコードされていることを暗黙的に示していると自動的に想定することによって、エンコードされた URL とデコードされた URL の両方を処理するということに注意してください。 ファイルとフォルダーで新たに % と # がサポートされるようになったことで、この自動処理は問題になることがあります。なぜなら、この処理によって、% と # が含まれるファイル名がダウンストリーム コードで無視されたり正しく処理されなかったりする可能性があるためです。
新しいクラス Microsoft.SharePoint.Client.ResourcePath
が API に追加されました。 ResourcePath クラスは、これらの新しい文字のサポートに不可欠です。 これは、デコードされた URL を想定し、デコードされた URL のみを処理するため、SharePoint と OneDrive for Business 内のアイテムを扱ううえであいまいさのない新しい方法を提供します。 これは、サイト コレクション、サイト、ファイル、フォルダーまたはその他の成果物と OneDrive for Business の完全 (絶対) または部分 (相対) URL を表す文字列ベースのパスを置き換えるものです。 URL 内の % と # を適切にサポートするには、ResourcePath ベースの API をデコードされた URL と共に使用する必要があります。
ResourcePath は、静的関数 ResourcePath.FromDecodedUrl(string)
を呼び出すことによって簡単に構築することができます。 渡された入力値には、プロパティ DecodedUrl を呼び出すことによって ResourcePath オブジェクトからアクセスできます。
文字列ベースの URL を使用する既存の呼び出しの場合、文字列ベースの URL 呼び出しにつながるコード パスがエンコードされた URL とデコードされた URL のどちらで提供されたものか、また、それらのコード パスがアンカー リンク (つまり、ファイル URL の先頭に #bookmark を追加) を許可していたかどうかを判別する必要があります。
注:
単純に検索と置換で既存の文字列ベースの URL API を ResourcePath.FromDecodedUrl
に変更しないでください。 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 プロパティが提供されます。 1 つの例外は、SPFolder.WelcomePage プロパティです。これは、以前はエンコードされた URL とエンコードされていない 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) |
上記の API で使用するための、あいまいさのないエンコードの System.Uri を返すために、次の C# プロパティが追加されました。 次の API の以前のバリアントは、デコードされた URL を返しました。それらの 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