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

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

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

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

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

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

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

После того как приложение создано необходимо добавить ссылки на сборки для работы с 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:

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

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

Используйте класс 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 '{SharePointSiteUrl}' 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;
}

И результат:

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

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

Ссылки

Complete basic operations using SharePoint client library code


Поделиться

Коментарии