FormatWithTags Extension Method

Tuesday, August 14, 2018

By: Chris Dunn

The string.format(..) method for building strings with variables is useful when you have a string template and want to replace values within the text. The only problem I have with this method is that it uses numeric placeholders for the values. That's fine if you have one or two values to integrate, but if you're dealing with more formatting of the text, it's problematic.

string.Format("My name is {0} and I live in {1}.", "Chris", "Indiana");
 Note: String interpolation will not work in this case as it's not intended as a templating solution.  It's just syntactic sugar and generates string.format at compile time.

Formatting e-mail content is a great example where you would need to "personalize" the text content by replacing placeholders with values. I like to externalize my e-mail content into a database or xml file.  I cringe every time I see hard coded email content within code. Using string.format to find and replace values in the email content would be a headache to maintain.  You would be translating numeric placeholders which gets tricky.

Tags: A better way

I didn't originate this idea but have used it for many years in varying forms and code. The idea is to pass a set of key value pairs, along with templated content, and utilize regular expressions to find and replace each {{tag}} with the value. Wrapping the functionality into an string extension makes it easy to implement. The method allows, as the second parameter, an object. If the object is not a Dictionary, it will automatically covert the values of the object to a Dictionary before processing.

 public static string FormatWithTags(this string text, object tags)
        {
            //return original string if no tag values given
            if (tags == null) return text;

            string result;
            //initialize tag dictionary of values
            IDictionary<string, string> tagsDictionary = null;

            //if already dictionary just cast
            if (tags is IDictionary<string, string>)
                tagsDictionary = tags as IDictionary<string, string>;
            else
            {
                //object or anonymous type so convert to dictionary of values
                tagsDictionary = TypeDescriptor
                .GetProperties(tags).Cast< PropertyDescriptor>()
                .ToDictionary(x => x.Name, x => x.GetValue(tags).ToString());
            }
            
            //replace all tags with values from dictionary
            result = tagsDictionary.Aggregate(text, (current, tag) => current.Replace("{" + tag.Key + "}", (tag.Value ?? string.Empty).ToString()));
            
            return result;
        }

Using FormatWithTags

Here is an simple example of using the method. Using this for external content isn't any more complicated than setting the "message" to the external data. In the first example I am passing in an anonymous type, and the second I am passing in key/value pairs.

string message = "Thank you {name} for your order of {product}.";
string formattedMessage = message.FormatWithTags(new { name = "John", product = "Ski Boots" });

string formattedMessage2 = message.FormatWithTags(
  new Dictionary<string, string>()
  { {"name","John" },
  { "product","Ski Boots"} });

Using named tags is so much easier to maintain and implement. While string.format may work ok for short inline values it's not scalable. The FormatWithTags method keeps your code clean, and content maintainable.

Tags: c# extension method strings

Copyright 2019 Cidean, LLC. All rights reserved.

Proudly running Umbraco 7. This site is responsive with the help of Foundation 5.