Поделиться через


Определение политики блокировки для создания сегментов только для чтения

API неизменяемости пакета SDK для визуализации и моделирования Visual Studio позволяет программе блокировать часть или всю модель языка dsL, чтобы ее можно было прочитать, но не изменить. Этот параметр можно использовать только для чтения, например, чтобы пользователь мог попросить коллег анимировать и просматривать модель DSL, но может запретить им изменять исходный формат.

Кроме того, как автор DSL, можно определить политику блокировки. Политика блокировки определяет, какие блокировки разрешены, не разрешены или обязательны. Например, при публикации DSL можно поощрять сторонних разработчиков расширить его с помощью новых команд. Но можно также использовать политику блокировки, чтобы предотвратить изменение состояния только для чтения указанных частей модели.

Примечание.

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

Дополнительные сведения и примеры доступны в пакете SDK для визуализации и моделирования Visual Studio.

Примечание.

Компонент Text Template Transformation (Преобразование текстовых шаблонов) автоматически устанавливается как часть рабочей нагрузки разработки расширений Visual Studio. Его также можно установить на вкладке Отдельные компоненты Visual Studio Installer в категории Пакеты SDK, библиотеки и платформы. Установите компонент Пакет SDK для моделирования со вкладки Отдельные компоненты.

Настройка и получение блокировок

Вы можете задать блокировки в магазине, секции или отдельном элементе. Например, эта инструкция предотвращает удаление элемента модели, а также предотвращает изменение его свойств:

using Microsoft.VisualStudio.Modeling.Immutability; ...
element.SetLocks(Locks.Delete | Locks.Property);

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

Блокировки применяются как к действиям пользователя, так и к коду программы. Если код программы пытается внести изменения, InvalidOperationException создается исключение. Блокировки игнорируются в операции отмены или повторного выполнения.

Вы можете узнать, имеет ли элемент блокировку в заданном наборе, используя текущий IsLocked(Locks) набор блокировок для элемента.GetLocks()

Блокировку можно задать без использования транзакции. База данных блокировки не является частью хранилища. Если вы устанавливаете блокировку в ответ на изменение значения в хранилище, например OnValueChanged, следует разрешить изменения, которые являются частью операции отмены.

Эти методы являются методами расширения, определенными Microsoft.VisualStudio.Modeling.Immutability в пространстве имен.

Блокировки секций и хранилищ

Блокировки также можно применять к секциям и хранилищу. Блокировка, заданная в секции, применяется ко всем элементам в секции. Поэтому, например, следующая инструкция предотвращает удаление всех элементов в секции независимо от состояний собственных блокировок. Тем не менее, другие блокировки, такие как Locks.Property могут быть установлены на отдельных элементах:

partition.SetLocks(Locks.Delete);

Блокировка, установленная в магазине, применяется ко всем его элементам независимо от параметров этой блокировки секций и элементов.

Использование блокировок

Вы можете использовать блокировки для реализации схем, таких как следующие примеры:

  • Запретить изменения всех элементов и связей, кроме тех, которые представляют комментарии. Такой подход позволяет пользователям добавлять заметки в модель, не изменяя ее.

  • Запретить изменения в секции по умолчанию, но разрешить изменения в разделе схемы. Пользователь может изменить порядок схемы, но не может изменить базовую модель.

  • Запретить изменения в хранилище, за исключением группы пользователей, зарегистрированных в отдельной базе данных. Для других пользователей схема и модель доступны только для чтения.

  • Запретить изменение модели, если логическое свойство схемы имеет значение true. Предоставьте команду меню для изменения этого свойства. Этот подход помогает гарантировать, что пользователи не вносят изменения случайно.

  • Запретить добавление и удаление элементов и связей определенных классов, но разрешать изменения свойств. Этот подход предоставляет пользователям фиксированную форму, в которой они могут заполнить свойства.

Значения блокировки

Блокировки можно задать в хранилище, секции или отдельных ModelElement. Блокировки — это Flags перечисление: можно объединить значения с помощью "|".

  • Блокировки ModelElement всегда включают блокировки своей секции.

  • Блокировки секции всегда включают блокировки хранилища.

    Вы не можете задать блокировку для секции или хранилища и одновременно отключить блокировку для отдельного элемента.

