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

Иногда при работе с документами необходимо на некоторое время запретить другим пользователями его изменение. В Microsoft SharePoint 2010 для реализации данного требования есть две возможности: извлечение файла и блокировка файла. В этом посте я расскажу об отличиях этих двух операций и покажу пример реализации блокировки документов с использованием репозитория.

Извлечение файлов

Первый способ, извлечение файлов, доступен из интерфейса пользователя. Это стандартная реализация системы управления версиями. Есть один недостаток: пользователи с достаточными на то привилегиями могут отменить извлечение документа или вернуть его. SharePoint в таком случае просто выдаст предупреждение о том, что файл был извлечен другим пользователем:

Такое поведение SharePoint'а оправдано, тем, что пользователь, извлекший документ может, например, уйти в отпуск. И тогда администратор может отменить извлечение документа, предоставив тем самым возможность работать с документов другим пользователям. Такой подход не подходит для обеспечения монопольного доступа к файлу.

Блокировка документов

Второй способ более радикален и позволяет обеспечить монопольный доступ к файлу. Но здесь есть несколько особенностей:

  • Заблокировать файл, используя интерфейс пользователя нельзя;
  • Блокировать файл можно только на определенное время. Это связано с тем, что блокировку может отменить только пользователь, наложивший её;
  • При попытке редактировать свойства заблокированного файл, возникает исключение, которое не обрабатывается SharePoint'ом в дружелюбном виде.

Исключение это выглядит следующим образом:

<nativehr>0x80071779</nativehr><nativestack></nativestack>  
Файл "http://[SPServer]/DocumentLibrary/Report.xlsx" заблокирован для монопольного использования пользователем SHAREPOINT\system.

Или так (по-английски):

<nativehr>0x80071779</nativehr><nativestack></nativestack>
The file "http://[SPServer]/DocumentLibrary/Report.xlsx" is locked for exclusive use by SHAREPOINT\system.

При открытии файла в клиентском приложении SharePoint выдаст вот такое сообщение:

Блокировка файла программными средствами

Так как блокировать документы в SharePoint'е можно только программно, я покажу как это сделать на примере репозитория, описанного в посте Linq to SharePoint. Паттерн Repository

Блокировка в объектной модели SharePoint

В объектной модели SharePoint блокировка реализована в классе SPFile и представлена следующими методами:

  • Lock(SPLockType lockType, string lockId, TimeSpan timeout) - блокирование файла на заданный период времени;
  • ** RefreshLock(string lockId, TimeSpan timeout)** - продление блокировки файла на заданный период времени;
  • ReleaseLock(string lockId) - снятие блокировки с файла;

Информация о блокировке файла содержится в следующих свойствах объекта SPFile:

  • LockedByUser - пользователь, заблокировавший файл;
  • LockedDate - дата блокировки файла;
  • LockExpires - время, на которое заблокирован файл;
  • LockId - Id блокировки;
  • LockType - тип блокировки.;

Тип блокировки может принимать следующие значения:

  • Exclusive - доступ к файлу имеет только пользователь, наложивший на него блокировку;
  • Shared - доступ к файлу имеет группа пользователей;
  • None - файл не заблокирован;

Получение файла

Прежде чем блокировать файл, необходимо его получить. Для этого в репозиторий я добавил следующий метод:

/// <summary>
/// Получение файла элемента
/// </summary>
/// <param name="id">Id элемента</param>
/// <returns>Файл</returns>
protected SPFile GetFile(int id)
{
    // Получаем элемент
    var entity = GetEntity(id);
    // Получаем список, содержащий элемент
    var list = MetaData.List;
    // Получаем сайт, содержащий список
    var web = list.ParentWeb;
    // Получаем файл
    var file = web.GetFile(entity.ServerUrl);
    return file;
}

Этот метод использует мета-данные списка, способ получение которых я описал в посте Linq to SharePoint. Получение мета-данных списка. В SharePoint'е и для элемента списка можно получить файл, но заблокировать его не удастся, т.к. он не является файлом, подлежащим хранению в системе управления версиями.

Блокировка файла

Файл есть, теперь можно и блокировку реализовать:

/// <summary>
/// Блокировка элемента
/// </summary>
/// <param name="id">Id элемента</param>
/// <param name="lockType">Тип блокировка</param>
/// <param name="timeSpan">Тайм-аут</param>
public void LockEntity(int id, SPFile.SPLockType lockType, TimeSpan timeSpan)
{
    var file = GetFile(id);
    if (file.ListItemAllFields.ParentList is SPDocumentLibrary)
    {
        if (file.LockType == SPFile.SPLockType.None)
        {
            file.Lock(lockType, Guid.NewGuid().ToString("N"), timeSpan);
        }
    }
}
 
/// <summary>
/// Снятие блокировки
/// </summary>
/// <param name="id">Id элемента</param>
public void ReleaseLockEntity(int id)
{
    var file = GetFile(id);
    if (file.LockType != SPFile.SPLockType.None)
    {
        file.ReleaseLock(file.LockId);
    }
}
 
/// <summary>
/// Продление блокировки
/// </summary>
/// <param name="id">Id элемента</param>
/// <param name="timeSpan">Тайм-аут</param>
public void RefreshLockEntity(int id, TimeSpan timeSpan)
{
    string lockId;
    var file = GetFile(id);
    if (file.LockType != SPFile.SPLockType.None)
    {
        file.RefreshLock(file.LockId, timeSpan);
    }
}

В объектной модели SharePoint при блокировки файла или её продления требуется указать Id этой блокировки. В реализации этих методов в репозитории я "опустил" это требование.

Информация о блокировке

Для получения информации о блокировке файла я сделал простой класс:

public class EntityLockInfo
{
    public SPFile.SPLockType LockType { get; set; }
    public string LockId { get; set; }
    public DateTime LockExpires { get; set; }
    public DateTime LockedDate { get; set; }
    public SPUser LockedByUser { get; set; }
 
    public EntityLockInfo(SPFile file)
    {
        LockType = file.LockType;
        LockId = file.LockId;
        LockExpires = file.LockExpires;
        LockedByUser = file.LockedByUser;
        LockedDate = file.LockedDate;
    }
}

И метод в репозитории для получения его экземпляра:

/// <summary>
/// Получение информации о блокировке элемента
/// </summary>
/// <param name="id">Id элемента</param>
public EntityLockInfo GetLockInfo(int id)
{
    var file = GetFile(id);
    var info = new EntityLockInfo(file);
    return info;
}

Применение

Использовать новый функционал можно примерно так:

var repository = new DocumentRepository(siteUrl, false);
repository.LockEntity(1, SPFile.SPLockType.Exclusive, TimeSpan.FromHours(10));
Виталий Жуков

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

Техлид, Архитектор, Разработчик, Microsoft MVP. Более 20 лет опыта в области системной интеграции и разработки программного обеспечения. Специализируюсь на проектировании и внедрении масштабируемых высокопроизводительных программных решений в различных отраслях.

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

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

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

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

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

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

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

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. Паттерн 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. Оптимистические блокировки