CSOM Sharepoint Methods for adding Folders to Library and Folders in Library

gsaunders

Member
Joined
Mar 30, 2021
Messages
16
Programming Experience
5-10
Target .NET4.7.2, Windows Forms App template

Environment:
  • Windows 10
  • Visual Studio 2019 16.9.4
Goal:
  • Create Folders in Root Library and then create subfolders a couple of levels deep.
Code Setup:
  • We have added Microsoft.SharePoint.Online.CSOM (16.1.2111.12000) Nuget Package
  • We have added Microsoft .Identity.Client (4.29.0) Nuget Package
Question:
  • I have seen multiple ways to potentially add folders and check to see if folder exists and so forth. I am looking to find out what is the best or recommended way of doing this.
I have seen examples making use of the Folder.Add and others making use of ListItemCreationInformation and ListItem.

Here is example of ListItemCreationInformation and ListItem:
C#:
        public static bool CreateFolder(ClientContext context, List list, string folderName)
        {
            string url = list.RootFolder.ServerRelativeUrl + "/" + folderName;

            try
            {
                ListItemCreationInformation newItemInfo = new ListItemCreationInformation();
                newItemInfo.UnderlyingObjectType = FileSystemObjectType.Folder;
                newItemInfo.LeafName = folderName;
                ListItem newListItem = list.AddItem(newItemInfo);
                newListItem["Title"] = folderName;
                newListItem.Update();
                context.ExecuteQuery();
                return true;
            }
            catch (ServerUnauthorizedAccessException uae)
            {
                Trace.WriteLine($"You are not allowed to access this folder: " + uae.Message);
                throw;
            }
            catch (Exception ex)
            {
                Trace.WriteLine($"Could create folder {url}" + ex.Message);
                return false;
            }
        }

And here is an example making use of the Folder.Add methodology:
C#:
        var list = ctx.Web.Lists.GetByTitle(listName);
        var folder = list.RootFolder;
        ctx.Load(folder);
        ctx.ExecuteQuery();
        folder = folder.Folders.Add(folderName);
        ctx.ExecuteQuery();

So what I am trying to determine is WHAT methodology should I be using to create these folders.

Why do I see some examples using Folders.Add and other examples making use of the ListItemCreationInformation and ListItem?

In addition there is the issue of whether the folder or (later a file) exists prior to creating or uploading. At this point I know if I try to add a folder that already exists it throws an exception and stops you.

So at this point I seem to have to check if the folder exists first for every folder which is more calls back to share point making this all a singular folder creation event and not many.

So a follow up question is if there is a way to see if a folder exists without throwing an exception. The current check for folder exists that I am using is like this:
C#:
      private static bool FolderExists(ClientContext context, string url)
        {
            var folder = context.Web.GetFolderByServerRelativeUrl(url);
            context.Load(folder, f => f.Exists);
            try
            {
                context.ExecuteQuery();

                if (folder.Exists)
                {
                    return true;
                }
                return false;
            }
            catch (ServerUnauthorizedAccessException uae)
            {
                Trace.WriteLine($"You are not allowed to access this folder: " + uae.Message);
                throw;
            }
            catch (Exception ex)
            {
                Trace.WriteLine($"Could not find folder {url}" + ex.Message);
                return false;
            }
        }

Which basically will throw an exception and is trapped, but you have to do this for every folder test. It is hard to believe there isn't a way to do this without throwing exceptions if you wanted to send up 100 folders in one shot.

Here is something I am playing with and will see if will work, but thought I would get some feedback while testing. In this test using the Folders.Add methodology. But they key part is loading all of the folders and then checking to see if it exists. Not sure this will work yet as I pulled this from another site.
C#:
               List list = context.Web.Lists.GetByTitle("Documents");
                FolderCollection folders = list.RootFolder.Folders;
                context.Load(folders);               
                context.ExecuteQuery();

                var folderExists = folders.Any(x => x.Name == "SOMEFOLDERNAME");
                if (!folderExists)
                {
                    //create folder
                    Folder newFolder= folders.Add("SOMEFOLDERNAME");
                    context.Load(newFolder);
                    context.ExecuteQuery();
                }
 
Solution
Personally, I would recommend the AddFolder method, but if it not giving what you need, as I said before, stop using the abstraction, and access the list items.
You are on the right track of minimizing round trips. So trying to retrieve all the listitems names or folders and then checking that client side is better that pinging the server one at a time to see if it exists, or if you have a collision.

The downside of this query everything, and then check for collisions is in the end you still have to write defensive code that handles that off chance that someone creates a colliding item since the time that you queried. It may feel frustrating because you might as well have just not bothered querying and just tried to create the item and gotten an exception in the first place. Your users will appreciate it though when things go down the happy path when there are no collisions.

You can also queue up a bunch of folder adds and only do a single or batched ExecuteQuery(). But again, you need to be prepared for the collision and/or other failure conditions.

You should always lean on the methods that give you the most abstraction (until the point when you can't use the abstractions anymore). As you've probably learned by now, almost everything in SharePoint is either a List, a ListItem, or a HashTable, or composed of these things. The abstraction of the folders and files on top of lists is a useful abstraction to take advantage of specially when it comes time to upload the data that belongs to the files. Sometimes you have to break out of the folder and file abstraction, and actually play with the backing list item, but it's not that often.
 
You are on the right track of minimizing round trips. So trying to retrieve all the listitems names or folders and then checking that client side is better that pinging the server one at a time to see if it exists, or if you have a collision.

The downside of this query everything, and then check for collisions is in the end you still have to write defensive code that handles that off chance that someone creates a colliding item since the time that you queried. It may feel frustrating because you might as well have just not bothered querying and just tried to create the item and gotten an exception in the first place. Your users will appreciate it though when things go down the happy path when there are no collisions.

You can also queue up a bunch of folder adds and only do a single or batched ExecuteQuery(). But again, you need to be prepared for the collision and/or other failure conditions.

You should always lean on the methods that give you the most abstraction (until the point when you can't use the abstractions anymore). As you've probably learned by now, almost everything in SharePoint is either a List, a ListItem, or a HashTable, or composed of these things. The abstraction of the folders and files on top of lists is a useful abstraction to take advantage of specially when it comes time to upload the data that belongs to the files. Sometimes you have to break out of the folder and file abstraction, and actually play with the backing list item, but it's not that often.
Good thing is this is really for a conversion so there are no other users involved. It will be a one and done.

We just have a ton of files to be moved and they are all broken down by company / job / folder / subfolder.

Definitely a learning experience with CSOM and Sharepoint.

So in regards to the two ways I have seen to add a folder (folder.addfolder vs the ListItemCreationInformation and ListItem). What is the preferred method? What is the benefit of one over the other.

I think I found my way of adding the subfolders below the company level mentioned above by making use of the ListItemCreationInformation.FolderUrl. Testing this now.
 
Personally, I would recommend the AddFolder method, but if it not giving what you need, as I said before, stop using the abstraction, and access the list items.
 
Solution
Back
Top Bottom