Pnp-sites-core: PnP Sites Core - EnsureFolderPath - Bug with '+' in folder name

Created on 29 Oct 2019  路  7Comments  路  Source: pnp/PnP-Sites-Core

Category

  • [ ] Question
  • [ ] Typo
  • [x] Bug
  • [ ] Additional article idea

Expected or Desired Behavior

I expect the full folder path provided to be created in the destination library, or if already present, to reported as such.

"/sites/demo/library/parentFolder+1/childFolder" if any of the folders already exist, I expect to code to succeed without errors and return the childFolder. If any of the folders do not yet exist, I expect the code to success without errors and return the childFolder.

Observed Behavior

Example:
context.Web.EnsureFolderPath("/sites/demo/library/parentFolder+1/childFolder") will throw an error when the 'parentFolder+1' folder exists, saying it can't create the folder because it already exists. I'm assuming a bug in determining if the folder already exists. Same behaviour for context.Web.EnsureFolderPath("/sites/demo/library/parentFolder+1")

context.Web.GetFolderByServerRelativeUrl("/sites/demo/library/parentFolder+1/childFolder") does not have this issue.

parentFolder.EnsureFolder(subFolderName, f => f.Exists, f => f.Files, f => f.ServerRelativePath, f => f.ServerRelativeUrl) does not have this issue either with "parentFolder+1" or "childFolder" as subFolderName at their respective parent folders.

Steps to Reproduce

context.Web.EnsureFolderPath("/sites/demo/library/parentFolder+1") will error if "parentFolder+1" already exists.

Needs

Most helpful comment

For those having this issue, I took a look at the source code to find the exact error and found a one liner solution.

The issue occurs because of this particular code in the FileFolderExtensions.cs class :

```c#
foreach (Folder existingFolder in folderCollection)
{
if (string.Equals(existingFolder.Name, System.Net.WebUtility.UrlDecode(folderName), StringComparison.InvariantCultureIgnoreCase))
{
nextFolder = existingFolder;
break;
}
}

When drilling down the different folders that are part of the destination folder's full path, the code checks if the current folder name equals any of the already existing folders. However, the code uses **System.Net.WebUtility.UrlDecode(folderName)** when comparing the name of the current folder to the existing ones, and usually in URL encoding a '+' represents a space just like '%20' does, so the **UrlDecode** function transforms **'My + Folder'** into **'My   Folder'**, and since the **'My   Folder'** isn't found it tries to create it. When trying to create it, the code uses native SharePoint CSOM which handles the encoding differently and doesn't try to decode '+' characters, which means it tries to create it with the correct name, and fails because it already exists with the correct name.

As a workaround, I used **System.Net.WebUtility.UrlEncode** to realize that the '+' character is in fact encoded as **'%2B'**, so knowing that I replaced **'My + Folder'** with **'My %2B Folder'** in order to make sure that the UrlDecode line used in the source code ends with the real value. Not only it fixed the problem when the folder already existed, it also doesn't break the code when the folder doesn't exist because the native CSOM used by the source code does decode '$2B' correctly into '+' so you end up with the correct name both when the folder already exist and when it must be created.

So the final workaround is simply :

```c#
context.Web.GetFolderByServerRelativeUrl("/sites/demo/library/parentFolder%2B1/childFolder")

or dynamically

c# string destinationFolderPath = "/sites/demo/library/parentFolder+1/childFolder"; string fixedDestinationFolderPath = destinationFolderPath.Replace("+", "%2B"); context.Web.GetFolderByServerRelativeUrl(fixedDestinationFolderPath)

馃憤

All 7 comments

Thank you for reporting this issue. We will be triaging your incoming issue as soon as possible.

This should be posted to the PNP Sites Core repo project...

Thank you for reporting this issue. We will be triaging your incoming issue as soon as possible.

@andrewconnell My bad, I somehow thought all PnP work was to be submitted under sp-dev-docs. Thx for the transfer!

Related to #1161

AddClientSidePage is using EnsureFolderPath and throws an exception when I try to create a second page in a folder with a "+" in the name.

I will work around this issue by replacing "+" with something else and renaming the folder (back) after creating all the pages.

For those having this issue, I took a look at the source code to find the exact error and found a one liner solution.

The issue occurs because of this particular code in the FileFolderExtensions.cs class :

```c#
foreach (Folder existingFolder in folderCollection)
{
if (string.Equals(existingFolder.Name, System.Net.WebUtility.UrlDecode(folderName), StringComparison.InvariantCultureIgnoreCase))
{
nextFolder = existingFolder;
break;
}
}

When drilling down the different folders that are part of the destination folder's full path, the code checks if the current folder name equals any of the already existing folders. However, the code uses **System.Net.WebUtility.UrlDecode(folderName)** when comparing the name of the current folder to the existing ones, and usually in URL encoding a '+' represents a space just like '%20' does, so the **UrlDecode** function transforms **'My + Folder'** into **'My   Folder'**, and since the **'My   Folder'** isn't found it tries to create it. When trying to create it, the code uses native SharePoint CSOM which handles the encoding differently and doesn't try to decode '+' characters, which means it tries to create it with the correct name, and fails because it already exists with the correct name.

As a workaround, I used **System.Net.WebUtility.UrlEncode** to realize that the '+' character is in fact encoded as **'%2B'**, so knowing that I replaced **'My + Folder'** with **'My %2B Folder'** in order to make sure that the UrlDecode line used in the source code ends with the real value. Not only it fixed the problem when the folder already existed, it also doesn't break the code when the folder doesn't exist because the native CSOM used by the source code does decode '$2B' correctly into '+' so you end up with the correct name both when the folder already exist and when it must be created.

So the final workaround is simply :

```c#
context.Web.GetFolderByServerRelativeUrl("/sites/demo/library/parentFolder%2B1/childFolder")

or dynamically

c# string destinationFolderPath = "/sites/demo/library/parentFolder+1/childFolder"; string fixedDestinationFolderPath = destinationFolderPath.Replace("+", "%2B"); context.Web.GetFolderByServerRelativeUrl(fixedDestinationFolderPath)

馃憤

Was this page helpful?
0 / 5 - 0 ratings