使用CSOM从特定的SharePoint 2013库中获取所有子文件夹

时间:2017-06-14 16:40:08

标签: sharepoint sharepoint-2010 sharepoint-2013

如何使用SharePoint library获取特定CSOM的所有子文件夹列表?当用户点击“选择文件夹”时,我想提供与SharePoint相同的功能。

enter image description here

我发现这篇文章CAML and the Client Object Model我认为非常好,但是当我尝试以下内容时,我会收到错误:

using (ClientContext clientContext = new ClientContext(this.SpSite))
{
    var web = clientContext.Web;
    var list = web.Lists.GetByTitle('Contracts');

    var query = new CamlQuery();
    query.FolderServerRelativeUrl = "/Contracts";
    query.ViewXml = "<View Scope='RecursiveAll'>"
    + "<Query>"
    + "   <Where>"
    + "      <Eq><FieldRef Name='FSObjType' /><Value Type='Integer'>1</Value></Eq>"
    + "   </Where>"
    + "</Query>"
    + "</View>";

    var folderItems = list.GetItems(query);
    clientContext.Load(folderItems);
    clientContext.ExecuteQuery();

    foreach (ListItem item in folderItems)
    {
        // item[ "..." ];
    }
}

我也尝试过不同的CALM查询,但无济于事:

query.ViewXml = "<View Scope=\"RecursiveAll\"> " +
"<Query>" +
"<Where>" +
"<Eq>" +
"<FieldRef Name=\"FileDirRef\" />" +
"<Value Type=\"Text\">" + title + "</Value>" +
"</Eq>" +
"</Where>" +
"</Query>" +
"</View>";

任何帮助都将不胜感激。

感谢。

UPDATE-1:

我在StackExchange上发现了一个问题How to traverse SharePoint Library in Client Object Model?,它与我的需求非常接近,但仍然存在一些问题:

  1. 它使用递归,这意味着如果你有很多级别,它最终会产生大量请求,并且可能显示非常慢。

  2. 未订购退回的数据。基于我提供的快照,而不是返回01,02,03等...它以随机顺序返回值。

  3. 我希望我能够拨打一个电话并获取所有文件夹和子文件夹的列表,但我想这也可能最终耗费时间。

    我想我有几个选择:

    1. 坚持递归方法,弄清楚如何整理数据,但我仍需要弄清楚后者。

    2. 仅在顶层请求文件夹,并且仅在展开文件夹时按需请求子文件夹。理想情况下,如果使用这种方法,最好知道一个文件夹是否有任何子文件夹,这意味着还必须解决这个问题。

    3. 到达那里,但还没到那里。

      所以如果有人可以提供额外的反馈,片段,任何事情,请做。

      感谢。

2 个答案:

答案 0 :(得分:1)

对于一次加载所有文件夹的情况,我建议进行以下调整:

由于CSOM API已经包含the built in method,因此加载所有文件夹项可以这样执行:

var folderItems = list.GetItems(CamlQuery.CreateAllFoldersQuery());

其次,我建议从关联的列表项中检索文件夹对象:

var allFolders = folderItems.Select(i => i.Folder).ToList();

示例:

public static List<Folder> GetAllFolders(List list)
{
    var ctx = list.Context;
    var folderItems = list.GetItems(CamlQuery.CreateAllFoldersQuery());
    ctx.Load(folderItems, icol => icol.Include(i => i.Folder));
    ctx.ExecuteQuery();
    var allFolders = folderItems.Select(i => i.Folder).ToList();
    return allFolders;
}

由于从性能角度加载整个文件夹结构可能是一个瓶颈,为避免您考虑按需加载方法:

加载表单后,检索 1st 级别文件夹列表并填充树视图:

var list = ctx.Web.Lists.GetByTitle(libraryTitle);
var folders = FolderManager.GetFolders(list.RootFolder);

var rootNode = new TreeNode(libraryTitle);
folderSelector.Nodes.Add(rootNode);
foreach (var folder in folders)
{
      var folderNode = new TreeNode(folder.Name) {Tag = folder};
      rootNode.Nodes.Add(folderNode);
}

然后根据需要加载子文件夹,并在触发expand事件后填充节点:

private void folderTreeView_BeforeExpand(object sender, TreeViewCancelEventArgs e)
{
    if (e.Node.Level > 0 ) //skip root level
    {
         var folders = FolderManager.GetFolders((Folder)e.Node.Tag);
         foreach (var folder in folders)
         {
                var folderNode = new TreeNode(folder.Name) { Tag = folder };
                e.Node.Nodes.Add(folderNode);
         }
    }
}

,其中

