4

I've got a URL to a folder on Sharepoint, and all I need to do is get a list of the files in that folder.

When I use my browser to go to https://<name>.sharepoint.com/Organisation/Section/Planning/, I automatically get redirected to https://<name>.sharepoint.com/Organisation/Section/Planning/Forms/AllItems.aspx, and I get to see the files present in that folder.

Now I want to get that same list of files in my desktop application. Here's what I have so far:

using (var Context = new ClientContext(fullUri.GetLeftPart(UriPartial.Authority)) {
    AuthenticationMode = ClientAuthenticationMode.Default,
    Credentials = new SharePointOnlineCredentials(username, password)
})
{
    var folder = Context.Web.GetFolderByServerRelativeUrl(fullUri.AbsolutePath);
    Context.Load(folder);
    Context.Load(folder.Files);
    Context.ExecuteQuery();

    Console.WriteLine(folder.Name);
    Console.WriteLine(folder.Files.Count);
    foreach (var file in folder.Files)
        Console.WriteLine(file.Name);
}

where fullUri = new Uri("https://<name>.sharepoint.com/Organisation/Section/Planning/");.

Now this appears to work fine; folder.Name prints as "Planning", which is as expected; however, the folder.Files.count is always zero, 0. But the browser shows that there is, indeed, a file present in that folder.

What am I doing wrong?!?


Update:

I've tried the REST request mentioned in the comments:

https://<name>.sharepoint.com/_api/web/getfolderbyserverrelativeurl('/Organisation/Section/Planning')/Files

which returns the following XML (which doesn't seem to contain much either :-\):

<?xml version="1.0" encoding="utf-8"?>
<feed xml:base="https://[name].sharepoint.com/_api/" xmlns="http://www.w3.org/2005/Atom" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns:georss="http://www.georss.org/georss" xmlns:gml="http://www.opengis.net/gml">
    <id>a13a6953-4a31-4e76-a9ba-437e85261a43</id>
    <title />
    <updated>2018-03-16T17:08:04Z</updated>
    <author>
        <name />
    </author>
</feed>
3
  • Not sure why CSOM isn't working as expected, but have you tried using REST instead? https://<name>.sharepoint.com/_api/web/getfolderbyserverrelativeurl('/Organisation/Section/Planning')/Files
    – wjervis
    Mar 16 '18 at 17:01
  • @wjervis: thanks for the tip; I've tried, but while that appears to work, it also doesn’t yield anything interesting. I’ve included the response in the question.
    – Martijn
    Mar 16 '18 at 17:17
  • It's a bit strange but the code seems to be ok. Did you try to retrieve ListItemAllFields property instead of Files? msdn.microsoft.com/en-us/library/…
    – jaloplo
    Mar 16 '18 at 17:36
3

Let's review the the url of documents library where files are stored: https://<name>.sharepoint.com/Organisation/Section/Planning/Forms/AllItems.aspx which corresponds to the following structure:

Organisation (root site)
        |
     Section (sub site)
            |
         Planning  (documents library)
            |
           (files) 

In your example the context is getting initialized for the root site:

using (var ctx = new ClientContext(fullUri.GetLeftPart(UriPartial.Authority)))
{
}  

since for

var fullUri = new Uri("https://<name>.sharepoint.com/Organisation/Section/Planning/Forms/AllItems.aspx");

fullUri.GetLeftPart(UriPartial.Authority) is getting resolved to site url: https://<name>.sharepoint.com/

In that case Context.Web points to the root site (Organisation in your case) and with this line

var folder = Context.Web.GetFolderByServerRelativeUrl(fullUri.AbsolutePath);

you are trying to retrieve the folder which is expected to be located on the current web site, which apparently is not the case here since it resides under sub site (Section)

Given the requirements, in particular to retrieve file/file per absolute url, i would to propose the following solution:

  using (var rootCtx = new ClientContext(fullUri.GetLeftPart(UriPartial.Authority))) //1. init context for root site
  {
      rootCtx.Credentials = GetCredentials(userName, password);
      Uri webUri = Web.WebUrlFromPageUrlDirect(rootCtx, fullUri);  //2. resolve the proper web  
      using (var ctx = new ClientContext(webUri))
      {
           ctx.Credentials = GetCredentials(userName, password);

           var list = ctx.Web.GetList(fullUri.AbsolutePath); //3. get list where files reside
           ctx.Load(list.RootFolder.Files);
           ctx.ExecuteQuery();

           Console.WriteLine(list.RootFolder.Files.Count);
      }
  }

Key points:


The same concerns REST API, the valid context needs to be provided as part of service root url.

So in your case, instead of endpoint:

https://<name>.sharepoint.com/_api/web/getfolderbyserverrelativeurl('/Organisation/Section/Planning')/Files

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid context (root site)

it should be

https://<name>.sharepoint.com/Organisation/Section/_api/web/getfolderbyserverrelativeurl('/Organisation/Section/Planning')/Files

or

https://<name>.sharepoint.com/Organisation/Section/_api/web/getfolderbyserverrelativeurl('Planning')/Files
3
  • 1
    Bingo! Thank you, that was it. Do you know why SharePoint didn’t give an error when I was asking for the wrong context? Or does SharePoint just not give error messages?
    – Martijn
    Mar 19 '18 at 9:25
  • Martijn, good question but not sure why SharePoint does not raise error in that case. Maybe because the provided container (sub site folder in this case) exist.. Mar 19 '18 at 10:54
  • This looks like it will work for me, but I can't work out where GetCredentials comes from (ie. its namespace). It's not recognised by C#. I have installed the SharePointPnPCoreOnline nuget package and added 'using Microsoft.SharePoint.Client;' May 9 '20 at 13:09

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.