DNN Community Blog

The Community Blog is a personal opinion of community members and by no means the official standpoint of DNN Corp or DNN Platform. This is a place to express personal thoughts about DNNPlatform, the community and its ecosystem. Do you have useful information that you would like to share with the DNN Community in a featured article or blog? If so, please contact .

The use of the Community Blog is covered by our Community Blog Guidelines - please read before commenting or posting.


4.6.0. A Sneak Peek (5) - Token Replace

4.6.0: Token Replace

DotNetNuke 4.6.0 is going to include a new Token Replace engine. It searches text for tokens, analyses them and replaces the tokens with their related framework values. The syntax is quite simple: [Object:Property]. For example the token [User:Lastname] will be replaced with the last name of the current user. You might already know this kind of notation; it is the same that has been already used for system messages inside the language pack.

History

At the end of last year Sebastian and I were working on a request for User Defined Table 3.4.0. We were asked to replace the caption of a link with context information. Sebastian as editor of the German Language pack was familiar with the token syntax, so we took the code out of localization and used it in our module. Quickly we realized that this code was too slow to be called for each row of a User Defined Table. We rewrote that code from scratch using Regular Expressions, and it was impressive enough to get part of DotNetNuke 4.4.1. inside the Localization namespace.

We now had got a fast token replacement service, and some developers already started on reusing the code inside their own projects. Reusing meant that they copied the code and wrote their own, specialized token engines. As copying code is not really an Object Orientated technique, I started again a major refactoring which resulted in a new set of classes located in the new DotNetNuke.Services.Tokens namespace. These new services provide new enhancements and are open for own extensions. The previous TokenReplace class inside the Localization namespace still exists, but it is now deprecated and is actually just an adapter to the new classes.

Usage

TokenReplace allows the following notations:

[Object :Property]
[Object :Property|Format]
[Object :Property|Format|IfEmpyReplacement]

TokenReplace recognizes the following Object names as valid source for values:

Object Class / Data source Default Content**
“Host”  System.Collection.Hashtable Secure Hostsettings
“Portal” DotNetNuke.Entities.Portals.PortalSettings current PortalSettings
“Tab”  DotNetNuke.Entities.Tabs.TabInfo current TabInfo
“Module” DotNetNuke.Entities.Modules.ModuleInfo Nothing
“Culture” System.Globalization.CultureInfo currrent Culture
     
“User” DotNetNuke.Entities.Users.UserInfo current User 
“Profile” DotNetNuke.Entities.Profile current User.Profile
“Membership” DotNetNuke.Entities.Users.Membership current User.Membership
     
“Date”, “DateTime”, “Time”  System.DateTime current DateTime
 “Ticks” System.Int64 (Long) current DateTime in ticks
     
“Row”, “Field” System.Data.DataRow Nothing
“Custom”* System.Collections.ArrayList Nothing
userdefined Token  Any Object by Reflection Nothing
userdefined Token Any System.Collection.IDictionary Nothing

* “custom” can be replaced with custom text, passed as separate parameter
** The content depends also on the scope and profile visibility setup. 

Scope Description
NoSettings Only access to Date and Time
Configuration Tokens for Host, Portal, Tab (, Module)
DefaultSettings Configuration and Current User
SystemMessages System notifications to users and adminstrators
Debug internal debugging, error messages, logs

The first four scopes will only return public relevant information. For example the only public avaiable property is HostName. All others are only accessible to the "Debug" scope. Critical information (host password...) is not available through TokenReplace.

The output can be formatted using a format string. You can use the usual Date and Time Format Strings for date values or Numeric Format Strings for any numeric value. String values are handled using String.Format.

Example:
[User:Lastname|Dear Mr./Mrs . {0}] Dear Mr./Mrs. Walker
[Date:Now|dddd] Monday

The “Format” string can be followed by an additional “IfEmptyReplacement”, which will be returned when is requested property is not found or not set.

Example:
[User:Firstname|Hi {0}|Hello Guest]

Reusing

TokenReplace was built with extensible in mind and was therefore created using inheritance. The top level class is BaseTokenReplace. This class handles the tokenization using Regular Expressions. If you only want to handle one single or only few custom token, this class is your friend:

Public Class DateTimeTokenReplace
    Inherits Services.Tokens.BaseTokenReplace

    Public Function ReplaceDateTimeTokens(ByVal strSource As String) As String
        Return MyBase.ReplaceTokens(strSource)
    End Function

    Protected Overrides Function replacedTokenValue(ByVal strObjectName As String, _
ByVal strPropertyName As String, ByVal strFormat As String) As String Dim result As String = String.Empty If strFormat = String.Empty Then strFormat = "g" If strObjectName.ToLower = "datetime" Then If strPropertyName.ToLower = "today" Then result = System.DateTime.Today.ToString(strFormat) Else result = System.DateTime.Now.ToString(strFormat) End If End If Return result End Function End Class 'sets "Today is Monday" on Mondays Dim r as String = new DateTimeTokenReplace().ReplaceDateTimeTokens("Today is [Datetime:today|dddd]")

If you need to handle multiple kinds of Object tokens, you might want to handle every data source in its own custom class. This class needs to implement IPropertyAccess which consists out of the function GetProperty and the property Cacheability. 
  

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

 

BaseCustomTokenReplace is able to handle multiple data sources. The previous example can now be rewritten. First we need the property access class:

Class DateTimeAccess
    Implements Services.Tokens.IPropertyAccess

    Public Function GetProperty(ByVal strPropertyName As String, ByVal strFormat As String, _
            ByVal formatProvider As System.Globalization.CultureInfo, ByVal AccessingUser As Entities.Users.UserInfo, _
            ByVal AccessLevel As Scope, ByRef PropertyNotFound As Boolean) As String Implements IPropertyAccess.GetProperty
    Dim result As String = String.Empty
    If strFormat = String.Empty Then strFormat = "g"
    If strPropertyName.ToLower = "today" Then
      result = System.DateTime.Today.ToString(strFormat, formatprovider)
    Else
      result = System.DateTime.Now.ToString(strFormat. formatprovider)
    End If
    Return result
  End Function
  
  Public ReadOnly Property Cacheability() As CacheLevel Implements Services.Tokens.IPropertyAccess.Cacheability
    Get
      Return CacheLevel.secureforCaching
    End Get
  End Property

End Class

The main token replace is now more compact:

Public Class DateTimeTokenReplace2
    Inherits Services.Tokens.BaseCustomTokenReplace
    Sub New()
        PropertySource("datetime") = New DateTimeAccess
    End Sub
    Public Function ReplaceDateTimeTokens(ByVal strSource As String) As String
        Return MyBase.ReplaceTokens(strSource)
    End Function
End Class

Dim dttr2 As New DateTimeTokenReplace2()
dttr2.DebugMessages = True
dttr2.Language = "de-de"
'sets "Montag" on Mondays
Dim s As String = dttr2.ReplaceDateTimeTokens("[datetime:today|dddd]")
There are three different CacheLevel:
CacheLevelMeaning
notCacheableCaching of the text is not suitable and might expose security risks
secureforCachingCaching of the text might result in inaccurate display (e.g. time), but does not expose a security risk
fullyCacheableCaching of the text can be done without limitations or any risk

You can ask TokenReplace whether your current [Token] string whether is cachable or not.

Dim cl as CacheLevel = dttr2.Cacheability("Is [Date:Now] cacheable")
'cl = CacheLevel.SecureForCaching

Class TokenReplace is the main class inside the tokens namespace. It uses to handle 13 different data sources. A new class does not need to handle each data source. If there is already an info class, the interface can also be put inside. Examples for these are UserInfo or ModuleInfo.

The method ReplaceEnviromentTokens has a number of overloads, which allow also to use DataRows, Dictionaries (HashTables) or ArrayLists as source for the tokenization.

Public Function ReplaceEnvironmentTokens(ByVal strSourceText As String) As String
Public Function ReplaceEnvironmentTokens(ByVal strSourceText As String, _
ByVal row As DataRow) As String Public Function ReplaceEnvironmentTokens(ByVal strSourceText As String, _
ByVal Custom As ArrayList, ByVal CustomCaption As String) As String Public Function ReplaceEnvironmentTokens(ByVal strSourceText As String, _
ByVal Custom As IDictionary, ByVal CustomCaption As String) As String Public Function ReplaceEnvironmentTokens(ByVal strSourceText As String, _
ByVal Custom As ArrayList, ByVal CustomCaption As String, _
ByVal Row As System.Data.DataRow) As String

