How To: Add Custom "Dictionary Token"

We all definitely used the tokens feature of orchard before, which provide us a smart way to replace strings with custom data, orchard has the basic tokens built in out of the box (like: Content, Text, Url ... etc), with the ability to connect tokens in chains to be more useful with the ability to build more complex tokens.

In this post, we will take orchard tokens functonality to another level of dynamicity, by implementing new token called "Dictionary", to be able to support any type of objects, with dynamic chain building.

Implement New "ITokenProvider", called "DictionaryTokens"

Here, we will describe and evaluate our new dictionary tokens, like the following:

public class DictionaryTokens : ITokenProvider {
public DictionaryTokens() {
T = NullLocalizer.Instance;
}

public Localizer T { get; set; }

public void Describe(DescribeContext context) {
context.For("Dictionary", T("Dictionary"), T("Dictionary tokens"));
}

public void Evaluate(EvaluateContext context) {
var dataContext = context.For<Dictionary<string, object>>("Dictionary");
if (dataContext.Data != null) {
foreach (var data in dataContext.Data) {
if (data.Value is string) {
dataContext.Token(data.Key, d => (string)d[data.Key])
.Chain(data.Key, "Text", d => (string)d[data.Key]);
}
else if (data.Value is DateTime) {
dataContext.Token(data.Key, d => (DateTime)d[data.Key])
.Chain(data.Key, "Date", d => (DateTime)d[data.Key]);
}
else if (data.Value is IContent) {
dataContext.Token(data.Key, d => (IContent)d[data.Key])
.Chain(data.Key, "Content", d => (IContent)d[data.Key]);
}
else if (data.Value is IUser) {
dataContext.Token(data.Key, d => (IUser)d[data.Key])
.Chain(data.Key, "User", d => (IUser)d[data.Key]);
}
else if (data.Value is JObject) {
dataContext.Token(data.Key, d => d[data.Key])
.Chain(data.Key, "Dictionary", d =>
((JObject)d[data.Key]).ToObject<Dictionary<string, object>>());
}
else {
dataContext.Token(data.Key, d => d[data.Key]);
}
}
}
}
}

This provider will take your dictionary as parameter, then check it's contents in the evaluation process, to link every property to the appropriate token chain, with support to chain itself if there is an object within the dictionary.

Let's Use It

We can use this new token like any other one, declare a dictionary and pass it to the tokenizer service with a key, as following:

var message = "Hi {Dictionary.User.FirstName} {Dictionary.User.lastName},<br/>" +
"This message sent to {Dictionary.Email}:<br/>" +
"<strong>{Dictionary.Subject}</strong><br/>" +
"{Dictionary.Message}";
var messageDictionary = new Dictionary<string, object> {
{"Subject", subject},
{"Message", message},
{"Email", email},
{"User", new Dictionary<string, object> {
{"FirstName", firstName},
{"LastName", lastName}
}
};
var tokenizedMessage = _tokenizer.Replace(
message,
new Dictionary<string, object> {
{ "Dictionary", messageDictionary }
}
);

If we run this code with the following dictionary data:

Subject: "Test Subject"
Message: "Test Message"
Email: "test@test.com"
User:
FirstName: "testfirstname"
LastName: "testlastname"

The output string will be:

Hi testfirstname testlastname,
This message sent to test@test.com:
Test Subject
Test Message

Tags

Leave a comment

4 Comments

  • Harry

    Just wanted to say thanks for this fantastic lesson. Nice work!

  • mdameer

    Thanks Harry, My pleasure

  • website

    Thanks , I have recently been searching for information approximately this topic for ages and yours is the greatest I have came upon till now. However, what in regards to the bottom line?

  • great post

    Just wanted to say thanks for this fantastic lesson. Nice work!