Definieren einer Sperrrichtlinie zum Erstellen von schreibgeschützten Segmenten

Die Unveränderlichkeits-API des Visual Studio Visualization and Modeling SDK ermöglicht es einem Programm, einen Teil oder das gesamte DSL-Modell (Domain-Specific Language) zu sperren, sodass es gelesen, aber nicht geändert werden kann. Diese schreibgeschützte Option kann z. B. verwendet werden, damit ein Benutzer Kollegen auffordern kann, ein DSL-Modell zu kommentieren und zu überprüfen, es ihnen jedoch nicht dürfen, das Original zu ändern.

Darüber hinaus können Sie als Ersteller einer DSL eine Sperrrichtlinie definieren. Eine Sperrrichtlinie definiert, welche Sperren zulässig, nicht zulässig oder obligatorisch sind. Wenn Sie z. B. eine DSL veröffentlichen, können Sie Entwickler von Drittanbietern dazu auffordern, sie mit neuen Befehlen zu erweitern. Sie können jedoch auch eine Sperrrichtlinie verwenden, um zu verhindern, dass sie den schreibgeschützten Status der angegebenen Teile des Modells ändern.

Hinweis

Eine Sperrrichtlinie kann mithilfe von Reflektion umgangen werden. Sie bietet eine klare Grenze für Drittanbieterentwickler, bietet aber keine starke Sicherheit.

Weitere Informationen und Beispiele finden Sie auf der website Visual Studio Visualization and Modeling SDK.

Hinweis

Die Komponente Textvorlagentransformation wird automatisch als Teil der Workload Visual Studio-Erweiterungsentwicklung installiert. Sie können die Installation auch über die Registerkarte Einzelne Komponenten des Visual Studio-Installers unter der Kategorie SDKs, Bibliotheken und Frameworks durchführen. Installieren Sie die Komponente Modellierungs-SDK auf der Registerkarte Einzelne Komponenten.

Festlegen und Abrufen von Sperren

Sie können Sperren für den Speicher, für eine Partition oder für ein einzelnes Element festlegen. Diese Anweisung verhindert beispielsweise, dass ein Modellelement gelöscht wird, und verhindert auch, dass seine Eigenschaften geändert werden:

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

Andere Sperrwerte können verwendet werden, um Änderungen an Beziehungen, der Elementerstellung, der Verschiebung zwischen Partitionen und der Neureihenfolge von Links in einer Rolle zu verhindern.

Die Sperren gelten sowohl für Benutzeraktionen als auch für Programmcode. Wenn Programmcode versucht, eine Änderung vorzunehmen, InvalidOperationException wird eine ausgelöst. Sperren werden bei einem Rückgängig- oder Wiederholungsvorgang ignoriert.

Sie können ermitteln, ob ein Element über eine Sperre in einem bestimmten Satz verfügt, indem IsLocked(Locks) Sie verwenden, und Sie können den aktuellen Satz von Sperren für ein Element mithilfe von GetLocks() abrufen.

Sie können eine Sperre festlegen, ohne eine Transaktion zu verwenden. Die Sperrendatenbank ist nicht Teil des Speichers. Wenn Sie eine Sperre als Reaktion auf eine Änderung eines Werts im Speicher festlegen, z. B. in OnValueChanged, sollten Sie Änderungen zulassen, die Teil eines Rückgängig-Vorgangs sind.

Diese Methoden sind Erweiterungsmethoden, die im -Namespace definiert Microsoft.VisualStudio.Modeling.Immutability sind.

Sperren für Partitionen und Speicher

Sperren können auch auf Partitionen und den Speicher angewendet werden. Eine Sperre, die für eine Partition festgelegt ist, gilt für alle Elemente in der Partition. Daher verhindert beispielsweise die folgende Anweisung, dass alle Elemente in einer Partition gelöscht werden, unabhängig von den Zuständen ihrer eigenen Sperren. Trotzdem können andere Sperren wie Locks.Property für einzelne Elemente weiterhin festgelegt werden:

partition.SetLocks(Locks.Delete);

Eine Sperre, die für den Store festgelegt ist, gilt für alle elemente, unabhängig von den Einstellungen dieser Sperre für die Partitionen und die Elemente.

Verwenden von Sperren

Sie können Sperren verwenden, um Schemas wie die folgenden zu implementieren:

  • Lassen Sie keine Änderungen an allen Elementen und Beziehungen zu, mit Ausnahme derjenigen, die Kommentare darstellen. Dadurch können Benutzer ein Modell kommentieren, ohne es zu ändern.

  • Lassen Sie Änderungen an der Standardpartition nicht zu, lassen Sie jedoch Änderungen in der Diagrammpartition zu. Der Benutzer kann das Diagramm neu anordnen, aber das zugrunde liegende Modell nicht ändern.

  • Lassen Sie Keine Änderungen am Store zu, mit Ausnahme einer Gruppe von Benutzern, die in einer separaten Datenbank registriert sind. Für andere Benutzer sind das Diagramm und das Modell schreibgeschützt.

  • Lassen Sie Änderungen am Modell nicht zu, wenn eine boolesche Eigenschaft des Diagramms auf TRUE festgelegt ist. Geben Sie einen Menübefehl an, um diese Eigenschaft zu ändern. Dadurch wird sichergestellt, dass Benutzer keine versehentlichen Änderungen vornehmen.

  • Lässt das Hinzufügen und Löschen von Elementen und Beziehungen bestimmter Klassen nicht zu, lässt jedoch Eigenschaftenänderungen zu. Dadurch erhalten Benutzer ein festes Formular, in dem sie die Eigenschaften ausfüllen können.

