2

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

 2 years ago
source link: https://www.cnblogs.com/noert/p/15769857.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

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("生成成功");
        }

让我们看看效果

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


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK