CSOM. Загрузка файлов

Пример загрузки документов в библиотеку SharePoint с помощью клиентской модели SharePoint .NET (CSOM).

Это простое консольное приложение созданное с помощью Visual Studio 2017, которое работает со следующими версиями SharePoint:

  • SharePoint 2013
  • SharePoint 2016
  • SharePoint 2019
  • SharePoint Online

Теоретически должно работать и с SharePoint 2010. Я не проверял - нет под рукой разработческого SharePoint.

Консольное приложение

Запускаем Visual Studio и создаем новый проект - Консольное приложение (.NET Framework):

Новое приложение в Visual Studio

Новое приложение в Visual Studio

После того как приложение создано необходимо добавить ссылки на сборки для работы с SharePoint.

Существуют как минимум два способы сделать это:

Добавить ссылку на существующую сборку Microsoft.SharePoint.Client.dll, которая расположена в папке %ProgramFiles%\Common Files\Microsoft Shared\web server extensions**{15|16}**\ISAPI (если есть установленный SharePoint).

Второй способ - добавление nuget-пакета, выпущенного компанией Microsoft.

В демонстрационном проекте я использовал NuGet.

NuGet Пакет

Чтобы установить пакет Microsoft.SharePointOnline.CSOM, который содержит CSOM-библиотеки как для SharePoint, так и для Project Server/Online, просто выполните следующую команду в консоле управления пакетами:

PM> Install-Package Microsoft.SharePointOnline.CSOM

Всё необходимое есть, теперь можно создавать код.

ClientContext

Для работы с SharePoint с помощью CSOM необходимо инициализировать объект ClientContext:

// URL-адрес сайта SharePoint
var siteUrl = "https://sharepointsiteurl";

using (var ctx = new ClientContext(siteUrl))
{
    // Код для работы с SharePoint
}

Перед тем как выполнять какие-либо операции необходимо предоставить учетные данные.

Учетные данные в ClientContext

Свойство Credentials должно быть представлено объектом, который реализует интерфейс ICredential:

Интерфейс ICredential

Интерфейс ICredential

Таких классов несколько:

  • System.Net.CredentialCache
  • System.Net.NetworkCredential
  • Microsoft.SharePoint.Client.SharePointOnlineCredentials
  • Microsoft.SharePoint.IdentityModel.OAuth2.OAuth2BearerCredentials

Классы, реализующие интерфейс

Классы, реализующие интерфейс ICredential

Используйте класс SharePointOnlineCredentials для работы с SharePoint Online и NetworkCredential в остальных случаях.

Если Вы попробуете использовать SharePointOnlineCredentials для работы с on-premise SharePoint, то будет выброшено такое исключение:

Microsoft.SharePoint.Client.ClientRequestException: The IDCRL response header from server '{SharePointSiteUrl}' is not valid. The response header value is 'NTLM'. The response status code is 'Unauthorized'. All response headers are 'SPRequestDuration=3, SPIisLatency=0, MicrosoftSharePointTeamServices=16.0.0.10711: 1; RequireReadOnly, Content-Length=16, Content-Type=text/plain; charset=utf-8, Date=Fri, 27 Jul 2018 14:53:07 GMT, Server=Microsoft-IIS/10.0, WWW-Authenticate=NTLM, X-Powered-By=nosniff'.

Или такое:

System.NotSupportedException: Cannot contact web site '' or the web site does not support SharePoint Online credentials. The response status code is 'OK'. The response headers are
X-SharePointHealthScore=4,
SPRequestGuid=74ee7e9e-8c75-309f-b9c2-2db7076e60a4,
request-id=74ee7e9e-8c75-309f-b9c2-2db7076e60a4,
X-FRAME-OPTIONS=SAMEORIGIN,
SPRequestDuration=460,
SPIisLatency=0,
MicrosoftSharePointTeamServices=16.0.0.4327,
X-AspNet-Version=4.0.30319,
X-Powered-By=ASP.NET

В консольном приложении, в случае если SharePointOnlineCredentials не сработал (значит мы работаем с on-premise SharePoint), то свойство Credentials заменяется на объект типа NetworkCredential:

// URL-адрес сайта SharePoint
var siteUrl = "https://sharepointsiteurl";
// Логин
var userLogin = "userLogin@domain";
// Пароль
var userPassword = "P@ssw0rd";

var pwd = new SecureString();
foreach (var c in userPassword) pwd.AppendChar(c);
var SPOCredentials = new SharePointOnlineCredentials(userLogin, pwd);
var SPCredentials = new NetworkCredential(userLogin, pwd);

using (var ctx = new ClientContext(siteUrl))
{
    try
    {
        // Пробуем использовать SharePoint Online Credentials
        ctx.Credentials = SPOCredentials;
        ctx.ExecuteQuery();
    }
    catch (ClientRequestException)
    {
        // переключаемся на  NetworkCredential
        ctx.Credentials = SPCredentials;
        ctx.ExecuteQuery();
    }
    catch (NotSupportedException)
    {
        // переключаемся на  NetworkCredential
        ctx.Credentials = SPCredentials;
        ctx.ExecuteQuery();
        Console.WriteLine("SharePoint On-premise");
    }

    // Код для работы с SharePoint
}

