有没有用动态数据替换占位符的好方法? 我尝试加载一个模板,然后用元对象中的数据替换所有 {{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);
}
获取全部异步 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);
你想这样做:
sb.Replace(placeholder.Key, meta.GetType().GetField(placeholder.Value).GetValue(meta).ToString())
而不是meta.reciever
,你的数据库只会存储receiver
这样,数据库中指定的占位符将替换为元对象中的相应值。缺点是你只能用这种方法从元对象中提取值。但是,从我所看到的情况来看,这对您来说似乎不是问题,因此可能无关紧要。
更多说明:您尝试的问题
//sb.Replace(placeholder.Key, placeholder.Value.GetType().GetField(placeholder.Value).GetValue(placeholder.Value));
首先,您尝试获取整个字符串的类型meta.reciever
而不仅仅是meta
部分,但除此之外,似乎没有从字符串到类类型的转换(例如Type.GetType("meta")
(。此外,当您 GetValue 时,没有从字符串到所需对象的转换(不是肯定的。
因为您要动态替换模板中的所有占位符,而无需手动逐个替换它们。所以我认为正则表达式更适合这些事情。
此函数将获取一个要插值的模板和一个要与模板绑定的对象。此功能将自动替换您的占位符,例如 {{RECEIVER_NAME}} 在对象中具有值。 您将需要一个包含要绑定的所有属性的类。在此示例中,按类是 MainInvoiceBind。
public static string Format(string obj,MainInvoiceBind invoice)
{
try
{
return Regex.Replace(obj, @"{{(?<exp>[^}]+)}}", match =>
{
try
{
var p = Expression.Parameter(typeof(MainInvoiceBind), "");
var e = System.Linq.Dynamic.DynamicExpression.ParseLambda(new[] { p }, null, match.Groups["exp"].Value);
return (e.Compile().DynamicInvoke(invoice) ?? "").ToString();
}
catch
{
return "Nill";
}
});
}
catch
{
return string.Empty;
}
}
我在一个项目中实现了这种技术,在这个项目中,我必须从指定的模板动态生成电子邮件。它对我有好处。希望它能解决您的问题。
我将habibs的解决方案更新为更新System.Linq.Dynamic.Core
NuGet包,并进行了一些小的改进。
此函数会自动将占位符(如 {{RECEIVER_NAME}}(替换为对象中的数据。您甚至可以使用一些运算符,因为它使用的是Linq。
public static string Placeholder(string input, object obj)
{
try {
var p = new[] { Expression.Parameter(obj.GetType(), "") };
return Regex.Replace(input, @"{{(?<exp>[^}]+)}}", match => {
try {
return DynamicExpressionParser.ParseLambda(p, null, match.Groups["exp"].Value)
.Compile().DynamicInvoke(obj)?.ToString();
}
catch {
return "(undefined)";
}
});
}
catch {
return "(error)";
}
}
您还可以使多个对象可访问并命名它们。