技术思绪摘录旅行
RazorEngine是一个开源的项目,它的基础就是ASP.NET MVC的Razor,它帮助我们渲染模板,我们使用其渲染后的结果内容,对于使用过ASP.NET MVC Razor视图引擎的开发者,已经领略过它的灵活性和易用性,而RazorEngine让我们无缝衔接。

1、引入RazorEngine组件

2、编写模板管理类TemplateManager.cs

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using RazorEngine;
using RazorEngine.Configuration;
using RazorEngine.Templating;

namespace GhisCodeGenerator.Comm
{
    /// <summary>
    /// 模板管理器
    /// </summary>
    public static class TemplateManager
    {
        public static string TemplateRootPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Tpls");

        public static Dictionary<string, string> TemplateDic = new Dictionary<string, string>();

        public static void Init()
        {
            //生成tpl文件
            //CsHtmlToTpl();

            var templateServiceConfiguration = new TemplateServiceConfiguration();
            //这里可以类引用解决器
            templateServiceConfiguration.ReferenceResolver = new CustomReferenceResolver();
            Engine.Razor = RazorEngineService.Create(templateServiceConfiguration);
        }

        /// <summary>
        /// Cses the HTML to TPL.
        /// </summary>
        private static void CsHtmlToTpl()
        {
            var root = new DirectoryInfo(TemplateRootPath);
            var fileInfos = root.GetFiles("*.cshtml").ToList();

            foreach (var directory in root.GetDirectories())
            {
                fileInfos.AddRange(directory.GetFiles("*.cshtml"));
            }
            fileInfos.ForEach(x =>
            {
                File.Copy(x.FullName, x.FullName.Replace(".cshtml", ".tpl"), true);
            });
        }

        /// <summary>
        /// Creates the directory and remove file.
        /// </summary>
        /// <param name="filepath">The filepath.</param>
        public static void CreateDirectoryAndRemoveFile(string filepath)
        {
            var dir = Path.GetDirectoryName(filepath);
            if (!Directory.Exists(dir))
            {
                Directory.CreateDirectory(dir);
            }

            if (File.Exists(filepath))
            {
                File.Delete(filepath);
            }
        }

        
        /// <summary>
        /// 获取所有模板
        /// </summary>
        public static List<string> GetTpls()
        {
            var root = new DirectoryInfo(TemplateRootPath);
            var fileInfos = root.GetFiles("*.cshtml").ToList();

            foreach (var directory in root.GetDirectories())
            {
                fileInfos.AddRange(directory.GetFiles("*.cshtml"));
            }
            List<string> tpls = new List<string>();
            foreach (FileInfo fileInfo in fileInfos)
            {
                tpls.Add(fileInfo.FullName.Replace(TemplateRootPath, "").TrimStart('\\'));
            }
            return tpls;
        }


        /// <summary>
        /// Loads the templates.
        /// </summary>
        /// <param name="clearCache">if set to <c>true</c> [clear cache].</param>
        public static void LoadTemplates(bool clearCache = false)
        {
            if (clearCache)
            {
                TemplateDic.Clear();
            }
            LoadTemplates(new DirectoryInfo(TemplateRootPath));
        }

        /// <summary>
        /// Loads the templates.
        /// </summary>
        /// <param name="directoryInfo">The directory information.</param>
        private static void LoadTemplates(DirectoryInfo directoryInfo)
        {
            if (!directoryInfo.Exists)
            {
                return;
            }

            var fileInfos = directoryInfo.GetFiles("*.cshtml");

            foreach (var fileInfo in fileInfos)
            {
                LoadTemplate(fileInfo.FullName.Replace(TemplateRootPath, ""));
            }

            foreach (var directory in directoryInfo.GetDirectories())
            {
                LoadTemplates(directory);
            }
        }

        /// <summary>
        /// 加载模板
        /// </summary>
        /// <param name="relativePath">The relative path.</param>
        public static void LoadTemplate(string relativePath)
        {
            relativePath = relativePath.TrimStart('\\');
            //打开并且读取模板
            string template = File.ReadAllText(Path.Combine(TemplateRootPath, relativePath));
            //添加模板
            Engine.Razor.AddTemplate(relativePath, template);
            //编译模板
            Engine.Razor.Compile(relativePath, null);

            if (!TemplateDic.ContainsKey(relativePath))
            {
                TemplateDic.Add(relativePath, "");
            }
            else
            {
                TemplateDic[relativePath] = "";
            }
        }

