Bagikan melalui


Keamanan properti dependensi (WPF .NET)

Aksesibilitas properti dependensi baca-tulis melalui sistem properti Windows Presentation Foundation (WPF) secara efektif menjadikannya properti publik. Akibatnya, tidak mungkin untuk membuat jaminan keamanan tentang nilai properti dependensi baca-tulis. Sistem properti WPF memberikan keamanan lebih untuk properti dependensi baca-saja sehingga Anda dapat membatasi akses tulis.

Penting

Dokumentasi Panduan Desktop untuk .NET 7 dan .NET 6 sedang dibangun.

Akses dan keamanan pembungkus properti

Pembungkus properti runtime bahasa umum (CLR) biasanya disertakan dalam implementasi properti dependensi baca-tulis untuk menyederhanakan mendapatkan atau mengatur nilai properti. Jika disertakan, pembungkus GetValue properti CLR adalah metode kenyamanan yang mengimplementasikan panggilan statis dan SetValue yang berinteraksi dengan properti dependensi yang mendasar. Pada dasarnya, pembungkus properti CLR mengekspos properti dependensi sebagai properti CLR yang didukung oleh properti dependensi daripada bidang privat.

Menerapkan mekanisme keamanan dan membatasi akses ke pembungkus properti CLR dapat mencegah penggunaan metode kenyamanan, tetapi teknik tersebut tidak akan mencegah panggilan langsung ke GetValue atau SetValue. Dengan kata lain, properti dependensi baca-tulis selalu dapat diakses melalui sistem properti WPF. Jika Anda menerapkan properti dependensi baca-tulis, hindari membatasi akses ke pembungkus properti CLR. Sebagai gantinya, nyatakan pembungkus properti CLR sebagai anggota publik sehingga penelepon mengetahui tingkat akses sebenarnya dari properti dependensi.

Paparan sistem properti properti properti dependensi

Sistem properti WPF menyediakan akses ke properti dependensi baca-tulis melalui pengidentifikasinya DependencyProperty . Pengidentifikasi dapat digunakan di GetValue dan SetValue memanggil. Bahkan jika bidang pengidentifikasi statis non-publik, beberapa aspek sistem properti akan mengembalikan DependencyProperty seperti yang ada pada instans kelas atau kelas turunan. Misalnya, metode mengembalikan GetLocalValueEnumerator pengidentifikasi untuk instans properti dependensi dengan nilai yang ditetapkan secara lokal. Selain itu OnPropertyChanged , Anda dapat mengambil alih metode virtual untuk menerima data peristiwa yang akan melaporkan DependencyProperty pengidentifikasi untuk properti dependensi yang telah mengubah nilai. Untuk membuat penelepon mengetahui tingkat akses sebenarnya dari properti dependensi baca-tulis, nyatakan bidang pengidentifikasinya sebagai anggota publik.

Catatan

Meskipun mendeklarasikan bidang pengidentifikasi properti dependensi sebagai private mengurangi jumlah cara properti dependensi baca-tulis dapat diakses, properti tidak akan bersifat pribadi sesuai dengan definisi bahasa CLR.

Keamanan validasi

Demand Menerapkan ke ValidateValueCallback dan mengharapkan validasi gagal pada Demand kegagalan, bukan mekanisme keamanan yang memadai untuk membatasi perubahan nilai properti. Selain itu, pembatalan nilai baru yang diberlakukan melalui ValidateValueCallback dapat ditekan oleh penelepon berbahaya, jika penelepon tersebut beroperasi dalam domain aplikasi.

Akses ke properti dependensi baca-saja

Untuk membatasi akses, daftarkan properti Anda sebagai properti dependensi baca-saja dengan memanggil RegisterReadOnly metode . Metode mengembalikan RegisterReadOnlyDependencyPropertyKey, yang dapat Anda tetapkan ke bidang kelas non-publik. Untuk properti dependensi baca-saja, sistem properti WPF hanya akan menyediakan akses tulis kepada mereka yang memiliki referensi ke DependencyPropertyKey. Untuk mengilustrasikan perilaku ini, kode pengujian berikut:

  • Membuat instans kelas yang mengimplementasikan properti dependensi baca-tulis dan baca-saja.
  • private Menetapkan pengubah akses ke setiap pengidentifikasi.
  • Hanya mengimplementasikan get aksesor.
  • Menggunakan metode untuk mengakses properti dependensi yang mendasar GetLocalValueEnumerator melalui sistem properti WPF.
  • GetValue Memanggil dan SetValue menguji akses ke setiap nilai properti dependensi.
    /// <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

Baca juga