Forum Discussion

Sean_Archer's avatar
Sean_Archer
Copper Contributor
May 03, 2023
Solved

Sharepoint Rest API only returning results for single folder

We have an integration that uses the Sharepoint REST API to Create and Query files and folders in a Sharepoint Online document library. 

 

The integration creates a folder structure whenever a new Item Code is added within an SAP Application.  

When navigating to an Item record in SAP we query the files for that item from the document library to display in SAP.

 

The issue we have is that the integration is only returning results for the very first folder we created.  Files within other folders are not returned even though the permissions appear the same.

 

The following is the code snippet we are using to return the results...

 

private const string constSiteDomain = "our domain";
private const string constSiteAddress = "our site address";
private const string constWebAPI = "_api/web";
private static readonly string _domainUrl = string.Format("https://{0}/", constSiteDomain);
private static readonly string _fmsSiteUrl = string.Format("{0}{1}/", _domainUrl, constSiteAddress);
private static readonly string _sapItemsUrl = string.Format("{0}{1}/", _fmsSiteUrl, constWebAPI);

public static string GetSharepointFilesForItemCode(string itemCode, string subPath = "", int summarizeFolders = 1)
{
    string getFilesURL = string.Format("{0}Lists/GetByTitle('Documents')/RenderListDataAsStream?viewid=9ca7ac23-97f3-45ad-8d41-4a68fb23657d", _sapItemsUrl);
    string fileContents = string.Empty;
    using (HttpRequestMessage getDocumentsRequest = new HttpRequestMessage(HttpMethod.Post, getFilesURI))
    {
        getDocumentsRequest.Headers.Add("Authorization", string.Format("Bearer {0}", BearerToken));                    
        getDocumentsRequest.Headers.Add("Accept", "application/json;odata=nometadata");

        string serverRelativeUrl = string.Format("/sites/FMS/Shared Documents/SAP_Items/{0}/{1}", itemCode, subPath);
        string viewXml = string.Concat(
            "<View Scope=\"RecursiveAll\">",
            "<Query><Where><Eq><FieldRef Name=\"FSObjType\"/><Value Type=\"Number\">0</Value></Eq></Where></Query>",
            "<RowLimit Paged=\"TRUE\">1000</RowLimit>",
            "<ViewFields>",
            "<FieldRef Name=\"ID\"/>",
            "<FieldRef Name=\"FileLeafRef\"/>",
            "<FieldRef Name=\"FileRef\"/>",
            "<FieldRef Name=\"FileRef.urlencode\"/>",
            "<FieldRef Name=\"FSObjType\"/>",
            "</ViewFields>",
            "</View>");


        var renderListDataParameter = new
        {
            parameters = new
            {
                FolderServerRelativeUrl = serverRelativeUrl,                            
                ViewXml = viewXml,
                AddRequiredFields = true
            }
        };

        string dataParameterString = JsonSerializer.Serialize(renderListDataParameter);

        StringContent payloadContent = new StringContent(dataParameterString, Encoding.UTF8, "application/json");
        getDocumentsRequest.Content = payloadContent;

        using (HttpResponseMessage getDocumentsResponse = _httpClient.SendAsync(getDocumentsRequest).Result)
        {
            getDocumentsResponse.EnsureSuccessStatusCode();
            fileContents = getDocumentsResponse.Content.ReadAsStringAsync().Result;
        }
    }

    if (string.IsNullOrEmpty(fileContents))
        throw new Exception("No files found");

    JsonNode data = JsonNode.Parse(fileContents);
    JsonArray rowData = data["Row"].AsArray();
    foreach (JsonNode row in rowData)
    {
        // Do some stuff
    }
}

 

The above code returns all files within the folder and subfolders of the specified item code.  However, it is only working for the tree of the first item we added to the document library.  For every other item the HttpResponseMessage has a success status code but no items are returned.

 

The folder structure, files and their permissions look correct (the same as the item that is working) and I have tried re-indexing the library.

 

Any insights or suggestions appreciated.

 

Cheers,