Теперь приложение будет работать как с on-premise SharePoint, так и с SharePoint Online (или Project Online).

Документ

Документ генерируется при исполнении приложения в памяти. Это простой текстовый файл:

var fileBytes = new byte[] { };

using (var ms = new MemoryStream())
{
    using (TextWriter tw = new StreamWriter(ms, Encoding.UTF8))
    {
        for (var i = 0; i < 100; i++)
        {
            tw.WriteLine(@"Съешь ещё этих мягких французских булок, да выпей чаю");
        }
        fileBytes = ms.ToArray();
    }
}

Загрузка документы

Для загрузки необходимо инициализировать объект типа FileCreationInformation:

// Информация о документе
var fileInformation = new FileCreationInformation
{
    // Относительный URL загружаемого файла
    Url = library.RootFolder.ServerRelativeUrl + "/fileName2.txt",
    // Перезаписываем файл, если он уже есть
    Overwrite = true,
    // Содержимое файла
    Content = fileBytes
};
// Добавляем файл в корневую папку библиотеки документов
library.RootFolder.Files.Add(fileInformation);

ctx.ExecuteQuery();

Это был первый способ и у него есть ограничение: максимальный размер файла 2 МБ. Если файл больше двух мегабайт, то получим исключение:

Microsoft.SharePoint.Client.ServerException: 'The request message is too big. The server does not allow messages larger than 2097152 bytes.'

Для этого есть второй способ загрузить документ.

Загрузка большого документа

Для больших файлов существует метод SaveBinaryDirect класса Microsoft.SharePoint.Client.File:

Microsoft.SharePoint.Client.File.SaveBinaryDirect(
    //Контекст
    ctx,
    // Относительный URL загружаемого файла
    library.RootFolder.ServerRelativeUrl + "/fileName2.txt",
    // Содержимое файла
    new MemoryStream(fileBytes),
    // Перезаписываем файл, если он уже есть
    true);
ctx.ExecuteQuery();

Даже если загружаемый документ слишком большой - есть выход в CSOM.

Загрузка документа по частям

Для загрузки файла по частям существует набор методов в классе Microsoft.SharePoint.Client.File:

  • StartUpload
  • ContinueUpload
  • FinishUpload
  • CancelUpload

Начинаем загрузку с помощью метода StartUpload, затем продолжаем загрузку с помощью метода ContinueUpload и завершаем загрузку вызовом метода FinishUpload. Если необходимо прервать загрузку - вызываем метод CancelUpload.

Сначала создаем пустой файл и только после этого начинаем загрузку его контента:

// Создаем пустой файл
var fileChunkedInformation = new FileCreationInformation
{
    // Относительный URL загружаемого файла
    Url = library.RootFolder.ServerRelativeUrl + "/fileName3.txt",
    // Перезаписываем файл, если он уже есть
    Overwrite = true,
    Content = new byte[] {}
};
// Добавляем файл в корневую папку библиотеки документов
var fileChunked = library.RootFolder.Files.Add(fileChunkedInformation);

ctx.ExecuteQuery();

// Идентификатор загрузки
var uploadId = Guid.NewGuid();

// Смещение в массиве содержимого файла
var fileBytesOffset = 0;

// Смещение в загружаемом файле
long fileChunkedOffset = 0;

// Размер загружаемой части
var fileChunkArrayBuffer = new byte[1024];

while (fileBytesOffset < fileBytes.Length)
{
    // Длина массива, который будет загружен
    var length = Math.Min(fileChunkArrayBuffer.Length, fileBytes.Length - fileBytesOffset);
                    
    // Копируем часть массива в буфер
    Buffer.BlockCopy(fileBytes, fileBytesOffset, fileChunkArrayBuffer, 0, length);

    // Буфер в Stream
    using (var ms = new MemoryStream(fileChunkArrayBuffer))
    {
        // Если смещение равно 0 - Начинаем загрузку
        if (fileChunkedOffset == 0)
        {
            var fileChunkedOffsetResult = fileChunked.StartUpload(uploadId, ms);
            ctx.ExecuteQuery();
            fileChunkedOffset = fileChunkedOffsetResult.Value;
        }
        // Продолжаем загрузку
        else if (fileBytesOffset + length <= fileBytes.Length)
        {
            var fileChunkedOffsetResult = fileChunked.ContinueUpload(uploadId, fileChunkedOffset, ms);
            ctx.ExecuteQuery();
            fileChunkedOffset = fileChunkedOffsetResult.Value;
        }
        // Последняя часть файла - завершаем загрузку
        else
        {
            fileChunked.FinishUpload(uploadId, fileChunkedOffset, ms);
            ctx.ExecuteQuery();
        }
    }

    fileBytesOffset += length;
}

И результат:

Загруженные файлы с помощью CSOM

Загруженные файлы с помощью CSOM

Исходные коды

