The IPropertyAccess interface was first introduced in DotNetNuke version 4.06.00 to support the new Token Replace capability. The interface defines one function returning a string and one read-only property returning an enum of type DotNetNuke.Services.Tokens.CacheLevel:
Namespace DotNetNuke.Services.Tokens
''' <summary>
''' Interface to query any DataSource for their properties or custom values.
''' </summary>
''' <remarks></remarks>
Public Interface IPropertyAccess
Function GetProperty(ByVal strPropertyName As String, ByVal strFormat As String, _
ByVal formatProvider As Globalization.CultureInfo, ByVal AccessingUser As UserInfo, _
ByVal AccessLevel As Scope, ByRef PropertyNotFound As Boolean) As String
ReadOnly Property Cacheability() As CacheLevel
End Interface
End Namespace
Although the Token Replace capability can replace tokens with their property values from instances of classes which do not implement the IPropertyAcess interface, the use of .Net reflection in such a case is a costly process and does not offer the same security, formatting, and observance of the current culture (for example with DateTime structures) as is available with classes which have implemented this interface.
Let's take a look at each of the parameters which the core token replacement system may supply when calling an implementation of the interface's GetProperty function:
strPropertyName (String) - the name of the property whose value is to be returned. Any implementation of GetProperty should use a case in-sensitive comparison or force the supplied strPropertyName parameter to lowercase when branching to determine which property value to return.
strFormat (String) - a .Net standard or custom date/time or numeric format string, as would be applied when using the String.Format method, for example "MM/dd/yyyy" or "d" or "#,##0.00".
formatProvider (Globalization.CultureInfo) - user's or current culture information to be used when formatting dates, numeric values and currency.
AccessingUser (DotNetNuke.Entities.Users.UserInfo) - UserInfo object of the user accessing the object's property. May be used to determine if the requested property value should be returned based on the user's security roles or other user information.
AccessLevel (DotNetNuke.Services.Tokens.Scope) - Scope is an enum which may be used to inform the GetProperty function about the intended usage of the property. The scope should be the lowest scope needed for the current purpose. The property access classes should evaluate and use the scope before returning a value. The permitted values for Access Level are as follows:
Scope Enum NoSettings (0) | Access to only date and time |
Configuration (1) | Properties for Host, Portal, Tab, Module, Username |
DefaultSettings (2) | Configuration, current UserInfo, UserInfo for registered users |
SystemMessages (3) | System notifications to users and administrators |
Debug (4) | Debugging information, error messages, logs |
PropertyNotFound (Boolean) - Reference property returning True if specified property name not found in object implementing IPropertyAccess
The IPropertyAccess interface also defines a read-only property, Cacheability, which your implementation may use to inform the token replacement system whether or not values returned by GetProperty may be cached. The minimum level of cacheability should be returned when the GetProperty implementation may return property values having different levels of cacheability. Three levels of Cacheability are defined in the enum DotNetNuke.Services.Tokens.CacheLevel:
CacheLevel Enum notCacheable (0) | Caching of the returned text is not suitable and might expose security risks |
secureforCaching (5) | Caching of the text might result in inaccurate display (e.g. time), but does not expose a security risk |
fullyCacheable (10) | Caching of the text can be done without limitations or any risk |
To see how the IPropertyAccess interface may be implemented for your custom object classes, here is example code taken from the core UserInfo class:
#Region "IPropertyAccess Implementation"
Dim strAdministratorRoleName As String
''' <summary>
''' Determine, if accessing user is Administrator
''' </summary>
''' <param name="AccessingUser">userinfo of the user to query</param>
''' <returns>true, if user is portal administrator or superuser</returns>
''' <history>
''' 2007-10-20 [sleupold] added
''' </history>
Private Function isAdminUser(ByRef AccessingUser As UserInfo) As Boolean
If AccessingUser Is Nothing OrElse AccessingUser.UserID = -1 Then
Return False
ElseIf strAdministratorRoleName = "" Then
Dim ps As DotNetNuke.Entities.Portals.PortalInfo = _
New DotNetNuke.Entities.Portals.PortalController().GetPortal(AccessingUser.PortalID)
strAdministratorRoleName = ps.AdministratorRoleName
End If
Return AccessingUser.IsInRole(strAdministratorRoleName) OrElse AccessingUser.IsSuperUser
End Function
''' <summary>
''' Property access, initially provided for TokenReplace
''' </summary>
''' <param name="strPropertyName">Name of the Property</param>
''' <param name="strFormat">format string</param>
''' <param name="formatProvider">format provider for numbers, dates, currencies</param>
''' <param name="AccessingUser">userinfo of the user, who queries the data (used to determine permissions)</param>
''' <param name="CurrentScope">requested maximum access level, might be restricted due to user level</param>
''' <param name="PropertyNotFound">out: flag, if property could be retrieved.</param>
''' <returns>current value of the property for this userinfo object</returns>
''' <history>
''' 2007-10-20 [sleupold] documented and extended with differenciated access permissions
''' 2007-10-20 [sleupold] role access added (for user himself or admin only).
''' </history>
Public Function GetProperty(ByVal strPropertyName As String, ByVal strFormat As String, _
ByVal formatProvider As System.Globalization.CultureInfo, ByVal AccessingUser As UserInfo, _
ByVal CurrentScope As Services.Tokens.Scope, ByRef PropertyNotFound As Boolean) As String _
Implements Services.Tokens.IPropertyAccess.GetProperty
'Limit permissions according to user type (admin, user itself, registered member or unauthenticated):
Dim internScope As DotNetNuke.Services.Tokens.Scope
If Me.UserID = -1 And CurrentScope > Scope.Configuration Then
internScope = Scope.Configuration 'anonymous users only get access to displayname
ElseIf Me.UserID <> AccessingUser.UserID AndAlso Not isAdminUser(AccessingUser) AndAlso CurrentScope > Scope.DefaultSettings Then
internScope = Scope.DefaultSettings 'registerd users can access username and userID as well
Else
internScope = CurrentScope 'admins and user himself can access all data
End If
Dim OutputFormat As String = String.Empty
If strFormat = String.Empty Then OutputFormat = "g" Else OutputFormat = strFormat
Select Case strPropertyName.ToLower
Case "verificationcode"
If internScope < Scope.SystemMessages Then PropertyNotFound = True : Return PropertyAccess.ContentLocked
Return Me.PortalID.ToString & "-" & Me.UserID.ToString
Case "affiliateid"
If internScope < Scope.SystemMessages Then PropertyNotFound = True : Return PropertyAccess.ContentLocked
Return (Me.AffiliateID.ToString(OutputFormat, formatProvider))
Case "displayname"
If internScope < Scope.Configuration Then PropertyNotFound = True : Return PropertyAccess.ContentLocked
Return PropertyAccess.FormatString(Me.DisplayName, strFormat)
Case "email"
If internScope < Scope.DefaultSettings Then PropertyNotFound = True : Return PropertyAccess.ContentLocked
Return (PropertyAccess.FormatString(Me.Email, strFormat))
Case "firstname" 'using profile property is recommended!
If internScope < Scope.DefaultSettings Then PropertyNotFound = True : Return PropertyAccess.ContentLocked
Return (PropertyAccess.FormatString(Me.FirstName, strFormat))
Case "issuperuser"
If internScope < Scope.Debug Then PropertyNotFound = True : Return PropertyAccess.ContentLocked
Return (Me.IsSuperUser.ToString(formatProvider))
Case "lastname" 'using profile property is recommended!
If internScope < Scope.DefaultSettings Then PropertyNotFound = True : Return PropertyAccess.ContentLocked
Return (PropertyAccess.FormatString(Me.LastName, strFormat))
Case "portalid"
If internScope < Scope.Configuration Then PropertyNotFound = True : Return PropertyAccess.ContentLocked
Return (Me.PortalID.ToString(OutputFormat, formatProvider))
Case "userid"
If internScope < Scope.DefaultSettings Then PropertyNotFound = True : Return PropertyAccess.ContentLocked
Return (Me.UserID.ToString(OutputFormat, formatProvider))
Case "username"
If internScope < Scope.DefaultSettings Then PropertyNotFound = True : Return PropertyAccess.ContentLocked
Return (PropertyAccess.FormatString(Me.Username, strFormat))
Case "fullname" 'fullname is obsolete, it will return DisplayName
If internScope < Scope.Configuration Then PropertyNotFound = True : Return PropertyAccess.ContentLocked
Return (PropertyAccess.FormatString(Me.DisplayName, strFormat))
Case "roles"
If CurrentScope < Scope.SystemMessages Then PropertyNotFound = True : Return PropertyAccess.ContentLocked
Return (PropertyAccess.FormatString(String.Join(", ", Me.Roles), strFormat))
End Select
PropertyNotFound = True : Return String.Empty
End Function
<Browsable(False)> Public ReadOnly Property Cacheability() As CacheLevel Implements Services.Tokens.IPropertyAccess.Cacheability
Get
Return CacheLevel.notCacheable
End Get
End Property
#End Region
References
DotNetNuke 4.6.0 A Sneak Peek (5) Token ReplaceTokens