Amar
Amar

Reputation: 27

CSOM - FileRef vs ServerUrl vs sp.listitem.ServerRelativeUrl

I have lately been working on SharePoint CSOM and have been dealing with file handling in document libraries (Upload / download / metadata updation). I have come across a couple of ways to get the server relative url of a file namely listitem["FileRef"] or listitem.ServerRelativeUrl. this link a link that gives a list of internal names for sharepoint fields. Note that it lists "Server Relative URL" as "ServerUrl". However, when i try to access something like listitem["ServerUrl"] an exception is thrown:

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

Heres my code sample

    using (ClientContext clientContext = new ClientContext(siteUrl))
{
clientContext.Credentials = new NetworkCredential("abc", "abc", "cde");
List oList = clientContext.Web.Lists.GetByTitle("abcd");
clientContext.Load(oList);
clientContext.ExecuteQuery();
CamlQuery camlQuery = new CamlQuery();

ListItemCollectionPosition itemPosition = null;

conn.Open();
while (true)
{
    camlQuery = new CamlQuery();
    camlQuery.ListItemCollectionPosition = itemPosition;

        camlQuery.ViewXml =
            //@"<View Scope='RecursiveAll'>
            string.Format(@"<View Scope='RecursiveAll'>
                            <Query>
                                <Where>
                                    <And>
                                        <Eq>
                                            <FieldRef Name='FSObjType' />
                                            <Value Type='Integer'>0</Value>
                                        </Eq>
                                        <In>
                                            <FieldRef Name='FileLeafRef' />
                                            <Values>
                                                {0}
                                            </Values>
                                        </In>                                
                                    </And>
                                </Where>
                            </Query>
                            <FieldRef Name='FileLeafRef' /><FieldRef Name='FileRef'><FieldRef Name='ServerUrl'>
                            <RowLimit>100</RowLimit>
                          </View>", CAMLcoll);

    ListItemCollection listItems = oList.GetItems(camlQuery);

    clientContext.Load(listItems);
    clientContext.ExecuteQuery();
    itemPosition = listItems.ListItemCollectionPosition;

    foreach (ListItem listItem in listItems)
    {
        try
        {
            clientContext.Load(listItem, eachitem => eachitem.File.ServerRelativeUrl);
            clientContext.ExecuteQuery();
            string url = listItem["FileRef"].ToString(); //This works
            url = listItem.ServerRelativeUrl.ToString(); //This works
            url = listItem["ServerUrl"].ToString(); //This throws exception!!
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.ToString());
        }
    }
    if (itemPosition == null)
        break;
    //Debug.Print(itemPosition.PagingInfo);
}

I have a couple of questions:

  1. what is the difference between these 3 ways of accessing items server relative url?

  2. Why does url = listItem["ServerUrl"].ToString() fail?

I am pretty new to CSOM programming so please excuse me for my ignorance.

Thanks

Amar

Upvotes: 0

Views: 5243

Answers (1)

Gautam Sheth
Gautam Sheth

Reputation: 2500

First of all the ServerRelativeUrl works only with the File class.

So, your code should be listItem.File.ServerRelativeUrl.ToString();

Regarding your first question related to differences, I think they all give the same result. That means, FileRef , listItem.File.ServerRelativeUrl and ServerUrl provide you with the same Server relative path of a document inside a document library.

Regarding your second question, in SharePoint CSOM, you need to explicitly the load the properties that you want to utilize. Some basic properties are provided but for certain other properties, like in your case ServerUrl, you need to explicitly load it so that you can use it.

Thirdly, your code is executing and requesting data for each list item. This is simply not needed. You can load these properties in your list item collection.

Have modified, simplified and optimized your code. Do have a look:

ListItemCollection listItems = oList.GetItems(camlQuery);
clientContext.Load(listItems,items => items.Include(
                        item => item["FileRef"],
                        item => item.File.ServerRelativeUrl,
                        item => item["ServerUrl"]));
clientContext.ExecuteQuery();

itemPosition = listItems.ListItemCollectionPosition;

foreach (ListItem listItem in listItems)
{
    try
    {

        string url = listItem["FileRef"].ToString(); //This works
        url = listItem.File.ServerRelativeUrl.ToString(); //This should work
        url = listItem["ServerUrl"].ToString(); //This will work now
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.ToString());
    }
}

Upvotes: 2

Related Questions