0

I have a folder structure similar to this on our SharePoint Online site:

Documents/
    Drawings/
         For Review/
         Released/
         Archived/
    Documentation/
         For Review/
         Released/
         Archived/
    Pictures/
         For Review/
         Released/
         Archived/

What I'm trying to do is write a function that will recursively search under just one of the directories, say, "Drawings", and return all of the filenames and their paths relative to Documents, ideally without hardcoding any of the subdirectories (e.g., the names may change or more may be added).

It was pretty easy to do a recursive query in a CamlQuery to find all of the Files under Documents, and I could just parse their paths to get what I want, but there should be a similar way to specify a server relative path and then descend recursively starting from there, but I haven't been able to figure it out.

Here is what I wrote to retrieve a file stream from a specific folder:

    public static Stream GetFileFromSpecificLocation(string directoryPath, string fileName)
    {
        using var cc = new AuthenticationManager().GetACSAppOnlyContext(siteUrl,
            appId, clientSecret);

        List documents = cc.Web.Lists.GetByTitle("Documents");
        cc.Load(documents.RootFolder);
        cc.ExecuteQuery();

        var combinedPath = $"{documents.RootFolder.ServerRelativeUrl}/{directoryPath.UrlPathEncode()}";

        Folder f = cc.Web.GetFolderByServerRelativeUrl(combinedPath);
        cc.Load(f, xf => xf.Files);
        cc.ExecuteQuery();

        foreach (var file in f.Files)
        {
            cc.Load(file, f => f.Name);
            cc.ExecuteQuery();
            if (file.Name != fileName) continue;

            ClientResult<Stream> streamResult = file.OpenBinaryStream();
            cc.Load(file);
            cc.ExecuteQuery();
            return streamResult.Value;
        }

        return null;
    }

This is in a .NET Core application, so I'm a little limited in a few libraries.

1 Answer 1

0

Missed the FolderServerRelativeUrl property of the CamlQuery.

Here is a solution:

    public static List<string> GetAllFilesUnderFolder(string startFolder)
    {
        var fileList = new List<string>();

        using var cc = new AuthenticationManager().GetACSAppOnlyContext(siteUrl,
            appId, clientSecret);

        List documents = cc.Web.Lists.GetByTitle("Documents");
        cc.Load(documents);
        cc.Load(cc.Web, w => w.ServerRelativeUrl);
        cc.ExecuteQuery();

        var query = CamlQuery.CreateAllItemsQuery();
        if (startFolder[0] != '/')
        {
            startFolder = $"/{startFolder}";
        }
        query.FolderServerRelativeUrl = $"{cc.Web.ServerRelativeUrl}{startFolder}";

        ListItemCollection items = documents.GetItems(query);

        cc.Load(items);

        cc.ExecuteQuery();

        foreach (var item in items)
        {
            if ((string) item.FieldValues["FSObjType"] == "0")
            {
                fileList.Add(item.FieldValues["FileRef"].ToString());
            }
        }

        return fileList;
    }

Improvements/comments would be welcome...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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