Beveiliging van afhankelijkheidseigenschappen (WPF .NET)
De toegankelijkheid van eigenschappen van lees-/schrijfafhankelijkheid via het WPF-eigenschappensysteem (Windows Presentation Foundation) maakt ze effectief openbare eigenschappen. Als gevolg hiervan is het niet mogelijk om beveiligingsgaranties te maken over eigenschapswaarden voor lezen/schrijven. Het WPF-eigenschappensysteem biedt meer beveiliging voor alleen-lezen afhankelijkheidseigenschappen, zodat u de schrijftoegang kunt beperken.
Toegang tot en beveiliging van property wrappers
Een common Language Runtime -eigenschapswikkelaar (CLR) is meestal opgenomen in implementaties van afhankelijkheidseigenschappen voor lezen/schrijven om het ophalen of instellen van eigenschapswaarden te vereenvoudigen. Indien opgenomen, is de CLR-eigenschap wrapper een gemakkelijke methode die de statische aanroepen GetValue en SetValue implementeert, welke communiceren met de onderliggende afhankelijkheidseigenschap. In wezen maakt een CLR-eigenschap-wrapper een afhankelijkheidseigenschap beschikbaar als een CLR-eigenschap die wordt ondersteund door een afhankelijkheidseigenschap in plaats van een privéveld.
Het toepassen van beveiligingsmechanismen en het beperken van de toegang tot de CLR-eigenschapinterface kan het gebruik van de hulpmethode voorkomen, maar deze technieken verhinderen geen directe aanroepen naar GetValue
of SetValue
. Met andere woorden, een afhankelijkheidseigenschap lezen/schrijven is altijd toegankelijk via het WPF-eigenschappensysteem. Als u een read-write afhankelijkheidseigenschap implementeert, moet u vermijden om de toegang tot de CLR-eigenschapsschakel te beperken. Declareer in plaats daarvan de CLR-eigenschapsschil als een openbaar lid, zodat oproepers op de hoogte zijn van het daadwerkelijke toegangsniveau van de afhankelijkheidseigenschap.
Blootstelling van eigenschappen van het eigenschapssysteem aan afhankelijkheidseigenschappen
Het WPF-eigenschappensysteem biedt toegang tot een eigenschap voor lezen/schrijven via de DependencyProperty-id. De identificator kan worden gebruikt in GetValue en SetValue oproepen. Zelfs als het statische id-veld niet openbaar is, retourneren verschillende aspecten van het eigenschappensysteem een DependencyProperty
zoals deze bestaat op een exemplaar van een klasse of afgeleide klasse. De methode GetLocalValueEnumerator retourneert bijvoorbeeld id's voor exemplaren van afhankelijke eigenschappen met een lokaal ingestelde waarde. U kunt ook de OnPropertyChanged virtuele methode overschrijven om gebeurtenisgegevens te ontvangen die de DependencyProperty
-id rapporteren voor afhankelijkheidseigenschappen die een gewijzigde waarde hebben. Als u bellers op de hoogte wilt stellen van het werkelijke toegangsniveau van een eigenschap voor lees-/schrijfafhankelijkheid, declareert u het id-veld als een openbaar lid.
Notitie
Hoewel het declareren van een veld voor afhankelijkheidseigenschappen als private
het aantal manieren vermindert waarop een afhankelijkheidseigenschap voor lezen en schrijven toegankelijk is, wordt de eigenschap niet privé- volgens de CLR-taaldefinitie.
Validatiebeveiliging
Het toepassen van een Demand op een ValidateValueCallback en verwachten dat de validatie faalt bij een Demand
-fout, is geen geschikt beveiligingsmechanisme om wijzigingen in de eigenschapswaarde te beperken. Bovendien kan de nieuwe ongeldigverklaring van waarden die wordt afgedwongen via ValidateValueCallback
worden onderdrukt door kwaadwillende aanroepen, als deze binnen het toepassingsdomein plaatsvinden.
Toegang tot eigenschappen van alleen-lezenafhankelijkheid
Als u de toegang wilt beperken, moet u uw eigenschap registreren als een alleen-lezen afhankelijkheidseigenschap door de methode RegisterReadOnly aan te roepen. De methode RegisterReadOnly
retourneert een DependencyPropertyKey, die u kunt toewijzen aan een niet-openbaar klasseveld. Voor eigenschappen van alleen-lezenafhankelijkheid biedt het WPF-eigenschappensysteem alleen schrijftoegang voor degenen die een verwijzing naar de DependencyPropertyKey
hebben. Ter illustratie van dit gedrag voert u de volgende testcode uit:
- Hiermee wordt een klasse geïnstantieerd die zowel lees-schrijf als alleen-lezen afhankelijkheidseigenschappen implementeert.
- Hiermee wijst u een
private
toegangsmodificator toe aan elke identifier. - Implementeert alleen
get
accessors. - Gebruikt de methode GetLocalValueEnumerator om toegang te krijgen tot de onderliggende afhankelijkheidseigenschappen via het WPF-eigenschappensysteem.
- Roept GetValue en SetValue aan om de toegang tot elke waarde van de afhankelijkheidseigenschap te testen.
/// <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
Zie ook
.NET Desktop feedback