TokenReplace is not sealed, so you can extend it with your own data sources.

TokenReplace can also handle object less [PROPERTY] tokens, which might help to renew some already existing Token Engines inside DotNetNuke.

Example:

Public Class DateTimeTokenReplace3
    Inherits DotNetNuke.Services.Tokens.TokenReplace

    Public Sub New()
        MyBase.new(Services.Tokens.Scope.Configuration)
UseObjectLessExpression = True PropertySource(ObjectLessToken) = New DateTimeAccess End Sub End Classdim s as String = new DateTimeTokenReplace3().ReplaceEnvironmentTokens( _
"hello [User:Displayname|{0}|Guest], today is [TODAY]")

Comments

Comment Form

Only registered users may post comments.

NewsArchives


Aderson Oliveira (15)
Alec Whittington (11)
Alex Shirley (10)
Andrew Nurse (30)
Andy Tryba (1)
Anthony Glenwright (5)
Antonio Chagoury (28)
Ash Prasad (32)
Ben Schmidt (1)
Benjamin Hermann (25)
Benoit Sarton (9)
Beth Firebaugh (12)
Bill Walker (36)
Bob Kruger (5)
Bogdan Litescu (1)
Brian Dukes (2)
Brice Snow (1)
Bruce Chapman (20)
Bryan Andrews (1)
cathal connolly (55)
Charles Nurse (163)
Chris Hammond (209)
Chris Paterra (55)
Clinton Patterson (40)
Cuong Dang (21)
Daniel Bartholomew (2)
Daniel Mettler (154)
Dave Buckner (2)
David Poindexter (4)
David Rodriguez (3)
Doug Howell (11)
Erik van Ballegoij (30)
Ernst Peter Tamminga (74)
Geoff Barlow (10)
George Alatrash (6)
Gifford Watkins (3)
Gilles Le Pigocher (3)
Ian Robinson (7)
Israel Martinez (17)
Jan Blomquist (2)
Jan Jonas (3)
Jaspreet Bhatia (1)
Jenni Merrifield (6)
Joe Brinkman (274)
John Mitchell (1)
Jon Henning (14)
Jonathan Sheely (4)
Jordan Coopersmith (1)
Joseph Craig (2)
Kan Ma (1)
Keivan Beigi (3)
Ken Grierson (10)
Kevin Schreiner (6)
Leigh Pointer (31)
Lorraine Young (60)
Malik Khan (1)
Matthias Schlomann (15)
Mauricio Márquez (5)
Michael Doxsey (7)
Michael Tobisch (3)
Michael Washington (202)
Miguel Gatmaytan (3)
Mike Horton (19)
Mitchel Sellers (28)
Nathan Rover (3)
Navin V Nagiah (14)
Néstor Sánchez (31)
Nik Kalyani (14)
Peter Donker (54)
Philip Beadle (135)
Philipp Becker (4)
Richard Dumas (22)
Robert J Collins (5)
Roger Selwyn (8)
Ruben Lopez (1)
Ryan Martinez (1)
Salar Golestanian (4)
Sanjay Mehrotra (9)
Scott McCulloch (1)
Scott S (11)
Scott Wilkinson (3)
Scott Willhite (97)
Sebastian Leupold (80)
Shaun Walker (237)
Shawn Mehaffie (17)
Stefan Cullmann (12)
Stefan Kamphuis (12)
Steve Fabian (31)
Timo Breumelhof (24)
Tony Henrich (3)
Torsten Weggen (2)
Vicenç Masanas (27)
Vincent Nguyen (3)
Vitaly Kozadayev (6)
Will Morgenweck (40)
Will Strohl (165)
William Severance (5)

Content Layout

Subscribe to DNN Digest

DNN Digest is our monthly email newsletter. It highlights news and content from around the DNN ecosystem, such as new modules and themes, messages from leadership, blog posts and notable tweets. Keep your finger on the pulse of the ecosystem by subscribing.  


Copyright 2017 by DNN Corp Terms of Use Privacy
What is Liquid Content?
Find Out
What is Liquid Content?
Find Out
What is Liquid Content?
Find Out