Значение Значение, если IsLocked(Value) имеет значение true
нет Нет ограничений.
Свойство Не удается изменить свойства домена элементов. Это значение не применяется к свойствам, созданным ролью класса домена в связи.
Добавить Новые элементы и ссылки не могут быть созданы в разделе или хранилище. Неприменимо к ModelElement.
Передвинуть Элемент не может быть перемещен между секциями, если element.IsLocked(Move) имеет значение true или targetPartition.IsLocked(Move) имеет значение true.
DELETE Невозможно удалить элемент, если эта блокировка задана в самом элементе или на любом из элементов, к которым будет распространяться удаление, например внедренные элементы и фигуры. Можно использовать element.CanDelete() для обнаружения возможности удаления элемента.
Переупорядочить Порядок ссылок в проигрывателе ролей не может быть изменен.
RolePlayer Не удается изменить набор ссылок, исходных в этом элементе. Например, новые элементы не могут быть внедрены в этот элемент. Это значение не влияет на ссылки, для которых этот элемент является целевым. Если этот элемент является ссылкой, его источник и целевой объект не затрагиваются.
Все Битовое ИЛИ других значений.

Политики блокировки

Как автор DSL, вы можете определить политику блокировки. Политика блокировки модерирует операцию SetLocks(), чтобы можно было предотвратить настройку определенных блокировок или запретить настройку определенных блокировок. Как правило, вы будете использовать политику блокировки, чтобы запретить пользователям или разработчикам случайно препятствовать случайному использованию DSL таким же образом, как можно объявить переменную private.

Можно также использовать политику блокировки для задания блокировок для всех элементов, зависящих от типа элемента. Это происходит потому, что SetLocks(Locks.None) всегда вызывается при первом создании или десериализации элемента из файла.

Однако политику нельзя использовать для изменения блокировок элемента во время его существования. Чтобы добиться этого эффекта, следует использовать вызовы SetLocks().

Чтобы определить политику блокировки, выполните следующие действия.

  • Создайте класс, реализующий перехватчик ILockingPolicy.

  • Добавьте этот класс в службы, доступные через DocData dsL.

Определение политики блокировки

ILockingPolicy имеет следующее определение:

public interface ILockingPolicy
{
  Locks RefineLocks(ModelElement element, Locks proposedLocks);
  Locks RefineLocks(Partition partition, Locks proposedLocks);
  Locks RefineLocks(Store store, Locks proposedLocks);
}

Эти методы вызываются при вызове SetLocks() в хранилище, секции или ModelElement. В каждом методе вы предоставляете предлагаемый набор блокировок. Вы можете вернуть предлагаемый набор или добавить и вычитать блокировки.

Например:

using Microsoft.VisualStudio.Modeling;
using Microsoft.VisualStudio.Modeling.Immutability;
namespace Company.YourDsl.DslPackage // Change
{
  public class MyLockingPolicy : ILockingPolicy
  {
    /// <summary>
    /// Moderate SetLocks(this ModelElement target, Locks locks)
    /// </summary>
    /// <param name="element">target</param>
    /// <param name="proposedLocks">locks</param>
    /// <returns></returns>
    public Locks RefineLocks(ModelElement element, Locks proposedLocks)
    {
      // In my policy, users can never delete an element,
      // and other developers cannot easily change that:
      return proposedLocks | Locks.Delete);
    }
    public Locks RefineLocks(Store store, Locks proposedLocks)
    {
      // Only one user can change this model:
      return Environment.UserName == "aUser"
           ? proposedLocks : Locks.All;
    }

Чтобы убедиться, что пользователи всегда могут удалять элементы, даже если другие вызовы кода SetLocks(Lock.Delete):

return proposedLocks & (Locks.All ^ Locks.Delete);

Чтобы запретить изменение всех свойств каждого элемента MyClass:

return element is MyClass ? (proposedLocks | Locks.Property) : proposedLocks;

Чтобы сделать политику доступной как услуга

DslPackage В проекте добавьте новый файл, содержащий код, похожий на следующий пример:

using Microsoft.VisualStudio.Modeling;
using Microsoft.VisualStudio.Modeling.Immutability;
namespace Company.YourDsl.DslPackage // Change
{
  // Override the DocData GetService() for this DSL.
  internal partial class YourDslDocData // Change
  {
    /// <summary>
    /// Custom locking policy cache.
    /// </summary>
    private ILockingPolicy myLockingPolicy = null;

    /// <summary>
    /// Called when a service is requested.
    /// </summary>
    /// <param name="serviceType">Service requested</param>
    /// <returns>Service implementation</returns>
    public override object GetService(System.Type serviceType)
    {
      if (serviceType == typeof(SLockingPolicy)
       || serviceType == typeof(ILockingPolicy))
      {
        if (myLockingPolicy == null)
        {
          myLockingPolicy = new MyLockingPolicy();
        }
        return myLockingPolicy;
      }
      // Request is for some other service.
      return base.GetService(serviceType);
    }
}