        /// <summary>
        /// 运行模板
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="templatePath">The template path.</param>
        /// <param name="model">The model.</param>
        /// <returns></returns>
        public static string Run<T>(string templatePath, T model)
        {
            return Engine.Razor.Run(templatePath, null, model);
        }
        public static string Run<T>(int idx, T model)
        {
            return Engine.Razor.Run(TemplateDic.Keys.ToList()[idx], null, model);
        }
    }
}

编写CustomReferenceResolver.cs

using System.Collections.Generic;
using System.IO;
using System.Linq;
using RazorEngine.Compilation;
using RazorEngine.Compilation.ReferenceResolver;

namespace GhisCodeGenerator.Comm
{
    public class CustomReferenceResolver : IReferenceResolver
    {
        /// <summary>
        /// <see cref="CompilerServiceBase.DynamicTemplateNamespace"/>
        /// </summary>
        protected internal const string DynamicTemplateNamespace = "CompiledRazorTemplates.Dynamic";
        /// <summary>
        /// See <see cref="IReferenceResolver.GetReferences"/>
        /// </summary>
        /// <param name="context"></param>
        /// <param name="includeAssemblies"></param>
        /// <returns></returns>
        public IEnumerable<CompilerReference> GetReferences(TypeContext context = null, IEnumerable<CompilerReference> includeAssemblies = null)
        {
            return CompilerServicesUtility
                .GetLoadedAssemblies()
                .Where(a => !a.IsDynamic && File.Exists(a.Location) && !a.Location.Contains(DynamicTemplateNamespace))
                .GroupBy(a => a.GetName().Name).Select(grp => grp.First(y => y.GetName().Version == grp.Max(x => x.GetName().Version))) // only select distinct assemblies based on FullName to avoid loading duplicate assemblies
                .Select(a => CompilerReference.From(a))
                .Concat(includeAssemblies ?? Enumerable.Empty<CompilerReference>());
        }
    }
}

3、准备模板文件demo.cshtml

image.png

文件为什么是cshtml?因为我想让我编写模板的时候,能语法高亮,能有智能提示,能和mvc开发绑定数据一样去开发

注意:需要将我们的模板文件(.cshtml)属性调整为内容,阻止编译,我们要像使用txt一样去使用他们

image.png

4、模板是否正确,是否能编译通过,需要我们初始化,不然后期生成代码的时候,会非常慢

所以需要在程序启动时候去初始化

using System;
using System.Windows.Forms;
using GhisCodeGenerator.Comm;

namespace GhisCodeGenerator
{
    static class Program
    {
        /// <summary>
        /// 应用程序的主入口点。
        /// </summary>
        [STAThread]
        static void Main()
        {
            TemplateManager.Init();//这里
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Frm_Main());
        }
    }
}

这样做,会导致我们的程序启动的时候,稍微慢了一点点,但是为了后期使用非常流畅,还是值得

到这里,我们的准备工作已经完成,接下来就是运用了

5、运用,即点击生成代码按钮之后该干的事情

List<string> tpls = TemplateManager.GetTpls();//得到所有模板
for (var i = 0; i < tpls.Count; i++)
{ //一次处理所有模板
    var codeStr = TemplateManager.Run(tpls[i], ClassInfo);//将模板和razor绑定的数据传过去,这个classInfo就是渲染数据
    var path = Path.Combine(savepath, ClassInfo.OutPutFileName);//根据回写的地址输出文件,这里决定了输出文件位置和后缀名
    TemplateManager.CreateDirectoryAndRemoveFile(path);//创建文件夹
    using (var stream = new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write)) //写入文件
    {
        using (var writer = new StreamWriter(stream, Encoding.UTF8))
        {
            writer.Write(codeStr);
        }
    }
}

模板一般都是很多个,而且生成的代码需要存放在不同的文件夹,文件名称和后缀也不一样,所以我们把FileName放在模板中来赋值

最后生成的文件输出的位置和后缀名,完全取决于模板文件中的OutPutFileName变量

CarsonIT 微信扫码关注公众号 策略、创意、技术

留下您的脚步

 

最近评论

查看更多>>

精选推荐

阅读排行

友情打赏

请打开您的微信,扫一扫