Sperren von Werten

Sperren können für ein Store, eine Partition oder ein einzelnes ModelElement festgelegt werden. Sperren ist eine Flags Enumeration: Sie können ihre Werte mithilfe von "|" kombinieren.

  • Sperren eines ModelElement enthalten immer die Sperren seiner Partition.

  • Sperren einer Partition enthalten immer die Sperren der Store.

    Sie können keine Sperre für eine Partition oder einen Speicher festlegen und gleichzeitig die Sperre für ein einzelnes Element deaktivieren.

Wert Bedeutung, wenn IsLocked(Value) "true" ist
Keine Keine Einschränkung.
Eigenschaft Domäneneigenschaften von Elementen können nicht geändert werden. Dies gilt nicht für Eigenschaften, die von der Rolle einer Domänenklasse in einer Beziehung generiert werden.
Add Neue Elemente und Links können nicht in einer Partition oder einem Speicher erstellt werden.

Gilt nicht für ModelElement .
Move Das Element kann nicht zwischen Partitionen verschoben werden, wenn element.IsLocked(Move) true oder true targetPartition.IsLocked(Move) ist.
Löschen Ein Element kann nicht gelöscht werden, wenn diese Sperre für das Element selbst oder für eines der Elemente festgelegt ist, an die der Löschvorgang erfolgen würde, z. B. eingebettete Elemente und Formen.

Mit können Sie element.CanDelete() ermitteln, ob ein Element gelöscht werden kann.
Neu anordnen Die Reihenfolge der Links in einem Roleplayer kann nicht geändert werden.
RolePlayer Der Satz von Links, die in diesem Element stammen, kann nicht geändert werden. Beispielsweise können neue Elemente nicht unter dieses Element eingebettet werden. Dies wirkt sich nicht auf Links aus, für die dieses Element das Ziel ist.

Wenn es sich bei diesem Element um einen Link handelt, sind Quelle und Ziel nicht betroffen.
Alle Bitweises OR der anderen Werte.

Sperrrichtlinien

Als Ersteller einer DSL können Sie eine Sperrrichtlinie definieren. Eine Sperrrichtlinie moderiert den Vorgang von SetLocks(), sodass Sie verhindern können, dass bestimmte Sperren festgelegt werden, oder festlegen, dass bestimmte Sperren festgelegt werden müssen. In der Regel würden Sie eine Sperrrichtlinie verwenden, um Benutzer oder Entwickler davon abzuhalten, versehentlich gegen die beabsichtigte Verwendung einer DSL zu verstoßen, und zwar auf die gleiche Weise, wie Sie eine Variable deklarieren private können.

Sie können auch eine Sperrrichtlinie verwenden, um Sperren für alle Elemente festzulegen, die vom Typ des Elements abhängen. Dies liegt daran, dass SetLocks(Locks.None) immer aufgerufen wird, wenn ein Element zum ersten Mal erstellt oder aus einer Datei deserialisiert wird.

Sie können jedoch keine Richtlinie verwenden, um die Sperren für ein Element während seiner Lebensdauer zu ändern. Um diesen Effekt zu erzielen, sollten Sie Aufrufe von SetLocks() verwenden.

Um eine Sperrrichtlinie zu definieren, müssen Sie Folgendes unternehmen:

  • Erstellen Sie eine Klasse, die das ILockingPolicy implementiert.

  • Fügen Sie diese Klasse den Diensten hinzu, die über docData Ihrer DSL verfügbar sind.

So definieren Sie eine Sperrrichtlinie

ILockingPolicy weist die folgende Definition auf:

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

Diese Methoden werden aufgerufen, wenn ein Aufruf von SetLocks() auf einem Store, Partition oder ModelElement erfolgt. In jeder Methode erhalten Sie einen vorgeschlagenen Satz von Sperren. Sie können den vorgeschlagenen Satz zurückgeben oder Sperren hinzufügen und subtrahieren.

Beispiel:

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;
    }

So stellen Sie sicher, dass Benutzer elemente immer löschen können, auch wenn anderer Code aufruft SetLocks(Lock.Delete):

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

So lassen Sie keine Änderungen in allen Eigenschaften jedes Elements von MyClass zu:

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

So stellen Sie Ihre Richtlinie als Dienst zur Verfügung

Fügen Sie in Ihrem DslPackage Projekt eine neue Datei hinzu, die Code enthält, der dem folgenden Beispiel ähnelt:

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);
    }
}