c# - 如何动态替换电子邮件模板中的占位符
问题描述
有没有用动态数据替换占位符的好方法?我尝试加载一个模板,然后用元对象中的数据替换所有 {{PLACEHOLDER}} 标记,这是有效的。但是如果我需要添加更多的占位符,我必须在代码中完成,并进行新的部署,所以如果可能的话,我想通过数据库来完成,如下所示:
Table Placeholders
ID, Key (nvarchar(50), Value (nvarchar(59))
1 {{RECEIVER_NAME}} meta.receiver
2 {{RESOURCE_NAME}} meta.resource
3 ..
4 .. and so on
meta 是发送到 BuildTemplate 方法的参数的名称。
因此,当我遍历所有占位符(来自 db)时,我想将值从 db 转换为元对象。我需要参数内的值,而不是获取“meta.receiver”。
GetAllAsync ex.1
public async Task<Dictionary<string, object>> GetAllAsync()
{
return await _context.EmailTemplatePlaceholders.ToDictionaryAsync(x => x.PlaceholderKey, x => x.PlaceholderValue as object);
}
GetAllAsync ex.2
public async Task<IEnumerable<EmailTemplatePlaceholder>> GetAllAsync()
{
var result = await _context.EmailTemplatePlaceholders.ToListAsync();
return result;
}
样本不使用数据库(工作))
private async Task<string> BuildTemplate(string template, dynamic meta)
{
var sb = new StringBuilder(template);
sb.Replace("{{RECEIVER_NAME}}", meta.receiver?.ToString());
sb.Replace("{{RESOURCE_NAME}}", meta.resource?.ToString());
return sb.ToString();
}
我希望它如何工作
private async Task<string> BuildTemplate(string template, dynamic meta)
{
var sb = new StringBuilder(template);
var placeholders = await _placeholders.GetAllAsync();
foreach (var placeholder in placeholders)
{
// when using reflection I still get a string like "meta.receiver" instead of meta.receiver, like the object.
// in other words, the sb.Replace methods gives the same result.
//sb.Replace(placeholder.Key, placeholder.Value.GetType().GetField(placeholder.Value).GetValue(placeholder.Value));
sb.Replace(placeholder.Key, placeholder.Value);
}
return sb.ToString();
}
我认为这可能是解决这个问题的更好方法。请告诉我!
解决方案
我们在开发过程中已经解决了类似的问题。
我们创建了扩展来格式化任何对象。
请查看我们的源代码:
public static string FormatWith(this string format, object source, bool escape = false)
{
return FormatWith(format, null, source, escape);
}
public static string FormatWith(this string format, IFormatProvider provider, object source, bool escape = false)
{
if (format == null)
throw new ArgumentNullException("format");
List<object> values = new List<object>();
var rewrittenFormat = Regex.Replace(format,
@"(?<start>\{)+(?<property>[\w\.\[\]]+)(?<format>:[^}]+)?(?<end>\})+",
delegate(Match m)
{
var startGroup = m.Groups["start"];
var propertyGroup = m.Groups["property"];
var formatGroup = m.Groups["format"];
var endGroup = m.Groups["end"];
var value = propertyGroup.Value == "0"
? source
: Eval(source, propertyGroup.Value);
if (escape && value != null)
{
value = XmlEscape(JsonEscape(value.ToString()));
}
values.Add(value);
var openings = startGroup.Captures.Count;
var closings = endGroup.Captures.Count;
return openings > closings || openings%2 == 0
? m.Value
: new string('{', openings) + (values.Count - 1) + formatGroup.Value
+ new string('}', closings);
},
RegexOptions.Compiled | RegexOptions.CultureInvariant | RegexOptions.IgnoreCase);
return string.Format(provider, rewrittenFormat, values.ToArray());
}
private static object Eval(object source, string expression)
{
try
{
return DataBinder.Eval(source, expression);
}
catch (HttpException e)
{
throw new FormatException(null, e);
}
}
用法很简单:
var body = "[{Name}] {Description} (<a href='{Link}'>See More</a>)";
var model = new { Name="name", Link="localhost", Description="" };
var result = body.FormatWith(model);
推荐阅读
- mongodb - Mongo:多个 $inc 在 Mongoose 中不起作用
- java - (在原地为数字添加值) + 运算符如何在 java 中工作?
- c++ - 如何在 C++ 中将字符串传递给 gets_s()?
- sympy - 在涉及 int() 的函数上使用 sympy.integrate
- r - 创建带有侧向箭头的美人鱼图
- asp.net-core - 如何在 asp core 3.1 中获取客户端 IP?
- python-3.x - 如何在 1 个 CSV 文件中组合文本和熊猫数据框
- image - 在 ChartJS 图表区域中添加图像作为背景 [不是画布]
- django - 如何使用序列化方法字段处理主键相关数据
- javascript - 何时在动作创建者中使用调度?