简体   繁体   中英

access Sharepoint document library items from provider-hosted app

So I'm trying to access files from a Sharepoint document library in C#. My app is a provider-hosted Sharepoint app. I seem to be able to access the library, but not the library's items.

Here is how I get my context in the controller:

var spContext = SharePointContextProvider.Current.GetSharePointContext(System.Web.HttpContext.Current);
using (var clientContext = spContext?.CreateUserClientContextForSPHost())
{
    if (clientContext != null)
    {
        template.SetMergefields(clientContext);
    }
}

And how I try to access the files:

Web web = clientContext.Web;

List templateList = web.Lists.GetByTitle(libraryName);
clientContext.Load(templateList);
clientContext.ExecuteQuery();

var templateFiles = templateList.RootFolder.Files;
clientContext.Load(templateFiles);
clientContext.ExecuteQuery();

var templateListItems = templateList.GetItems(CamlQuery.CreateAllItemsQuery());
clientContext.Load(templateListItems);
clientContext.ExecuteQuery();

At this point, the templateList has the property ItemCount = 8 which does match the number of the files in the library. Yet, both templateFiles and templateListItems , have Count = 0 so I don't seem to be able to access these 8 items.

I have also tried to access a single item by it's id which I looked up on Sharepoint:

var itemWithId1 = templateList.GetItemById(1);
clientContext.Load(itemWithId1);
clientContext.ExecuteQuery();

Yet this leads to the error:

Microsoft.SharePoint.Client.ServerException: 'Item does not exist. It may have been deleted by another user.'

Another approach I tried was using the GetFileByServerRelativeUrl to get a specific file:

File file = clientContext.Web.GetFileByServerRelativeUrl(serverRelativeUrl);
clientContext.Load(file);
clientContext.ExecuteQuery();

This gives me the following error:

Microsoft.SharePoint.Client.ServerUnauthorizedAccessException: 'Access denied. You do not have permission to perform this action or access this resource.'

And yes I've checked - I do have full permissions for this library and it's on default settings so item-level permissions do not vary from library's permissions.

Does anyone have an idea what I'm doing wrong or how to do it properly? The actual goal is to access a specific file from the library by the file's name, a file list would also work.

Did you try to start Visual Studio as Admin? If that solves your problem, you might be needing a manifest file and change inside that admin required. It normally happens when you're trying to access files that are not part of the Windows User, which means the root folder(C:).

I worked on this type of things before, but I didn't use C#. If you want to try another way, there is a PowerShell Method called PnP PowerShell that accesses easily the SharePoint app and return things (It is officially recognised by Microsoft). You could try with :

Get-PnPListItem -List <ListPipeBind>
            [-Fields <String[]>]
            [-PageSize <Int>]
            [-ScriptBlock <ScriptBlock>]
            [-Web <WebPipeBind>]
            [-Connection <SPOnlineConnection>]

which returns all items from a list (remember that a document library is just a special list, like a task list or other), there are versions of the cmdlet that only return 1 item.

For example:

PS:> Get-PnPListItem -List Tasks -PageSize 1000

returns the 1000 first elements of the Tasks list.

Here is the main github: https://github.com/SharePoint/PnP-PowerShell/tree/master/Documentation

here is the cmdlet documentaion: https://github.com/SharePoint/PnP-PowerShell/blob/master/Documentation/Get-PnPListItem.md

Another answer I can try to give, do you run your code directly from the server location? I sometimes needed to do that to make some of my programs work.

To access the file of a list item, you need to access the list item itself, and load its File property within the context:

var docs = clientContext.Web.Lists.GetByTitle(Library);
var listItem = docs.GetItemById(listItemId);
clientContext.Load(docs);
clientContext.Load(listItem, i => i.File);
clientContext.ExecuteQuery();

var fileRef = listItem.File.ServerRelativeUrl;

Are you absolutely sure, that you have a file with ID = 1 ? Use your code:

var templateListItems = templateList.GetItems(CamlQuery.CreateAllItemsQuery());

clientContext.Load(templateListItems);

clientContext.ExecuteQuery();

get all the items, and check their ids.

EDIT

Based on your comment - Did you try with a different Query (writing your own) that will retrieve some items based on a rule. Because the property templateList.ItemCount giving you some value, still doesn't mean that you have loaded the items properly. It means that you have loaded the list.

There is something with the Query. From what I see in all the examples they are creating a query like this:

var query = CamlQuery.CreateAllItemsQuery();
var templateListItems = templateList.GetItems(query);

I know that it doesn't seem like a deal breaker, but you know - SharePoint... It's worth the try.

I finally got it to work! Turns out, that the permissions on SharePoint where wrong.

On SharePoint, in the "Apps in Testing" Tab, you can click the "..." next to your app, go to "MANAGE PERMISSIONS" and you will be forwarded to a page that asks you "Do you trust XXX?" . I was so focused on the question and the "Trust It" and "Cancel" Buttons that I didn't see the dropdown on the left saying "Let it have full control of the list:" with "App Packages" pre-selected. When I changed it to the list I was trying to access, one of the approaches in my code suddenly worked:

List templateList = web.Lists.GetByTitle(libraryName);
clientContext.Load(templateList);
clientContext.ExecuteQuery();

ListItemCollection templateListItems = templateList.GetItems(CamlQuery.CreateAllItemsQuery());
clientContext.Load(templateListItems);
clientContext.ExecuteQuery();

Now templateListItems actually contains objects from my library!

One can of course "optimize" the code and delete the first ExecuteQuery() , or define the CamlQuery.CreateAllItemsQuery() as a separate variable and pass it to GetItems() , or use var s instead of explicit types - all of those work, it's up to your preferences.

Appreciate all the help, I hope I've got it from here on :)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM