Sécurité des propriétés de dépendance (WPF .NET)

L’accessibilité des propriétés de dépendance en lecture-écriture via le système de propriétés WPF (Windows Presentation Foundation) les rend ainsi publiques. Par conséquent, il n’est pas possible de garantir la sécurité des valeurs de propriété de dépendance en lecture-écriture. Le système de propriétés WPF offre davantage de sécurité pour les propriétés de dépendance en lecture seule afin que vous puissiez restreindre l’accès en écriture.

Important

La documentation du Guide du bureau pour .NET 7 et .NET 6 est en cours de construction.

Accès et sécurité des wrappers de propriétés

Un wrapper de propriétés CLR (Common Language Runtime) est généralement inclus dans les implémentations de propriétés de dépendance en lecture-écriture pour simplifier l’obtention ou la définition des valeurs de propriété. Si elle est incluse, le wrapper de propriété CLR est une méthode pratique qui implémente les GetValue appels statiques qui SetValue interagissent avec la propriété de dépendance sous-jacente. Essentiellement, un wrapper de propriété CLR expose une propriété de dépendance en tant que propriété CLR sauvegardée par une propriété de dépendance plutôt qu’un champ privé.

L’application de mécanismes de sécurité et la restriction de l’accès au wrapper de propriété CLR peuvent empêcher l’utilisation de la méthode pratique, mais ces techniques n’empêchent pas les appels directs vers GetValue ou SetValue. En d’autres termes, une propriété de dépendance en lecture-écriture est toujours accessible via le système de propriétés WPF. Si vous implémentez une propriété de dépendance en lecture-écriture, évitez de restreindre l’accès au wrapper de propriété CLR. Au lieu de cela, déclarez le wrapper de propriété CLR en tant que membre public afin que les appelants soient conscients du niveau d’accès réel de la propriété de dépendance.

Exposition du système de propriétés des propriétés de dépendance

Le système de propriétés WPF permet d’accéder à une propriété de dépendance en lecture-écriture via son DependencyProperty identificateur. L’identificateur est utilisable et GetValueSetValue appelle. Même si le champ d’identificateur statique n’est pas public, plusieurs aspects du système de propriétés retournent un DependencyProperty tel qu’il existe sur une instance d’une classe ou d’une classe dérivée. Par exemple, la GetLocalValueEnumerator méthode retourne des identificateurs pour les instances de propriété de dépendance avec une valeur définie localement. En outre, vous pouvez remplacer la OnPropertyChanged méthode virtuelle pour recevoir des données d’événement qui signalent l’identificateur DependencyProperty des propriétés de dépendance qui ont changé de valeur. Pour rendre les appelants conscients du niveau d’accès réel d’une propriété de dépendance en lecture-écriture, déclarez son champ d’identificateur en tant que membre public.

Remarque

Bien que la déclaration d’un champ private d’identificateur de propriété de dépendance réduit le nombre de façons dont une propriété de dépendance en lecture-écriture est accessible, la propriété ne sera pas privée en fonction de la définition du langage CLR.

Sécurité de la validation

Demand L’application d’une validation à une ValidateValueCallback validation attendue échoue en Demand cas d’échec, n’est pas un mécanisme de sécurité adéquat pour restreindre les modifications de valeur de propriété. De plus, une nouvelle invalidation de valeur appliquée ValidateValueCallback peut être supprimée par des appelants malveillants, si ces appelants fonctionnent dans le domaine d’application.

Accès aux propriétés de dépendance en lecture seule

Pour restreindre l’accès, inscrivez votre propriété en tant que propriété de dépendance en lecture seule en appelant la RegisterReadOnly méthode. La RegisterReadOnly méthode retourne un DependencyPropertyKey, que vous pouvez affecter à un champ de classe non public. Pour les propriétés de dépendance en lecture seule, le système de propriétés WPF fournit uniquement un accès en écriture à ceux qui ont une référence au DependencyPropertyKeyfichier . Pour illustrer ce comportement, le code de test suivant :

  • Instancie une classe qui implémente à la fois les propriétés de dépendance en lecture-écriture et en lecture seule.
  • Affecte un modificateur d’accès private à chaque identificateur.
  • Implémente uniquement les get accesseurs.
  • Utilise la GetLocalValueEnumerator méthode pour accéder aux propriétés de dépendance sous-jacentes via le système de propriétés WPF.
  • Appelle et SetValue teste GetValue l’accès à chaque valeur de propriété de dépendance.
    /// <summary>
    ///  Test get/set access to dependency properties exposed through the WPF property system.
    /// </summary>
    public static void DependencyPropertyAccessTests()
    {
        // Instantiate a class that implements read-write and read-only dependency properties.
        Aquarium _aquarium = new();
        // Access each dependency property using the LocalValueEnumerator method.
        LocalValueEnumerator localValueEnumerator = _aquarium.GetLocalValueEnumerator();
        while (localValueEnumerator.MoveNext())
        {
            DependencyProperty dp = localValueEnumerator.Current.Property;
            string dpType = dp.ReadOnly ? "read-only" : "read-write";
            // Test read access.
            Debug.WriteLine($"Attempting to get a {dpType} dependency property value...");
            Debug.WriteLine($"Value ({dpType}): {(int)_aquarium.GetValue(dp)}");
            // Test write access.
            try
            {
                Debug.WriteLine($"Attempting to set a {dpType} dependency property value to 2...");
                _aquarium.SetValue(dp, 2);
            }
            catch (InvalidOperationException e)
            {
                Debug.WriteLine(e.Message);
            }
            finally
            {
                Debug.WriteLine($"Value ({dpType}): {(int)_aquarium.GetValue(dp)}");
            }
        }

        // Test output:

        // Attempting to get a read-write dependency property value...
        // Value (read-write): 1
        // Attempting to set a read-write dependency property value to 2...
        // Value (read-write): 2

        // Attempting to get a read-only dependency property value...
        // Value (read-only): 1
        // Attempting to set a read-only dependency property value to 2...
        // 'FishCountReadOnly' property was registered as read-only
        // and cannot be modified without an authorization key.
        // Value (read-only): 1
    }
}

public class Aquarium : DependencyObject
{
    public Aquarium()
    {
        // Assign locally-set values.
        SetValue(FishCountProperty, 1);
        SetValue(FishCountReadOnlyPropertyKey, 1);
    }

    // Failed attempt to restrict write-access by assigning the
    // DependencyProperty identifier to a non-public field.
    private static readonly DependencyProperty FishCountProperty =
        DependencyProperty.Register(
          name: "FishCount",
          propertyType: typeof(int),
          ownerType: typeof(Aquarium),
          typeMetadata: new PropertyMetadata());

    // Successful attempt to restrict write-access by assigning the
    // DependencyPropertyKey to a non-public field.
    private static readonly DependencyPropertyKey FishCountReadOnlyPropertyKey =
        DependencyProperty.RegisterReadOnly(
          name: "FishCountReadOnly",
          propertyType: typeof(int),
          ownerType: typeof(Aquarium),
          typeMetadata: new PropertyMetadata());

    // Declare public get accessors.
    public int FishCount => (int)GetValue(FishCountProperty);
    public int FishCountReadOnly => (int)GetValue(FishCountReadOnlyPropertyKey.DependencyProperty);
}
    ''' <summary>
    ''' ' Test get/set access to dependency properties exposed through the WPF property system.
    ''' </summary>
    Public Shared Sub DependencyPropertyAccessTests()
        ' Instantiate a class that implements read-write and read-only dependency properties.
        Dim _aquarium As New Aquarium()
        ' Access each dependency property using the LocalValueEnumerator method.
        Dim localValueEnumerator As LocalValueEnumerator = _aquarium.GetLocalValueEnumerator()
        While localValueEnumerator.MoveNext()
            Dim dp As DependencyProperty = localValueEnumerator.Current.[Property]
            Dim dpType As String = If(dp.[ReadOnly], "read-only", "read-write")
            ' Test read access.
            Debug.WriteLine($"Attempting to get a {dpType} dependency property value...")
            Debug.WriteLine($"Value ({dpType}): {CInt(_aquarium.GetValue(dp))}")
            ' Test write access.
            Try
                Debug.WriteLine($"Attempting to set a {dpType} dependency property value to 2...")
                _aquarium.SetValue(dp, 2)
            Catch e As InvalidOperationException
                Debug.WriteLine(e.Message)
            Finally
                Debug.WriteLine($"Value ({dpType}): {CInt(_aquarium.GetValue(dp))}")
            End Try
        End While

        ' Test output

        ' Attempting to get a read-write dependency property value...
        ' Value (read-write): 1
        ' Attempting to set a read-write dependency property value to 2...
        ' Value (read-write): 2

        ' Attempting to get a read-only dependency property value...
        ' Value (read-only): 1
        ' Attempting to set a read-only dependency property value to 2...
        ' 'FishCountReadOnly' property was registered as read-only
        ' and cannot be modified without an authorization key.
        ' Value (read-only): 1
    End Sub

End Class

Public Class Aquarium
    Inherits DependencyObject

    Public Sub New()
        ' Assign locally-set values.
        SetValue(FishCountProperty, 1)
        SetValue(FishCountReadOnlyPropertyKey, 1)
    End Sub

    ' Failed attempt to restrict write-access by assigning the
    ' DependencyProperty identifier to a non-public field.
    Private Shared ReadOnly FishCountProperty As DependencyProperty =
        DependencyProperty.Register(
            name:="FishCount",
            propertyType:=GetType(Integer),
            ownerType:=GetType(Aquarium),
            typeMetadata:=New PropertyMetadata())

    ' Successful attempt to restrict write-access by assigning the
    ' DependencyPropertyKey to a non-public field.
    Private Shared ReadOnly FishCountReadOnlyPropertyKey As DependencyPropertyKey =
        DependencyProperty.RegisterReadOnly(
            name:="FishCountReadOnly",
            propertyType:=GetType(Integer),
            ownerType:=GetType(Aquarium),
            typeMetadata:=New PropertyMetadata())

    ' Declare public get accessors.
    Public ReadOnly Property FishCount As Integer
        Get
            Return GetValue(FishCountProperty)
        End Get
    End Property

    Public ReadOnly Property FishCountReadOnly As Integer
        Get
            Return GetValue(FishCountReadOnlyPropertyKey.DependencyProperty)
        End Get
    End Property

End Class

Voir aussi