Sean

  • Deleted's avatar
    Deleted
    May 12, 2023

    Sean_Archer 

    you can execute a CAML query against the results obtained from the `GetFolderByServerRelativeUrl` endpoint to achieve a RecursiveAll query and retrieve all files below a specified folder. However, the SharePoint REST API doesn't directly support CAML queries on folders. Instead, you can recursively call the `GetFolderByServerRelativeUrl` endpoint to retrieve files and subfolders.

    Here's an example of how you can recursively retrieve files and folders using PowerShell and the SharePoint REST API:

     

    private static void GetFilesAndFoldersRecursive(string folderServerRelativeUrl)
    {
    string filesUrl = $"{_sapItemsUrl}GetFolderByServerRelativeUrl('{folderServerRelativeUrl}')/Files";
    string foldersUrl = $"{_sapItemsUrl}GetFolderByServerRelativeUrl('{folderServerRelativeUrl}')/Folders";
    
    // Retrieve files in the current folder
    string filesResponse = SendGetRequest(filesUrl);
    // Process files...
    
    // Retrieve subfolders in the current folder
    string foldersResponse = SendGetRequest(foldersUrl);
    JsonNode data = JsonNode.Parse(foldersResponse);
    JsonArray foldersArray = data["value"].AsArray();
    
    foreach (JsonNode folderNode in foldersArray)
    {
    string subfolderServerRelativeUrl = folderNode["ServerRelativeUrl"].AsString();
    
    // Recursively call the method for each subfolder
    GetFilesAndFoldersRecursive(subfolderServerRelativeUrl);
    }
    }
    
    private static string SendGetRequest(string url)
    {
    using (HttpClient client = new HttpClient())
    {
    client.DefaultRequestHeaders.Accept.Clear();
    client.DefaultRequestHeaders.Add("Authorization", $"Bearer {BearerToken}");
    
    HttpResponseMessage response = client.GetAsync(url).Result;
    response.EnsureSuccessStatusCode();
    
    return response.Content.ReadAsStringAsync().Result;
    }
    }

    In the above code, the `GetFilesAndFoldersRecursive` method takes the server-relative URL of a folder as a parameter. It first retrieves the files within the current folder using the `GetFolderByServerRelativeUrl` endpoint with the `/Files` suffix. Next, it retrieves the subfolders using the same endpoint with the `/Folders` suffix. It then processes the files in the current folder and recursively calls itself for each subfolder, passing the server-relative URL of the subfolder.

    You can modify and integrate this code into your existing solution to retrieve all files below a specified folder in a recursive manner. Make sure to provide the correct server-relative URL of the starting folder when calling the `GetFilesAndFoldersRecursive` method.

    Note: This example uses the `HttpClient` class for making HTTP requests. Ensure that you have the necessary namespaces imported and handle the disposal of the `HttpClient` instance appropriately in your actual implementation.

    By recursively traversing the folder structure, you can retrieve all files and folders below a specified folder in SharePoint using the SharePoint REST API.

     

    If I have answered your question, please mark your post as Solved
    If you like my response, please give it a like

