доступ к элементам библиотеки документов Sharepoint из приложения, размещенного у поставщика

Итак, я пытаюсь получить доступ к файлам из библиотеки документов Sharepoint на C #. Мое приложение размещено на сервере Sharepoint. Кажется, я могу получить доступ к библиотеке, но не к ее элементам.

Вот как я получаю свой контекст в контроллере:

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

И как я пытаюсь получить доступ к файлам:

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();

На этом этапе templateList имеет свойство ItemCount = 8, которое соответствует количеству файлов в библиотеке. Тем не менее, и templateFiles, и templateListItems имеют Count = 0, поэтому я не могу получить доступ к этим 8 элементам.

Я также попытался получить доступ к одному элементу по его идентификатору, который я искал на Sharepoint:

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

Но это приводит к ошибке:

Microsoft.SharePoint.Client.ServerException: 'Элемент не существует. Возможно, он был удален другим пользователем ».

Другой подход, который я пробовал, заключался в использовании GetFileByServerRelativeUrl для получения определенного файла:

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

Это дает мне следующую ошибку:

Microsoft.SharePoint.Client.ServerUnauthorizedAccessException: 'Доступ запрещен. У вас нет разрешения на выполнение этого действия или доступ к этому ресурсу. '

И да, я проверил - у меня есть полные разрешения для этой библиотеки, и она по умолчанию, поэтому разрешения на уровне элементов не отличаются от разрешений библиотеки.

Есть у кого-нибудь идеи, что я делаю не так или как правильно делать? Фактическая цель - получить доступ к определенному файлу из библиотеки по имени файла, список файлов также будет работать.


