Sep
9
Posted by:
Stefan Cullmann
Sun, 09 Sep 2007 20:59:24 GMT
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:
| CacheLevel | Meaning |
| notCacheable | Caching of the text is not suitable and might expose security risks |
| secureforCaching | Caching of the text might result in inaccurate display (e.g. time), but does not expose a security risk |
| fullyCacheable | Caching 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 Class
…
dim s as String = new DateTimeTokenReplace3().ReplaceEnvironmentTokens( _
"hello [User:Displayname|{0}|Guest], today is [TODAY]")
15 comment(s) so far...
Re: 4.6.0. A Sneak Peek (5) - Token Replace
I just wrote something like this over the weekend. Too bad I didn't know about this before, i could have gone fishing on Saturday!
A request i have from my designers a lot is to have token replacements in the skins. Something you see a lot is:
Welcome RYAN, If you are not RYAN please click here to logoff.
Thanks, Ryan Morgan www.ArrowNuke.com
By JimSteele on
Mon, 10 Sep 2007 14:00:19 GMT
|
Re: 4.6.0. A Sneak Peek (5) - Token Replace
Stefan, As a designer I love the new feature. Problem is I don't use Visual Studio so these are hard to access.
Would you be willing to make a cheat sheet that fully exposes the objects and properties available by default?
By lancelong on
Tue, 18 Sep 2007 18:21:09 GMT
|
Re: 4.6.0. A Sneak Peek (5) - Token Replace
Sure. We already added token replace to BulkMail (Newsletter) and the Text/Html module. UDT is also using an early version of TokenReplace.
By cshark on
Sat, 22 Sep 2007 19:29:12 GMT
|
Re: 4.6.0. A Sneak Peek (5) - Token Replace : Cheat Sheet
Hello everyone,
For those in the same boat as LanceLong here is an alternative to a "cheat sheet". The number of assembly objects and properties is TREMENDOUS and would take forever to clean-up and map out.
So DNN Web Designers, here is a great way to browse the objects you might need for token replacement.
First, get this great tool that uses reflection to browse assemblies.
http://www.aisto.com/roeder/dotnet/Download.aspx?File=Reflector
Okay, nearly there, just do this...
1. Extract the reflector tool into its own folder on a server where you have DotNetNuke installed. 2. Open it and choose the 2.x .NET framework as the default when prompted. 3. Go to File > Open and browse to the /bin folder under your DNN website folders. 4. Open the assembly you want to check out, example...
User properties can be found in: DotNetNuke.Entities.Users.UserInfo a) We open the DotNetNuke.dll file. b) We browse using the reflector into DotNetNuke.dll > DotNetNuke.Entities.Users > UserInfo. c) We clap and cheer as we see that Dylan from has shown us the very properties we need... (You should now be looking at things like "FirstName", "Email", etc.)
So using the reflector, I now know that I can token replace with a string like:
[Object:Property|Text & Token|Text + Token for empty properties.] [User:Firstname|Hi {0}|Hello Guest]
I hope this helps.
Cheers, Dylan
Dylan Lopez @ Inno Software Inc 604.628.4467 www.innosoftware.net Web Development & .NET Consulting
By dylanlopez on
Tue, 25 Sep 2007 02:20:04 GMT
|
Re: 4.6.0. A Sneak Peek (5) - Token Replace : Cheat Sheet
For those struggling with the brutal comment formatting. Copy the entire comment I wrote above, paste it into notepad and do a save-as to your desktop with the file name "comment.html" in double-quotes to force the .html extension. Open the file in your favorite browser and it'll be readable.
By dylanlopez on
Tue, 25 Sep 2007 02:26:00 GMT
|
Re: 4.6.0. A Sneak Peek (5) - Token Replace
Thank you dylanlopez, I realize that I misunderstood lancelongs question. You are rright, tools like reflector (or in fact any object browser) will help, at least for reasl object properties. It will not help in case of for example profile data with custom profile properties. We are currentlly discussing some ways to gain a list of object/property/localized description triples on the fly.
By cshark on
Tue, 25 Sep 2007 06:50:12 GMT
|
Re: 4.6.0. A Sneak Peek (5) - Token Replace
Any plans on adding this at the Page Level using the same deprecatable settings as the HTML config? This would be great for things like the PageName, Title, Description, Keywords etc...
By schafer_brad on
Fri, 05 Oct 2007 18:44:31 GMT
|
Re: 4.6.0. A Sneak Peek (5) - Token Replace
Hey guys, great work! I am refactoring all my replacment methods to run through your methods as I was hardcoding all the user properties I wanted and using a standard Replace method.
One thing I do on the UserProfile Detail template is list all the custom profile properties - eg:
//loop through all core properties ProfilePropertyDefinitionCollection profilePropertyDefinitionCollection = ProfileController.GetPropertyDefinitionsByPortal(moduleSettingsBase.PortalId); foreach (ProfilePropertyDefinition definition in profilePropertyDefinitionCollection) { if (definition.Visible) { sb.Append("["); sb.Append(definition.PropertyName); sb.Append("]"); } }
So the template editor knows exactly what is available on their portal.
By rodneyjoyce on
Tue, 16 Oct 2007 03:06:19 GMT
|
Re: 4.6.0. A Sneak Peek (5) - Token Replace
Hey Stefan - I have some questions on this but I think it's better to move them to the Forums - please have a look at this when you have a mo: http://www.dotnetnuke.com/Community/Forums/tabid/795/mid/2108/threadid/176614/scope/posts/Default.aspx#176614
By rodneyjoyce on
Tue, 16 Oct 2007 06:19:28 GMT
|
UserProfile Templating and Forum Integration
The core DNN forums has it's own limited user profile system built into it. We already use the Smart-Thinker UserProfile to display templated views of the core profile data, so we want to remove the F ... # Smart-Thinker DotNetNuke Development Blog
By TrackBack on
Mon, 01 Dec 2008 16:35:25 GMT
|
Re: 4.6.0. A Sneak Peek (5) - Token Replace
Very useful post, but there seems to be a problem with outputting blank if a token does not have a value - http://www.dotnetnuke.com/Community/Forums/tabid/795/forumid/-1/threadid/179522/scope/posts/Default.aspx
By rodneyjoyce on
Fri, 26 Oct 2007 06:16:15 GMT
|
Re: 4.6.0. A Sneak Peek (5) - Token Replace
Stefan -
I coordinate the Southern California DotNetNuke Users Group that meets monthly (www.socaldug.org). We do virtual presentations via MS Live Meeting. Would you be able to "meet" with us (virtually) the 2nd Wed. of any month in 2008? We start at 5:30 pm Pacific time so we can include the East Coast. Whatever you would like to present would be interesting to our group, I'm sure, especially the XML module. Please let me know at dma@dmcma.com.
Dave McMullen
By dma111 on
Sun, 04 Nov 2007 06:13:32 GMT
|
Announcements module: version 4 is here!
After so much inspiration from the OpenForce conferences, where Charles Nurse and Vicenç Masanas created advanced versions of the Announcements module, it really felt good creating a new version of th ... # Module :: Announcements
By TrackBack on
Mon, 01 Dec 2008 16:32:59 GMT
|
Re: 4.6.0. A Sneak Peek (5) - Token Replace
Added link to this as an External Resource on PortalModuleBase.com wiki - Token Replacement (www.portalmodulebase.com/Wiki/tabid/56/Default.aspx?topic=Token+Replacement)
By Dave Amphlett on
Thu, 11 Dec 2008 17:27:37 GMT
|
Re: 4.6.0. A Sneak Peek (5) - Token Replace
Very helpful post. Thank you.
Can anyone point me to a code example of how to use TR to create new tokens that would be recognized in FCKEditor? Want create [Title] and [Content] tokens and replace them with strings when applying fck template.
Thanks again!
By Corinne on
Wed, 04 Mar 2009 21:53:52 GMT
|