I'm writing automatic e-mailer. It has to scan database every X minutes and email people with reminders etc.
I have all underlying code ready. All I need now is to format emails.
Is there any predefined templating system in C# so I can create a folder with different templates and eg. tags such as {NAME}
so I just find those and开发者_开发技巧 replace it.
I can do it manually with opening a *.txt document and replacing those specific tags etc, however is there anything smarter? I wouldn't want to reinvent the wheel.
I'd look at using StringTemplate: http://www.stringtemplate.org/
You can do it with MVC 3's Razor templates, even in non-web applications.
An Internet search for Razor templates non-web
will turn up many examples.
It's not too difficult to write from scratch. I wrote this quick utility to do exactly what you described. It looks for tokens in the pattern {token}
and replaces them with the value that it retrieves from the NameValueCollection
. Tokens in the string correspond to keys in the collection which get replaced out for the value of the key in the collection.
It also has the added bonus of being simple enough to customize exactly as you need it.
public static string ReplaceTokens(string value, NameValueCollection tokens)
{
if (tokens == null || tokens.Count == 0 || string.IsNullOrEmpty(value)) return value;
string token = null;
foreach (string key in tokens.Keys)
{
token = "{" + key + "}";
value = value.Replace(token, tokens[key]);
}
return value;
}
USAGE:
public static bool SendEcard(string fromName, string fromEmail, string toName, string toEmail, string message, string imageUrl)
{
var body = GetEmailBody();
var tokens = new NameValueCollection();
tokens["sitedomain"] = "http://example.com";
tokens["fromname"] = fromName;
tokens["fromemail"] = fromEmail;
tokens["toname"] = toName;
tokens["toemail"] = toEmail;
tokens["message"] = message;
tokens["image"] = imageUrl;
var msg = CreateMailMessage();
msg.Body = StringUtility.ReplaceTokens(body, tokens);
//...send email
}
You can use the nVelocity
string templateDir = HttpContext.Current.Server.MapPath("Templates");
string templateName = "SimpleTemplate.vm";
INVelocityEngine fileEngine =
NVelocityEngineFactory.CreateNVelocityFileEngine(templateDir, true);
IDictionary context = new Hashtable();
context.Add(parameterName , value);
var output = fileEngine.Process(context, templateName);
If you are using ASP.NET 4 you can download RazorMail from the Nuget Gallery. It allows creation of emails using the Razor View Engine outwith the context of an MVC http request.
More details can be found via the following links...
http://www.nuget.org/List/Packages/RazorMail
https://github.com/wduffy/RazorMail/
I use this alot, plug in a Regex and a method that selects the replacement value based on the match.
/// </summary>
/// <param name="input">The text to perform the replacement upon</param>
/// <param name="pattern">The regex used to perform the match</param>
/// <param name="fnReplace">A delegate that selects the appropriate replacement text</param>
/// <returns>The newly formed text after all replacements are made</returns>
public static string Transform(string input, Regex pattern, Converter<Match, string> fnReplace)
{
int currIx = 0;
StringBuilder sb = new StringBuilder();
foreach (Match match in pattern.Matches(input))
{
sb.Append(input, currIx, match.Index - currIx);
string replace = fnReplace(match);
sb.Append(replace);
currIx = match.Index + match.Length;
}
sb.Append(input, currIx, input.Length - currIx);
return sb.ToString();
}
Example Usage
Dictionary<string, string> values = new Dictionary<string, string>();
values.Add("name", "value");
TemplateValues tv = new TemplateValues(values);
Assert.AreEqual("valUE", tv.ApplyValues("$(name:ue=UE)"));
/// <summary>
/// Matches a makefile macro name in text, i.e. "$(field:name=value)" where field is any alpha-numeric + ('_', '-', or '.') text identifier
/// returned from group "field". the "replace" group contains all after the identifier and before the last ')'. "name" and "value" groups
/// match the name/value replacement pairs.
/// </summary>
class TemplateValues
{
static readonly Regex MakefileMacro = new Regex(@"\$\((?<field>[\w-_\.]*)(?<replace>(?:\:(?<name>[^:=\)]+)=(?<value>[^:\)]*))+)?\)");
IDictionary<string,string> _variables;
public TemplateValues(IDictionary<string,string> values)
{ _variables = values; }
public string ApplyValues(string template)
{
return Transform(input, MakefileMacro, ReplaceVariable);
}
private string ReplaceVariable(Match m)
{
string value;
string fld = m.Groups["field"].Value;
if (!_variables.TryGetValue(fld, out value))
{
value = String.Empty;
}
if (value != null && m.Groups["replace"].Success)
{
for (int i = 0; i < m.Groups["replace"].Captures.Count; i++)
{
string replace = m.Groups["name"].Captures[i].Value;
string with = m.Groups["value"].Captures[i].Value;
value = value.Replace(replace, with);
}
}
return value;
}
}
(Even though you've ticked an answer, for future reference) - I got some amazing responses on my question of a similar nature: Which approach to templating in C sharp should I take?
精彩评论