Second Life of a Hungarian SharePoint Geek

January 27, 2011

How to check if a specific list or folder exists using the managed client object model

Filed under: Managed Client OM, SP 2010 — Tags: , — Peter Holpar @ 23:10

A few days ago I read a question on the SharePoint 2010 developer MSDN forum where part of the request was to check for the existence of a specific folder within a specific list. In the answer the check is simply done applying a try / catch block (try to get it and if it fails, create it).

One can read similar suggestions in this MSDN technical article as well:

“You should be prepared to catch exceptions when you write code that may fail if you ask for objects that may not exist.”

I agree that you should be prepared for this case but I’m pretty sure it should not be your default path. Exception handling should remain what its name suggests: handling exceptions, special cases. If there is other way to check object existence you should use that at first place, and not use exception handling to define program flow logic. The latter one may have serious performance issues and results typically quick-and-dirty “solutions”.

But how can we check whether an object exists or not? Let’s see a code sample for lists and folders:

  1. public Folder GetFolderCS(ClientContext clientContext, String listTitle, String folderName)
  2. {
  3.     Folder existingFolder = null;
  4.  
  5.     Web web = clientContext.Web;
  6.     ListCollection lists = web.Lists;
  7.  
  8.     List list = GetListByTitleCS(clientContext, listTitle);
  9.  
  10.     if (list != null)
  11.     {
  12.         FolderCollection folders = list.RootFolder.Folders;
  13.  
  14.         String folderUrl = String.Format("/{0}/{1}", listTitle, folderName);
  15.  
  16.         IEnumerable<Folder> existingFolders = clientContext.LoadQuery<Folder>(
  17.             folders.Where(
  18.             folder => folder.ServerRelativeUrl == folderUrl)
  19.             );
  20.         clientContext.ExecuteQuery();
  21.  
  22.         existingFolder = existingFolders.FirstOrDefault();
  23.     }
  24.  
  25.     return existingFolder;
  26. }
  27.  
  28.  
  29. public List GetListByTitleCS(ClientContext clientContext, String listTitle)
  30. {
  31.     List existingList;
  32.  
  33.     Web web = clientContext.Web;
  34.     ListCollection lists = web.Lists;
  35.  
  36.     IEnumerable<List> existingLists = clientContext.LoadQuery(
  37.             lists.Where(
  38.             list => list.Title == listTitle)
  39.             );
  40.     clientContext.ExecuteQuery();
  41.  
  42.     existingList = existingLists.FirstOrDefault();
  43.  
  44.     return existingList;
  45. }

In the above code we ask for the folder and list having the specified name and title. If the result is null the object does not exist.

If you call the GetFolderCS method using the exact list title and folder name of an existing list and folder, you get the folder object:

ClientContext clientContext = new ClientContext(http://sp2010);
Folder folder = GetFolderCS(clientContext, "Pages", "folder1");

If you test the solution further, you may found, that it is unfortunately case sensitive (that is the CS postfix in the method names). For example, if you type pages for a list named Pages, the result will be null, suggesting a non-existing list. That is due to the case sensitivity of the lambda expression used in the LoadQuery method of the ClientContext class.

Unfortunately, trivial methods to workaround this issue do not help, you will get ClientRequestException for the following trials:

list => list.Title.ToLower() == listTitle.ToLower()
The ‘ToLower’ member cannot be used in the expression.

list => list.Title.IndexOf(listTitle) == 0 && list.Title.Length == listTitle.Length
The ‘IndexOf’ member cannot be used in the expression.

list => list.Title.Equals(listTitle, StringComparison.CurrentCultureIgnoreCase))
The ‘Equals’ member cannot be used in the expression.

So what can we do to create a case insensitive version?

