RazorEngine.NetCore 相见恨晚,它让我彻底放弃了T4模板

   在dbfrist 时代,用T4模板生成代码,貌似还没有感觉到别扭。但是到了codefrist 后,我想要实体生成生成备注,我就得想方设法的去把备注弄到数据库,然后 还要处理模型中类型像枚举这种属性,渐渐的感觉到了吃力。要不换种方式吧,想着去反射实体,但是用T4去处理这种反射,还是感觉到有点吃力,就觉得能不能直接像我们直接写后台程序一样去解析,后面想到了Razor 引擎,经过进一步的了解,发现大神封装了一个组件 RazorEngine.NetCore,他很好的解决了我的问题。
   下面就让我们来了解下这个组件吧,先让我们得到这个组件如图

 

 

 

  有了组件,我们先去编写对应自己业务的模板先吧,就比如我这个我创建一个AddDto,我创建的模板如下:

@*@model LazyBoy.Dtos.DbTableDto*@
@using LazyBoy.Dtos;
@using LazyBoy.Extensions;
@using LazyBoy.Enums;

using System;
using AutoMapper;
using Domain.Models.Enum;
using Domain.Models.Entitys;
using Sy.ExpressionBuilder.Modules;
using System.ComponentModel.DataAnnotations;
using Sy.ExpressionBuilder.Modules;
using Domain.Models.Entitys;
using AutoMapper;
using Domain.Models.Enum;


namespace @GeneratorConfig.DtoNameSpaceName
{
    /// <summary>
    /// @Model.Remark
    ///</summary>
    [AutoMap(typeof(@(@StringExtension.FirstToUp(@Model.TableName))), ReverseMap = true)]
    public partial class  BaseAdd@(@StringExtension.FirstToUp(@Model.TableName))Dto
    {
    @foreach (var pm in @Model.DbColumns)
    {
    @if ((pm.ColumnName.ToLower() != "id"&&(pm.PropertyType == EnumPropertyType.Field || pm.PropertyType == EnumPropertyType.Enum) ))
    {

        @:/// <summary>
        @:/// @pm.Remark
        @:/// </summary>
        @:[Display(Name ="@(pm.Remark)")]
        @if (pm.IsRequired)
        {
        @:[Required(ErrorMessage ="@(pm.Remark)不能为空")]
        }
        @if (pm.StringLengthMax!=0)
        {
        @:[StringLength(@(pm.StringLengthMax), MinimumLength =@(pm.StringLengthMin), ErrorMessage = "@(pm.Remark)的长度为{2}至{1}个字符")]
        }
        else if (pm.StringLengthMin!=0)
        {
        @:[StringLength(@(pm.StringLengthMin), ErrorMessage = "@(pm.Remark)的长度至少为{1}个字符")]
        }
        @if(pm.RangeMax!=null)
        {
        @:[Range(@(pm.RangeMax), MinimumLength =@(pm.RangeMin), ErrorMessage="@(pm.Remark)的范围在{1}至{2}之间")]
        }
        @if(pm.Regular!=null)
        {
        @:[RegularExpression("@(pm.Regular)", ErrorMessage = "@(pm.Remark)@(pm.ErrorMessage)")]
        }
        @:public virtual @pm.ColumnType @(pm.IsNullable==true?"?":"")  @StringExtension.FirstToUp(pm.ColumnName) { get;set;}

    }
    }
    }
}

 温馨提示,代码头部这个引用后台返回的实体的这个,我们编写的时候放出来,这样我们就可以像写Razor 视图一样了,后面生成代码的注释掉。

 有了模板后,我们就可以生成我们要的AddDto了,在起始项(.net6 直接在Program) 添加并且编译我们的模板,如下:
 

            //打开并且读取模板
            string template = File.ReadAllText(filePath); //CreateDto.cshtml
            var nameKey = templateName.ToLower().Replace(".cshtml", "");
            //添加模板
            Engine.Razor.AddTemplate(nameKey, template);
            //编译模板
            Engine.Razor.Compile(nameKey, null);

 然后我们根据反射拿到实体类库的解析类,传给引擎就好了
 

 var result = Engine.Razor.Run(templateName.ToLower(), null, item);
templateName.ToLower(),对应我们添加模板的key,item对应单个实体的解析类,下面给出我的示例代码:
 /// <summary>
        /// 创建所有类型Dto
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        public IResultModel CreateAllBaseDto()
        {
            CreateDtoManager dtoManager = new CreateDtoManager();
            var dbTables = dtoManager.GetDbTable();
            var dtoPath = _configuration.GetSection("DbConfigInfo")["CodeResourcePath"];
            var templateNames = _configuration.GetSection("DbConfigInfo")["BaseDtoTemplateName"];
            foreach (var item in dbTables)
            {
                foreach (var templateName in templateNames?.Split(',').ToList())
                {
                    var result = Engine.Razor.Run(templateName.ToLower(), null, item);
                    var filePath = $"{dtoPath}/BaseDtos/{item.SchemaName.GetPath('_')}/{item.TableName}s";
                    var prefix = "";
                    if (templateName.Contains("add", StringComparison.OrdinalIgnoreCase))
                        prefix = "Add";
                    if (templateName.Contains("all", StringComparison.OrdinalIgnoreCase))
                        prefix = "All";
                    if (templateName.Contains("edit", StringComparison.OrdinalIgnoreCase))
                        prefix = "Edit";
                    string fileName = filePath + "\\" + $"{prefix}Base{item.TableName}Dto.cs";

                    //保存文件
                    FileHelper.Save(fileName, result);
                }
            }
            return ResultTo.Success("生成成功");
        }

让我们看看效果

 

 

 然后保存在本地就大功告成了,我集中放到了一个文件夹,这样方便直接拷贝替换(集成到项目可以直接替换,但是有覆盖风险,没敢),后面看看最后的成果。