Razorengine 的 The same key was already used for another template

使用razorengine 生成代码 生成报表方便。但是一旦修改模板文件cshtml,就会报错 The same key was already used for another template。查了很多资料,发现问题没那么简单。

参考 https://github.com/Antaris/RazorEngine/issues/232

总结原因如下:
主要是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;
        }

        /// 
        /// work arounf MD5 has for razorengine caching.
        /// 
        /// 
        /// 
        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模板,只能重启程序。

你可能感兴趣的:(Razorengine 的 The same key was already used for another template)