public static List<Folder> GetFolders(Folder parentFolder)
{
    var ctx = parentFolder.Context;
    var result = ctx.LoadQuery(parentFolder.Folders.Where(f => !f.ListItemAllFields.ServerObjectIsNull.Value));
    ctx.ExecuteQuery();
    return result.ToList();
}   

答案 1 :(得分:0)

我最终使用Caml Designer 2013搞清楚了。这个概念非常好,但对于我的品味仍然非常不稳定,这使得它无法使用,但经过多次试验和错误后,我最终查看了“查询选项”部分。

事实证明,在本节中,有一个处理文件夹和选项的选项。子文件夹,它最终为我生成了正确的Calm查询。

这是最后的结果:

using (ClientContext clientContext = new ClientContext(this.SpSite))
{
    List spList = clientContext.Web.Lists.GetByTitle(title);
    clientContext.Load(spList);
    clientContext.ExecuteQuery();

    if (spList != null && spList.ItemCount > 0)
    {
        CamlQuery camlQuery = new CamlQuery();
        camlQuery.ViewXml = 
            "<View Scope='RecursiveAll'>"
          + "  <Query>"
          + "    <Where>"
          + "      <Eq><FieldRef Name='FSObjType' /><Value Type='Integer'>1</Value></Eq>"
          + "    </Where>"                            
          + "  </Query>"
          + "  <ViewFields><FieldRef Name='Title' /></ViewFields>"
          + "</View>";

          ListItemCollection listItems = spList.GetItems(camlQuery);

          clientContext.Load(listItems);
          clientContext.ExecuteQuery();

          foreach (var item in listItems)
          {
              Debug.WriteLine($"Title: {item.FieldValues["Title"]} 
              - FileRef: {item.FieldValues["FileRef"]} 
              - FileLeafRef: {item.FieldValues["FileLeafRef"]}");
          }
      }
  }

以上代码生成了以下结果:

Title: 2016 - FileRef: /Contracts/2016 - FileLeafRef: 2016
Title: 2017 - FileRef: /Contracts/2017 - FileLeafRef: 2017
Title: 01 - FileRef: /Contracts/2016/01 - FileLeafRef: 01
Title: 02 - FileRef: /Contracts/2016/02 - FileLeafRef: 02
Title: 03 - FileRef: /Contracts/2016/03 - FileLeafRef: 03
Title: 04 - FileRef: /Contracts/2016/04 - FileLeafRef: 04
Title: 05 - FileRef: /Contracts/2016/05 - FileLeafRef: 05
Title: 06 - FileRef: /Contracts/2016/06 - FileLeafRef: 06
Title: 07 - FileRef: /Contracts/2016/07 - FileLeafRef: 07
Title: 08 - FileRef: /Contracts/2016/08 - FileLeafRef: 08
Title: 09 - FileRef: /Contracts/2016/09 - FileLeafRef: 09
Title: 10 - FileRef: /Contracts/2016/10 - FileLeafRef: 10
Title: 11 - FileRef: /Contracts/2016/11 - FileLeafRef: 11
Title: 12 - FileRef: /Contracts/2016/12 - FileLeafRef: 12
Title: 01 - FileRef: /Contracts/2017/01 - FileLeafRef: 01
Title: 02 - FileRef: /Contracts/2017/02 - FileLeafRef: 02
Title: 03 - FileRef: /Contracts/2017/03 - FileLeafRef: 03
Title: 04 - FileRef: /Contracts/2017/04 - FileLeafRef: 04
Title: 05 - FileRef: /Contracts/2017/05 - FileLeafRef: 05
Title: 06 - FileRef: /Contracts/2017/06 - FileLeafRef: 06
Title: 07 - FileRef: /Contracts/2017/07 - FileLeafRef: 07
Title: 08 - FileRef: /Contracts/2017/08 - FileLeafRef: 08
Title: 09 - FileRef: /Contracts/2017/09 - FileLeafRef: 09
Title: 10 - FileRef: /Contracts/2017/10 - FileLeafRef: 10
Title: 11 - FileRef: /Contracts/2017/11 - FileLeafRef: 11
Title: 12 - FileRef: /Contracts/2017/12 - FileLeafRef: 12

所以,我还要做的就是查看FieldValues字典中返回的其他属性,看看是否有一个可以帮助我识别父节点或子节点,但即使已经存在,也可以轻松解析诀窍。

希望这有助于节省您的时间!

PS:我不知道你们中的任何一位SharePoint专家是否注意到了,但我原来的问题代码看起来与解决方案非常相似,但它没有产生相同的结果。如果这是一个快速突出的内容,请分享,因为我很想知道,但不能再花时间在这个问题上。