依存関係プロパティのセキュリティ (WPF .NET)
Windows Presentation Foundation (WPF) プロパティ システムを介した読み取り/書き込み依存関係プロパティのアクセシビリティにより、パブリック プロパティが効果的に作成されます。 その結果、読み取り/書き込み依存関係プロパティの値に関するセキュリティを保証することはできません。 WPF プロパティ システムは、書き込みアクセスを制限できるように、読み取り専用の依存関係プロパティのセキュリティを強化します。
プロパティ ラッパーのアクセスとセキュリティ
共通言語ランタイム (CLR) プロパティ ラッパーは、通常、プロパティ値の取得または設定を簡略化するために、読み取り/書き込み依存関係プロパティの実装に含まれています。 含まれている場合、CLR プロパティ ラッパーは、基になる依存関係プロパティと対話する GetValue と SetValue 静的呼び出しを実装する便利なメソッドです。 基本的に、CLR プロパティ ラッパーは、プライベート フィールドではなく依存関係プロパティによってサポートされる CLR プロパティとして依存関係プロパティを公開します。
セキュリティ メカニズムを適用し、CLR プロパティ ラッパーへのアクセスを制限すると、便利なメソッドの使用が妨げられますが、これらの手法では、GetValue
または SetValue
への直接呼び出しを防ぐことはありません。 言い換えると、読み取り/書き込み依存関係プロパティには、WPF プロパティ システムを介して常にアクセスできます。 読み取り/書き込み依存関係プロパティを実装する場合は、CLR プロパティ ラッパーへのアクセスを制限しないでください。 代わりに、CLR プロパティ ラッパーをパブリック メンバーとして宣言して、呼び出し元が依存関係プロパティの真のアクセス レベルを認識できるようにします。
依存プロパティのシステム公開
WPF プロパティ システムは、DependencyProperty 識別子を介して読み取り/書き込み依存関係プロパティにアクセスできます。 この識別子は、GetValue 呼び出しと SetValue 呼び出しで使用できます。 静的識別子フィールドがパブリックでない場合でも、プロパティ システムのいくつかの側面は、クラスまたは派生クラスのインスタンスに存在する DependencyProperty
を返します。 たとえば、GetLocalValueEnumerator メソッドは、ローカルに設定された値を持つ依存関係プロパティ インスタンスの識別子を返します。 また、OnPropertyChanged 仮想メソッドをオーバーライドして、値が変更された依存関係プロパティの DependencyProperty
識別子を報告するイベント データを受信することもできます。 呼び出し元が読み取り/書き込み依存関係プロパティの真のアクセス レベルを認識できるようにするには、その識別子フィールドをパブリック メンバーとして宣言します。
手記
依存関係プロパティ識別子フィールドを
検証のセキュリティ
Demand を ValidateValueCallback に適用し、Demand
エラー時に検証が失敗することを想定することは、プロパティ値の変更を制限するための適切なセキュリティ メカニズムではありません。 また、ValidateValueCallback
によって適用される新しい値の無効化は、悪意のある呼び出し元がアプリケーション ドメイン内で動作している場合に抑制できます。
読み取り専用の依存関係プロパティへのアクセス
アクセスを制限するには、RegisterReadOnly メソッドを呼び出して、プロパティを読み取り専用の依存関係プロパティとして登録します。 RegisterReadOnly
メソッドは、パブリックでないクラス フィールドに割り当てることができる DependencyPropertyKeyを返します。 読み取り専用の依存関係プロパティの場合、WPF プロパティ システムは、DependencyPropertyKey
への参照を持つユーザーにのみ書き込みアクセスを提供します。 この動作を示すために、次のテスト コードを使用します。
- 読み取り/書き込み依存関係プロパティと読み取り専用依存関係プロパティの両方を実装するクラスをインスタンス化します。
- 各識別子に
private
アクセス修飾子を割り当てます。 get
アクセサーのみを実装します。- GetLocalValueEnumerator メソッドを使用して、WPF プロパティ システムを介して基になる依存関係プロパティにアクセスします。
- GetValue と SetValue を呼び出して、各依存関係プロパティ値へのアクセスをテストします。
/// <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
関連項目
- DependencyProperty
- GetLocalValueEnumerator
- OnPropertyChanged
- カスタム依存関係プロパティ
- 依存関係プロパティ を実装する
.NET Desktop feedback