person themaksmw    schedule 30.01.2018    source источник
comment
Можете ли вы опубликовать часть вашего AppManifest.xml, в которой показан раздел AppPermissionRequests? Из того, что вы сказали, разрешения приложения неверны, и у него нет доступа к элементам списка, даже если вы это сделаете.   -  person Equalsk    schedule 30.01.2018
comment
@Equalsk My AppManifest.xml не содержит AppPermissionRequestssection. У меня только Properties с Title и StartPage и AppPrincipal с RemoteWebApplication.   -  person themaksmw    schedule 31.01.2018
comment
Предназначено ли приложение для запуска в контексте текущего пользователя или оно предназначено для запуска только с разрешениями приложения?   -  person Equalsk    schedule 31.01.2018
comment
@Equalsk Теперь, когда вы упомянули об этом ... Возможно, было бы даже лучше запускать с разрешениями только для приложений. Я изменил его сейчас на CreateAppOnlyClientContextForSPHost() и установил <AppPermissionRequests AllowAppOnlyPolicy="true" />, но код ведет себя точно так же :(   -  person themaksmw    schedule 31.01.2018
comment
Какой объем вы запрашивали? Должна быть строка вида <AppPermissionRequest Scope="http://sharepoint/content/sitecollection/web/list" Right="Write"/> (ваша может отличаться в зависимости от того, что нужно)   -  person Equalsk    schedule 31.01.2018
comment
@Equalsk Теперь для тестирования я дал полный контроль <AppPermissionRequest Scope="http://sharepoint/content/sitecollection/web/list" Right="FullControl" />   -  person themaksmw    schedule 31.01.2018
comment
Если вы перейдете к http://YourSPSite/_layouts/15/appinv.aspx и найдете свое приложение по идентификатору, что вы увидите?   -  person Equalsk    schedule 31.01.2018
comment
@Equalsk Я не могу найти приложение по его идентификатору. Идентификатор формата XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX? Возможно, я должен иметь в виду, что это dev-Sharepoint, и поэтому приложение зарегистрировано как приложение в тестировании.   -  person themaksmw    schedule 31.01.2018


Ответы (5)


Вы пытались запустить Visual Studio в качестве администратора? Если это решит вашу проблему, возможно, вам понадобится файл манифеста и необходимые изменения внутри этого администратора. Обычно это происходит, когда вы пытаетесь получить доступ к файлам, которые не являются частью пользователя Windows, что означает корневую папку (C :).

person Community    schedule 30.01.2018
comment
К сожалению, у меня нет прав администратора на моем компьютере, и поэтому я не могу запускать VS как администратор. Но часть разрешения должна быть охвачена контекстом. Я имею в виду, что весь SP не является частью пользователя Windows, но я могу прочитать количество элементов в библиотеке документов. - person themaksmw; 30.01.2018

Раньше я работал над подобными вещами, но не использовал C #. Если вы хотите попробовать другой способ, существует метод PowerShell под названием PnP PowerShell, который легко получает доступ к приложению SharePoint и возвращает данные (он официально признан Microsoft). Вы можете попробовать:

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

который возвращает все элементы из списка (помните, что библиотека документов - это просто специальный список, такой как список задач или другой), существуют версии командлета, которые возвращают только 1 элемент.

Например:

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

возвращает 1000 первых элементов списка задач.

Вот основной github: https://github.com/SharePoint/PnP-PowerShell/tree/master/Documentation

вот документ командлета: https://github.com/SharePoint/PnP-PowerShell/blob/master/Documentation/Get-PnPListItem.md

person raiskader    schedule 30.01.2018
comment
Спасибо, что показали этот альтернативный способ, но я бы предпочел придерживаться C #. - person themaksmw; 30.01.2018
comment
Как хотите, но я никогда не использовал C # для доступа к сайту SharePoint, поскольку PnP PowerShell намного проще и лучше. - person raiskader; 30.01.2018
comment
Так как больше ничего не работает, я пробую ваш подход с powerShell.AddCommand("Get-PnPFile -Url " + serverRelativeUrl + " -AsFile");. Мне удалось включить код PS в C # и, вероятно, иметь код, чтобы впоследствии уловить результат. Моя проблема - как мне включить всю библиотеку PnP? Команда не распознается. Мне, наверное, нужно Import-Module, но откуда мне импортировать? В документации предлагается только .msi, но разве это не установит модуль только на моем ПК вместо решения Visual Studio? - person themaksmw; 01.02.2018
comment
Чтобы использовать PnP PowerShell, вам необходимо загрузить и установить оболочку управления SharePoint Online. Затем установите пакет PnP с помощью команды, указанной на главной странице PnP github. Но я думаю, что их можно использовать только в оболочке управления, которую вам нужно загрузить. Я знаю, что создание сторонних программ для веб-сайта SharePoint - это боль, свяжитесь со мной, Эрван Тассин, на linkedin, если у вас не получится. - person raiskader; 01.02.2018

Еще один ответ, который я могу попытаться дать, вы запускаете свой код прямо с сервера? Иногда мне приходилось делать это, чтобы некоторые из моих программ работали.

person raiskader    schedule 30.01.2018
comment
Я не знаю, как ответить на этот вопрос. Что ж, приложение в настоящее время работает на моем локальном хосте, но оно подключено к сайту Sharepoint, который, очевидно, находится в сети. - person themaksmw; 30.01.2018
comment
У вас есть полные права администратора на сайте SharePoint? - person raiskader; 30.01.2018
comment
Я нахожусь в группе «Владельцы» и имею уровень разрешений «Полный доступ». - person themaksmw; 30.01.2018
comment
Тогда я не могу понять, в чем проблема. Попробуйте использовать ответ PowerShell, MS SP полна ошибок и вещей, которые даже MS не понимает, а поддержка очень тонкая. А с PnP PowerShell, это 5 строк кода, вы можете передать результаты в файл .csv и бум, хорошая работа быстро сделана. - person raiskader; 30.01.2018
comment
Проблема в том, что мне нужно получить доступ к определенному файлу внутри моего кода C #. Поэтому мне действительно нужен поток файла. Один раз я использую его для преобразования docx в pdf (с помощью служб автоматизации слов) и несколько раз для открытия docx как WordprocessingDocument и чтения или изменения содержимого. - person themaksmw; 30.01.2018
comment
для этого есть командлет: Get-PnPFile -Url <String> [-Web <WebPipeBind>] [-Connection <SPOnlineConnection>] он загружает файл - person raiskader; 30.01.2018

Чтобы получить доступ к файлу элемента списка, вам необходимо получить доступ к самому элементу списка и загрузить его свойство File в контексте:

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;

Вы абсолютно уверены, что у вас есть файл с ID = 1? Используйте свой код:

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

clientContext.Load (templateListItems);

clientContext.ExecuteQuery ();

получить все предметы и проверить их идентификаторы.

ИЗМЕНИТЬ

На основе вашего комментария - Вы пытались использовать другой запрос (написать свой собственный), который будет извлекать некоторые элементы на основе правила. Поскольку свойство templateList.ItemCount дает вам некоторое значение, это еще не означает, что вы правильно загрузили элементы. Это означает, что вы загрузили список.

Что-то есть с запросом. Из того, что я вижу во всех примерах, они создают такой запрос:

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

Я знаю, что это не похоже на нарушение условий сделки, но вы знаете - SharePoint ... Попробовать стоит.

person m3n7alsnak3    schedule 30.01.2018
comment
Моя проблема заключается не в доступе к свойству File элемента, а в доступе к элементам списка вообще. Как уже указывалось в вопросе, мой код для templateListItems дает мне templateListItems.Count = 0, поэтому я не могу использовать его для получения всех элементов и проверки их идентификаторов. получить все предметы ЯВЛЯЕТСЯ актуальной проблемой. И да, я уверен в идентификаторах. Я заставил Sharepoint показать мне идентификаторы в библиотеке, и поскольку библиотека еще не была затронута, на самом деле идентификаторы 8 файлов составляют от 1 до 8. - person themaksmw; 31.01.2018
comment
Я тоже пробовал это сделать, запрос был определен отдельно, но он работает так же, как и предыдущий - templateListItems.Count = 0. - person themaksmw; 01.02.2018

Наконец-то я заработал! Оказывается, права на SharePoint неправильные.

В SharePoint на вкладке «Приложения в тестировании» вы можете щелкнуть «...» рядом с вашим приложением и перейти к «УПРАВЛЕНИЕ РАЗРЕШЕНИЯМИ» < / em>, и вы будете перенаправлены на страницу с вопросом «Доверяете ли вы XXX?». Я был так сосредоточен на вопросе и кнопках "Доверять" и "Отмена", что не увидел раскрывающегося слева выпадающего меню с надписью "Пусть иметь полный контроль над списком: " с предварительно выбранными " Пакеты приложений ". Когда я изменил его на список, к которому пытался получить доступ, один из подходов в моем коде внезапно сработал:

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

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

Теперь templateListItems действительно содержит объекты из моей библиотеки!

Конечно, можно «оптимизировать» код и удалить первый ExecuteQuery(), или определить CamlQuery.CreateAllItemsQuery() как отдельную переменную и передать ее GetItems(), или использовать vars вместо явных типов - все это работает, это зависит от ваших предпочтений.

Цените всю помощь, надеюсь, я получил ее отсюда :)

person themaksmw    schedule 01.02.2018