The solution is to get the list of the lists and the list of the folders within the list and compare its title and name locally as show in this slightly modified version:

  1. public Folder GetFolderCI(ClientContext clientContext, String listTitle, String folderName)
  2. {
  3.     Folder existingFolder = null;
  4.  
  5.     Web web = clientContext.Web;
  6.     ListCollection lists = web.Lists;
  7.  
  8.     List list = GetListByTitleCI(clientContext, listTitle);
  9.  
  10.     if (list != null)
  11.     {
  12.         FolderCollection folders = list.RootFolder.Folders;
  13.  
  14.         String folderUrl = String.Format("/{0}/{1}", listTitle, folderName);
  15.  
  16.         IEnumerable<Folder> existingFolders = clientContext.LoadQuery(
  17.             folders.Include(
  18.             folder => folder.ServerRelativeUrl)
  19.             );
  20.         clientContext.ExecuteQuery();
  21.  
  22.         existingFolder = existingFolders.FirstOrDefault(
  23.             folder => folder.ServerRelativeUrl.ToLower() == folderUrl.ToLower());
  24.     }
  25.  
  26.     return existingFolder;
  27. }
  28.  
  29.  
  30. public List GetListByTitleCI(ClientContext clientContext, String listTitle)
  31. {
  32.     List existingList;
  33.  
  34.     Web web = clientContext.Web;
  35.     ListCollection lists = web.Lists;
  36.  
  37.     IEnumerable<List> existingLists = clientContext.LoadQuery(
  38.              lists.Include(
  39.              list => list.Title)
  40.              );
  41.     clientContext.ExecuteQuery();
  42.  
  43.     existingList = existingLists.FirstOrDefault(list => list.Title.ToLower() == listTitle.ToLower());
  44.  
  45.     return existingList;
  46. }

In this case you can use the ToLower method that makes the result case insensitive.

I hope this version will help you to check for list and folder existence without misusing exception handling.

Advertisements

8 Comments »

  1. Very interesting.
    I thought that it would be simpler & efficient to search for the list in web.Lists, e.g.:

    foreach (SPList list in web.Lists)
    {
    if (string.Compare(list.Title, “My List”, true) == 0) // case-insensitive
    return list;
    }

    Am I wrong?

    Comment by Sruli Ganor — January 30, 2011 @ 14:19

    • Hi Sruli,

      You cannot use server side objects (like SPList) when using the managed client object model, you have to use their client side counterparts (that is List in this case). On the other hand, my code does exactly what you suggest, search in the web.Lists, although not by iterating using a foreach loop, but using a lambda expression. The issue was that I found no way to ask the server to do the comparision in a case insensitive way, so I had to do that on client side.

      Peter

      Comment by Peter Holpar — January 30, 2011 @ 19:08

  2. OK. Thanks. I’m not familiar with client object model and its restrictions. Now it’s clear.

    Comment by Sruli Ganor — January 31, 2011 @ 08:31

  3. Good work. Just i need to solve list problem.

    Greetings, Sebastián.-

    Comment by Sebastián Torres — March 16, 2012 @ 15:43

  4. hi awesome example!.. i’m using it and its working great in my dev environment.. however when i try debugging it when its running on our staging IIS server (using remote debugging) I get an empty collection of folders however if i do it on my dev server i get the folders list.. anyideas on why it would return nothing on the production environment. both obviously have the sharepoint client object model dll’s installed on them.. i must be missing something on the server but what…?

    String parentFolderURL = String.Format(“{0}/{1}/{2}”, relativeURL, listTitle, deptName);

    Enumerable existingFolders = clientContext.LoadQuery(
    parentFolders.Include(
    folder => folder.ServerRelativeUrl)
    );
    clientContext.ExecuteQuery();

    Comment by kevin dube — September 21, 2012 @ 00:02

  5. String parentFolderURL = String.Format(“{0}/{1}/{2}”, relativeURL, listTitle, deptName);

    IEnumerable existingFolders = clientContext.LoadQuery(
    parentFolders.Include(
    folder => folder.ServerRelativeUrl)
    );
    clientContext.ExecuteQuery();

    existingFolders is empty if this is done on the server but has values in the dev environment

    Comment by kevin dube — September 21, 2012 @ 00:04

  6. hey i did some more research on this problem… i created a “windows client” test application to test this and i found that the windows client worked fine onthe server… so it must be something to do with asp.net authentication because the call is failing when it runs as an asp.net application, but works as a windows client app… i wonder if there is some configuration i need to do in iis to get this to work… it’s weird that other client OM calls work but not this one..

    Comment by kevin dube — September 21, 2012 @ 18:22

    • Hi, Kevin,
      I have the same problem (it doesn’t work in DEV env). Did you finally resolve it? And if yes, can I ask you how do you have solved?

      Thank you,

      Comment by Luca Giornetti — November 19, 2012 @ 15:13


RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Create a free website or blog at WordPress.com.

%d bloggers like this: