RazorEngine.NetCore 相見恨晚,它讓我徹底放棄了T4模板

noert發表於2022-01-06

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

讓我們看看效果

 

 

 然後儲存在本地就大功告成了,我集中放到了一個資料夾,這樣方便直接拷貝替換(整合到專案可以直接替換,但是有覆蓋風險,沒敢),後面看看最後的成果。

 

 



 

相關文章