Question

Information given

I am using version 16.0.0.0 of the Microsoft.SharePoint.Client library. There are several different document libraries in the SharePoint site. In code, we are given a list of document URLs (containing document GUIDs) and need to determine in which Document Library each is located, including the sub-folder if it is in a folder in the library.

Document Id (GUID) - gathered from document url query parameter "sourcedoc" ex: "http://mycompany.sharepoint.com/spsite/_layouts/15/WopiFrame.aspx?action=default&file=testfile.docx&sourcedoc={6A290A65-4759-41ED-A13E-3333B45DF133}"

Information needed

  • Document Library Name
  • Document Library URL
  • Folder Name (if any)
  • Folder URL (if any)

Current Code

using SP = Microsoft.SharePoint.Client;

public class LibraryAndFolderInfo
{
    public LibraryAndFolderInfo();

    public string FolderName { get; set; }
    public string FolderUrl { get; set; }
    public string LibraryName { get; set; }
    public string LibraryBaseUrl { get; set; }
}

public class SPDataAccess
{
    public LibraryAndFolderInfo GetLibraryAndFolderInfo(Guid documentGuid)
    {
        SP.File file = Web.GetFileById(documentGuid);

        Context.Load(file);

        if (file != null)
        {
            Context.Load(file.ListItemAllFields);
            Context.ExecuteQuery();
            SP.ListItem item = file.ListItemAllFields;

            Context.Load(item.ParentList);
            Context.ExecuteQuery();

            SP.List list = item.ParentList;
            Context.Load(list);
            Context.ExecuteQuery();

            Context.Load(item.Folder);
            Context.ExecuteQuery();

            SP.Folder folder = item.Folder;
            Context.Load(folder);
            Context.ExecuteQuery();

            LibraryAndFolderInfo lib = new LibraryAndFolderInfo();
            lib.LibraryName = list.Title;
            lib.LibraryBaseUrl = list.DefaultViewUrl;
            lib.FolderName = folder.Name;
            lib.FolderUrl = folder.ServerRelativeUrl;

            return lib;
        }

        return null;
    }

    protected SP.ClientContext Context { get; set; }
}


The code currently fails at this line: Context.Load(item.ParentList); with the following error:

The property or field 'Title' has not been initialized. It has not been requested or the request has not been executed. It may need to be explicitly requested.

at Microsoft.SharePoint.Client.ClientObject.CheckUninitializedProperty(String propName)
at Microsoft.SharePoint.Client.List.get_Title()
at MyNamespace.SPDataAccess.GetLibraryAndFolderInfo(Guid documentGuid) in c:\path\SPDataAccess.cs:line 27

This line seems to be attempting to retrieve the Title of the list as it is being loaded and failing. Is this a correct assumption?

I am not super familiar with how exactly to load properties, so everything after the failing line is my best guess as to how it would work.

What is this code supposed to look like? Has anyone else tried to get this information from a document?

Was it helpful?

Solution

Below are provided some corrections, fixes and considerations for your code:

1)The condition if (file != null) is incorrect since it could not be used to determine whether file exists or not. The following example demonstrates how to verify whether file has been loaded:

SP.File file = Context.Web.GetFileById(documentGuid);
Context.Load(file);
Context.ExecuteQuery();

if (file.ServerObjectIsNull != null)
{
    //File has been loaded..
}

2)item.Folder does not return parent Folder, it returns Folder associated with List Item and it is not the same

How to return parent Folder for a File?

var file = Context.Web.GetFileById(documentGuid);
Context.Load(file,i => i.ListItemAllFields);
Context.ExecuteQuery();
var folder = Context.Web.GetFolderByServerRelativeUrl((string)file.ListItemAllFields["FileDirRef"]);
Context.Load(folder);
Context.ExecuteQuery();

3)List.DefaultViewUrl returns a default view server relative url and it is not the same as List server relative url

How to retrieve List Url?

var file = Context.Web.GetFileById(documentGuid);
var item = file.ListItemAllFields;
Context.Load(item.ParentList, l => l.RootFolder);
Context.ExecuteQuery();
var listUrl = item.ParentList.RootFolder.ServerRelativeUrl;

4)Since SharePoint CSOM supports Request Batching there is no need to submit multiple queries, instead in some cases you could submit only a single batch query as demonstrated below:

    SP.File file = Context.Web.GetFileById(documentGuid);
    SP.ListItem item = file.ListItemAllFields;
    var list = item.ParentList;
    Context.Load(list, l => l.Title, l => l.RootFolder);
    Context.Load(item);
    Context.ExecuteQuery(); //<- submit a single batch query

Fixed example

public class SPDataAccess
{

    public SPDataAccess(SP.ClientContext ctx)
    {
        Context = ctx;
    }

    public LibraryAndFolderInfo GetLibraryAndFolderInfo(Guid documentGuid)
    {
        var file = Context.Web.GetFileById(documentGuid);
        var item = file.ListItemAllFields;
        var list = item.ParentList;
        Context.Load(list, l => l.Title, l => l.RootFolder);
        Context.Load(item);
        Context.ExecuteQuery();


        var info = new LibraryAndFolderInfo();
        var folderUrl = (string)item["FileDirRef"];
        info.LibraryName = list.Title; //list title
        info.LibraryBaseUrl = list.RootFolder.ServerRelativeUrl; //list url  
        if (folderUrl.Replace(list.RootFolder.ServerRelativeUrl, string.Empty).Length > 0)
        {
            info.FolderName = folderUrl.Split('/').Last(); //folder name
            info.FolderUrl = folderUrl;
        }

        return info;
    }

    protected SP.ClientContext Context { get; private set; }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with sharepoint.stackexchange
scroll top