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 - файл не заблокирован;

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

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

  1. /// <summary>
  2. /// Получение файла элемента
  3. /// </summary>
  4. /// <param name="id">Id элемента</param>
  5. /// <returns>Файл</returns>
  6. protected SPFile GetFile(int id)
  7. {
  8.     // Получаем элемент
  9.     var entity = GetEntity(id);
  10.     // Получаем список, содержащий элемент
  11.     var list = MetaData.List;
  12.     // Получаем сайт, содержащий список
  13.     var web = list.ParentWeb;
  14.     // Получаем файл
  15.     var file = web.GetFile(entity.ServerUrl);
  16.     return file;
  17. }

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

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

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

  1. /// <summary>
  2. /// Блокировка элемента
  3. /// </summary>
  4. /// <param name="id">Id элемента</param>
  5. /// <param name="lockType">Тип блокировка</param>
  6. /// <param name="timeSpan">Тайм-аут</param>
  7. public void LockEntity(int id, SPFile.SPLockType lockType, TimeSpan timeSpan)
  8. {
  9.     var file = GetFile(id);
  10.     if (file.ListItemAllFields.ParentList is SPDocumentLibrary)
  11.     {
  12.         if (file.LockType == SPFile.SPLockType.None)
  13.         {
  14.             file.Lock(lockType, Guid.NewGuid().ToString("N"), timeSpan);
  15.         }
  16.     }
  17. }
  18.  
  19. /// <summary>
  20. /// Снятие блокировки
  21. /// </summary>
  22. /// <param name="id">Id элемента</param>
  23. public void ReleaseLockEntity(int id)
  24. {
  25.     var file = GetFile(id);
  26.     if (file.LockType != SPFile.SPLockType.None)
  27.     {
  28.         file.ReleaseLock(file.LockId);
  29.     }
  30. }
  31.  
  32. /// <summary>
  33. /// Продление блокировки
  34. /// </summary>
  35. /// <param name="id">Id элемента</param>
  36. /// <param name="timeSpan">Тайм-аут</param>
  37. public void RefreshLockEntity(int id, TimeSpan timeSpan)
  38. {
  39.     string lockId;
  40.     var file = GetFile(id);
  41.     if (file.LockType != SPFile.SPLockType.None)
  42.     {
  43.         file.RefreshLock(file.LockId, timeSpan);
  44.     }
  45. }

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

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

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

  1. public class EntityLockInfo
  2. {
  3.     public SPFile.SPLockType LockType { getset; }
  4.     public string LockId { getset; }
  5.     public DateTime LockExpires { getset; }
  6.     public DateTime LockedDate { getset; }
  7.     public SPUser LockedByUser { getset; }
  8.  
  9.     public EntityLockInfo(SPFile file)
  10.     {
  11.         LockType = file.LockType;
  12.         LockId = file.LockId;
  13.         LockExpires = file.LockExpires;
  14.         LockedByUser = file.LockedByUser;
  15.         LockedDate = file.LockedDate;
  16.     }
  17. }

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

  1. /// <summary>
  2. /// Получение информации о блокировке элемента
  3. /// </summary>
  4. /// <param name="id">Id элемента</param>
  5. public EntityLockInfo GetLockInfo(int id)
  6. {
  7.     var file = GetFile(id);
  8.     var info = new EntityLockInfo(file);
  9.     return info;
  10. }

Применение

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

  1. var repository = new DocumentRepository(siteUrl, false);
  2. repository.LockEntity(1, SPFile.SPLockType.Exclusive, TimeSpan.FromHours(10));

Поделиться

Коментарии