4

I have some SP .NET Object library code that will allow me to query for the contents of a specific folder in a document library. It worked fine in a UAT environment where there were only a few dozen folders, but when I moved it to Production where there were 14K folders, it won't return the folders anymore.

I assume that I need a way to get directly to the folder, instead of retrieving the list of folders and then getting the one I need, but I don't know how to do it? I think i could do it with a CAML query, but I can't find a way to get directly to the folder and get the list of files?

Assumumptions:
Site Name = https://xyz.sharepoint.com/sites/CRMDocs/

Library Friendly Name = Case

Library Path = incident

Sample Folder = 0312380e

Full Path = https://xyz.sharepoint.com/sites/CRMDocs/incident/0312380e

Web web = clientContext.Web;
ListCollection lists = web.Lists;

var docLib = web.Lists.GetByTitle(entityFriendlyName);
clientContext.Load(docLib, d => d.Title, d => d.RootFolder.Name);
clientContext.ExecuteQuery();

String folderUrl = String.Format("/{0}/{1}", docLib.RootFolder.Name, folderName);

var folders = docLib.RootFolder.Folders;
clientContext.Load(folders, fldrs => fldrs.Include(fldr => fldr.ServerRelativeUrl));
clientContext.ExecuteQuery();

// When there are more than 5K folders, folders collection is NULL
var folder = folders.FirstOrDefault(f => f.ServerRelativeUrl.ToLower().EndsWith(folderUrl.ToLower()));
if (folder != null)
{
    var files = folder.Files;

    clientContext.Load(files);
    clientContext.ExecuteQuery();
    // Process Files
}
4
  • For getting folders try to use caml like here instead of using directly docLib.RootFolder.Folders Commented Dec 20, 2016 at 18:27
  • you can use content iterator class from sharepoint in your code. that may help Commented Dec 20, 2016 at 18:30
  • I've tried the caml query, but I still get this: Commented Dec 20, 2016 at 20:56
  • "The attempted operation is prohibited because it exceeds the list view threshold enforced by the administrator." Commented Dec 20, 2016 at 20:57

3 Answers 3

5

In SharePoint Online, your only choice is to use REST. CSOM will not work. You call the REST endpoint and it will return a batch of 100 or 200 items, and if more exist, will return a paged link to access the next batch of data.

I've used this technique in the past to update 100k+ items in a document library with success (in PowerShell), CSOM would not work. Marc Anderson has it detailed here, http://sympmarc.com/2016/11/30/25696.

This is a sample from when I used it in PowerShell:

#https://www.itunity.com/article/working-lists-list-items-sharepoint-rest-service-windows-powershell-2077

function Get-Items{
    Param(
        [Parameter(Mandatory=$true,Position=0)][ValidateNotNull()]
        [string]$Url
    )
    $list = Invoke-SPORestMethod -Url "https://tenant.sharepoint.com/sites/site/_api/Web/Lists/getbytitle('Documents')" 
    $itemType = $list.ListItemEntityTypeFullName 
    $digest = (Invoke-SPORestMethod -Url "https://tenant.sharepoint.com/sites/site/_api/contextinfo" -Method "POST").GetContextWebInformation.FormDigestValue 
    $listItems = Invoke-SPORestMethod -Url $Url
    Write-Host "Processing batch starting at "$listItems.results[0].Id -ForegroundColor Yellow

    foreach($li in $listItems.results){
        $newTitle = $li.FileLeafRef.ToString()
        if($li.Title -ne $newTitle){
            $id = $li.Id
            $pgurl = "https://tenant.sharepoint.com/sites/site/_api/Web/Lists/getbytitle('Documents')/items($id)"
            Write-Host "Updating $pgurl" -ForegroundColor White
            $metadata = "{ '__metadata': { 'type': '$itemType' }, 'Title': '$newTitle'}"
            $item = Invoke-SPORestMethod -Url $pgurl -Method "POST" -XHTTPMethod "MERGE" -Metadata $metadata -RequestDigest $digest -ETag "*"
        }
    }
    Write-host "Batch complete" -ForegroundColor Green
    if($listItems.__next){
        Get-Items -Url $listItems.__next    
    }
}
cls
Get-Items -Url "https://tenant.sharepoint.com/sites/site/_api/Web/Lists/getbytitle('Documents')/items?`$select=FileLeafRef,Title,Id&`$orderby=Id%20desc&`$filter=(ID%20le%20313031)"
5
  • How do you A: pass in credentials? And B: overcome the CORS message? I am working on a .net web API proxy app that sits between Dynamics CRM online and SharePoint online Commented Dec 21, 2016 at 11:46
  • The invoke-sporestmethod in this case references a credential object username and password that is supplied previously when PowerShell is launched. There shouldn't be a CORS problem, I haven't seen one using REST against SPO. Commented Dec 21, 2016 at 13:02
  • Is there a C# / .NET equivalent to the invoke-sporestmethod? Commented Dec 21, 2016 at 13:05
  • I would imagine the WebRequest class Commented Dec 21, 2016 at 13:10
  • I found some code to connect to the REST API, but I am now getting 401 UNAUTHORIZED errors. I have good credentials, so I know that's not the problem. Commented Dec 21, 2016 at 15:02
0

Not a specific answer, but I did finally find a c# set of functions that will allow you to connect to SPOnline and pass in a REST call.

http://journeyintocrm.com/archives/1152

0

Actually, after working with this some more, I found an even better way that does not require a REST call.

Once you have the SharePoint clientcontext.Web, make a call to web.GetFolderByServerRelativeUrl(folderNameString);

Web web = clientContext.Web;
ListCollection lists = web.Lists;

var docLib = web.Lists.GetByTitle(entityFriendlyName);
clientContext.Load(docLib, d => d.Title, d => d.RootFolder.Name);
clientContext.ExecuteQuery();

String folderUrl = String.Format("/{0}/{1}", docLib.RootFolder.Name, folderName);

Folder folder = web.GetFolderByServerRelativeUrl(folderUrl);

if (folder != null)
{
    var files = folder.Files;

    clientContext.Load(files);
    clientContext.ExecuteQuery();
    // Process Files
}

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.