使用razorengine 生成代码 生成报表方便。但是一旦修改模板文件cshtml,就会报错 The same key was already used for another template。查了很多资料,发现问题没那么简单。
总结原因如下:
主要是clr机制的问题:
1 无法卸载程序集
2 其他动态编译方法比如说 DynamicAssemblies ,但是不能使用它
3 没有一个好的缓存方式。
就是说,一旦编译razor模板运行时候,模板也会编译到程序集里,但是这个模板不能修改或删除,相当于修改程序集,这个是clr不允许的事情,除非重新编译,那样相当于重启程序项目了。
razor内部机制会有个缓存,如果模板名称没有在这个缓存中,会再次编译添加到程序集里,否则会直接用这个缓存模板。那么我改模板时候,动态添加模板名称不就行了? 但这样会导致另一个问题,如果过多的加入模板(比如说1w个),会导致程序集庞大,运行时候会因为模板在内存过多导致内存溢出。
可能有人会说,我实现个缓存机制,如果少次数更改模板,来动态创建模板名称是否可以行。这个是可以的,但是达到量变还是会导致上面内存溢出的问题。个人感觉这个方式不是很完美,这个缓存方式有点复杂而且过于鸡肋。
如果有人想用这个缓存方式, 可以参考如下代码:
// 参考 https://github.com/Antaris/RazorEngine/issues/232
public static string RazorRender(Object info, string razorTempl, string templateKey, Boolean debugMode = false)
{
var result = "";
try
{
var service = (IRazorEngineService)HttpContext.Current.Application.Get("NBrightBuyIRazorEngineService");
if (service == null)
{
// do razor test
var config = new TemplateServiceConfiguration();
config.Debug = debugMode;
config.BaseTemplateType = typeof(NBrightBuyRazorTokens<>);
service = RazorEngineService.Create(config);
HttpContext.Current.Application.Set("NBrightBuyIRazorEngineService", service);
}
Engine.Razor = service;
var israzorCached = Utils.GetCache("nbrightbuyrzcache_" + templateKey); // get a cache flag for razor compile.
if (israzorCached == null || (string)israzorCached != razorTempl)
{
result = Engine.Razor.RunCompile(razorTempl, GetMd5Hash(razorTempl), null, info);
Utils.SetCache("nbrightbuyrzcache_" + templateKey, razorTempl);
}
else
{
result = Engine.Razor.Run(GetMd5Hash(razorTempl), null, info);
}
}
catch (Exception ex)
{
result = ex.ToString();
}
return result;
}
/// <summary>
/// work arounf MD5 has for razorengine caching.
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
private static string GetMd5Hash(string input)
{
var md5 = MD5.Create();
var inputBytes = System.Text.Encoding.ASCII.GetBytes(input);
var hash = md5.ComputeHash(inputBytes);
var sb = new StringBuilder();
foreach (byte t in hash)
{
sb.Append(t.ToString("X2"));
}
return sb.ToString();
}
总的来说,改了razor模板,只能重启程序。
网友评论