DNN Blog

Sep 9

Posted by: Stefan Cullmann
Sun, 09 Sep 2007 20:59:24 GMT  RssIcon

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]")

Tags:
Categories:

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
Gravatar

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
Gravatar

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
Attend A Webinar
Try An Online Demo
Download DotNetNuke Professional Edition Trial
Have Someone Contact Me

Like Us on Facebook Join our Network on LinkedIn Follow DNN Corporate on Twitter Follow DNN on Twitter

Advertisers

Sponsors

DotNetNuke Corporation

DotNetNuke Corp. is the steward of the DotNetNuke open source project, the most widely adopted Web Content Management Platform for building web sites and web applications on Microsoft .NET. Organizations use DotNetNuke to quickly develop and deploy interactive and dynamic web sites, intranets, extranets and web applications. The DotNetNuke platform is available in a free Community and subscription-based Professional and Enterprise Editions with an Elite Support option. DotNetNuke Corp. also operates Snowcovered.com where users purchase third party apps for the platform.