Исходные коды доступны здесь: https://code.msdn.microsoft.com/Upload-document-to-32056dbf.

Complete basic operations using SharePoint client library code

Виталий Жуков

Виталий Жуков

SharePoint архитектор, разработчик, тренер, Microsoft MVP (Office Development). Более 15 лет опыта работы с SharePoint, Dynamics CRM, Office 365, и другими продуктами и сервисами Microsoft.

Смотрите также

Развертывание списков и библиотек с помощью SPFx-решений

Развертывание списков и библиотек с помощью SPFx-решений

SharePoint. Drag-and-Drop Загрузчик файлов

SharePoint. Drag-and-Drop Загрузчик файлов

SharePoint List REST API. Часть 2

SharePoint List REST API. Часть 2

SharePoint Framework. Создание веб-части на Angular

SharePoint Framework. Создание веб-части на Angular

SharePoint List REST API. Часть 1

SharePoint List REST API. Часть 1

Презентация с доклада о SharePoint Framework

Презентация с доклада о SharePoint Framework

SharePoint Framework. Создаем AngularJS 1.x Client WebPart

SharePoint Framework. Создаем AngularJS 1.x Client WebPart

SharePoint. Регистрация CSS и JavaScript с помощью DelegateControl

SharePoint. Регистрация CSS и JavaScript с помощью DelegateControl

SharePoint. Расширяем REST API

SharePoint. Расширяем REST API

SharePoint Excel Services. Создаем кредитный калькулятор

SharePoint Excel Services. Создаем кредитный калькулятор

SharePoint Ribbon API. Использование ToggleButton

SharePoint Ribbon API. Использование ToggleButton

SharePoint 2013. How To: настройка входящей почты для разработчиков

SharePoint 2013. How To: настройка входящей почты для разработчиков

Мифы и правда о Linq to SharePoint

Мифы и правда о Linq to SharePoint

5 особенностей SPSiteDataQuery

5 особенностей SPSiteDataQuery

SharePoint 2013. Введение в SharePoint App. Часть 2

SharePoint 2013. Введение в SharePoint App. Часть 2

SharePoint 2013. Введение в SharePoint App. Часть 1

SharePoint 2013. Введение в SharePoint App. Часть 1

Превью для веб-части в SharePoint 2010/2013

Превью для веб-части в SharePoint 2010/2013

SharePoint 2013. Еще немного о новых контролах

SharePoint 2013. Еще немного о новых контролах

SharePoint 2013. Контрол ClientPeoplePicker

SharePoint 2013. Контрол ClientPeoplePicker

SharePoint 2013. Контрол ImageCrop

SharePoint 2013. Контрол ImageCrop

SharePoint 2013. Тип поля Geolocation

SharePoint 2013. Тип поля Geolocation

Создание типа поля в SharePoint

Создание типа поля в SharePoint

SharePoint 2010. Длительные операции с обновляемым статусом

SharePoint 2010. Длительные операции с обновляемым статусом

Linq to SharePoint. Создаем ContentIterator

Linq to SharePoint. Создаем ContentIterator

Linq to SharePoint. Получение данных из другой коллекции сайтов

Linq to SharePoint. Получение данных из другой коллекции сайтов

Linq to SharePoint. Версионность

Linq to SharePoint. Версионность

SharePoint. Получение URL-адреса иконки для документа

SharePoint. Получение URL-адреса иконки для документа

SharePoint 2010. PostBack для Fluent Ribbon API

SharePoint 2010. PostBack для Fluent Ribbon API

Linq to SharePoint. Блокировка документов

Linq to SharePoint. Блокировка документов

Linq to SharePoint. Паттерн Repository

Linq to SharePoint. Паттерн Repository

Linq to SharePoint. Получение мета-данных списка

Linq to SharePoint. Получение мета-данных списка

Linq to SharePoint. Мапинг полей

Linq to SharePoint. Мапинг полей

Linq to SharePoint. Формирование данных для ProcessBatchData

Linq to SharePoint. Формирование данных для ProcessBatchData

Linq to SharePoint. Сравнение производительности с Camlex.NET

Linq to SharePoint. Сравнение производительности с Camlex.NET

Linq to SharePoint. Часть 5. Поля Choice и MultiChoice

Linq to SharePoint. Часть 5. Поля Choice и MultiChoice

Linq to SharePoint. Часть 4. Dynamic LINQ

Linq to SharePoint. Часть 4. Dynamic LINQ

Linq to SharePoint. Особенности. Часть 3

Linq to SharePoint. Особенности. Часть 3

Linq to SharePoint. Особенности. Часть 2

Linq to SharePoint. Особенности. Часть 2

SharePoint 2010. PeopleEditor. Установка значения

SharePoint 2010. PeopleEditor. Установка значения

SharePoint 2010. Настройка входящей почты для кастомного списка

SharePoint 2010. Настройка входящей почты для кастомного списка

Linq to Sharepoint. Особенности

Linq to Sharepoint. Особенности

EntityFramework. Оптимистические блокировки

EntityFramework. Оптимистические блокировки