6 Replies

  • Based on the provided code, it seems like the issue may be related to the `serverRelativeUrl` variable that's used to construct the REST API URL.

    In the code, the `serverRelativeUrl` variable is set to the path of the folder structure for the specified item code. If this path is incorrect or doesn't exist for other items, the REST API call may not return any results.

    To troubleshoot this issue, you can try the following:

    1. Check that the folder structure for the other items exists in the document library and has the same permissions as the working item.

    2. Verify that the `serverRelativeUrl` variable is constructed correctly for each item. You can try logging the value of this variable to the console to confirm that it matches the expected path.

    3. Try querying the document library using the SharePoint REST API directly, without the C# code, to see if the issue is with the code or the SharePoint site. You can use a tool like Postman to send HTTP requests to the SharePoint REST API.

    4. Check the SharePoint site's logs or monitoring tools to see if any errors or issues are reported when querying for the files.

    Overall, it's difficult to determine the exact cause of the issue without more information or debugging. However, checking the folder structure, URL path, and using the SharePoint REST API directly can help pinpoint the issue.
    • Sean_Archer's avatar
      Sean_Archer
      Copper Contributor
      Another thing that is odd is that the following calls return files for both items...
      _api/web/GetFolderByServerRelativeUrl('Shared Documents/SAP_Items/DCW0012-B600-R12_TEST/Media/Web')/Files
      _api/web/GetFolderByServerRelativeUrl('Shared Documents/SAP_Items/DCW0012-B600-114_TEST/Media/Web')/Files

      Is there a way to execute a Caml Query against the GetFolderByServerRelativeUrl results to do a RecursiveAll query...at the end of the day I am trying to return all files below a specified folder. If this fails I will have to recursively call GetFolderByServerUrl to retrieve the Files and Folders, which I'm sure will be very slow 😞
      • Deleted's avatar
        Deleted

        Sean_Archer 

        Yes, you can execute a CAML query against the results of the GetFolderByServerRelativeUrl method. To do this, you will need to use the ListItemAllFields property. The ListItemAllFields property is a collection of all of the fields for a list item. This includes the fields for the files and folders that are contained in the folder.

         

        To execute a CAML query against the ListItemAllFields property, you will need to use the LINQ to SharePoint API. The LINQ to SharePoint API is a set of classes that allow you to query SharePoint data using LINQ queries.

         

        To use the LINQ to SharePoint API, you will need to add a reference to the Microsoft.SharePoint.Client.dll assembly to your project. Once you have added the reference, you can start using the LINQ to SharePoint API to query SharePoint data.

         

        The following code shows how to execute a CAML query against the ListItemAllFields property to return all files below a specified folder:

         

         

        using (var ctx = new ClientContext(webUri))
        
        {
        
          // Get the folder by server relative URL.
        
          var folder = ctx.Web.GetFolderByServerRelativeUrl(folderUrl);
        
        
        
          // Get the list item all fields for the folder.
        
          var listItemAllFields = folder.ListItemAllFields;
        
        
        
          // Create a CAML query.
        
          var camlQuery = new CamlQuery();
        
        
        
          // Set the view scope to recursive all.
        
          camlQuery.ViewXml = @"<View Scope='RecursiveAll'/>";
        
        
        
          // Execute the CAML query against the list item all fields.
        
          var results = ctx.Load(listItemAllFields, l => l.FieldValues).ExecuteQuery();
        
        
        
          // Iterate through the results and print the file names.
        
          foreach (var result in results)
        
          {
        
            var fileName = result.FieldValues["FileRef"].ToString();
        
            Console.WriteLine(fileName);
        
          }
        
        }

         

         

        This code will return all files below the specified folder.

         

        If I have answered your question, please mark your post as Solved
        If you like my response, please give it a like
    • Sean_Archer's avatar
      Sean_Archer
      Copper Contributor

      Deleted 

      Thank you for the suggestions.  Please see the comments in Bold below

       


      Deleted wrote:
      Based on the provided code, it seems like the issue may be related to the `serverRelativeUrl` variable that's used to construct the REST API URL.

      In the code, the `serverRelativeUrl` variable is set to the path of the folder structure for the specified item code. If this path is incorrect or doesn't exist for other items, the REST API call may not return any results.

      To troubleshoot this issue, you can try the following:

      1. Check that the folder structure for the other items exists in the document library and has the same permissions as the working item.
      The file structure for both items is the same and works for other searches.  I have also double checked the permissions are the same on both folders and subfolders.
      DCW0012-B600-R12_TEST has files but returns no data
      DCW0012-B600-114_TEST has files and returns data


      2. Verify that the `serverRelativeUrl` variable is constructed correctly for each item. You can try logging the value of this variable to the console to confirm that it matches the expected path.
      I have verified this both in my code and in Postman

      3. Try querying the document library using the SharePoint REST API directly, without the C# code, to see if the issue is with the code or the SharePoint site. You can use a tool like Postman to send HTTP requests to the SharePoint REST API.
      Good Call.  Running the query in Postman I get the same results as my application.
      For DCW0012-B600-R12_TEST I get the following with no row data
      {
          "Row": [],
          "FirstRow"1,
          "FolderPermissions""0x7ffffffffffbffff",
          "LastRow"0,
          "RowLimit"30,
          "FilterLink""?",
          "ForceNoHierarchy""1",
          "HierarchyHasIndention""",
          "CurrentFolderSpItemUrl"""
      }

      For DCW0012-B600-114_TEST  the rows array has the file details
      {
          "Row": [
              {
                  "ID""3544",
                  "PermMask""0x7fffffffffffffff",
                  "FSObjType""0",
                  "HTML_x0020_File_x0020_Type""",
                  "UniqueId""{F6D1E477-ED9F-492A-920A-C30A8F88A714}",
                  "ProgId""",
                  "NoExecute""1",
                  "ContentTypeId""0x01010041E4CB00DC5F6849AAB5E7D9774C969D",
      ...

      4. Check the SharePoint site's logs or monitoring tools to see if any errors or issues are reported when querying for the files.
      I'm not sure where to find these so will reach out to the Sites Administrator. 

      Overall, it's difficult to determine the exact cause of the issue without more information or debugging. However, checking the folder structure, URL path, and using the SharePoint REST API directly can help pinpoint the issue.

      Yes, it is proving very difficult to pinpoint.  The fact that the query is behaving the same way in Postman suggests the issue probably lies more in the Site Configuration or behaviour rather than the code. 

       

      One thing to note is that there are no Lists on the site, only the Document Library.  I am assuming that the Document Library is treated as a list as we can use the /Lists/GetByTitle('Documents') to return the list and the fact that the query is working for at least 1 item.

Resources