1. 程式人生 > >ABPHelper.CLI及其依賴項簡單介紹

ABPHelper.CLI及其依賴項簡單介紹

## 目錄 - [目錄](#目錄) - [ABPHelper.CLI](#abphelpercli) - [入門](#入門) - [使用指南](#使用指南) - [命令列](#命令列) - [技術點如下](#技術點如下) - [Scriban](#scriban) - [通過Microsoft.Extensions.FileProviders.Embedded獲取嵌入資源](#通過microsoftextensionsfileprovidersembedded獲取嵌入資源) - [通過靜態方法獲取檔案內容](#通過靜態方法獲取檔案內容) - [使用Microsoft.Extensions.FileProviders.Physical獲取檔案內容](#使用microsoftextensionsfileprovidersphysical獲取檔案內容) - [Microsoft.CodeAnalysis.CSharp](#microsoftcodeanalysiscsharp) - [Humanizer.Core](#humanizercore) - [System.CommandLine](#systemcommandline) - [Elsa](#elsa) - [AbpHelper.GUI](#abphelpergui)
## ABPHelper.CLI - AbpHelper is a tool that helps you with developing Abp vNext applications. - [https://github.com/EasyAbp/AbpHelper.CLI](https://github.com/EasyAbp/AbpHelper.CLI) 命令列CLI實現[ABP VNEXT](https://github.com/abpframework/abp)中CRUD程式碼的生成,使用者只需要建立一個實體類,即可生成該表的CRUD,並新增到專案中。 **使用前請確保備份您的原始檔!** ### 入門 1. 安裝 AbpHelper CLI 工具 `dotnet tool install EasyAbp.AbpHelper -g` >
如果您更喜歡GUI,那麼還有一個UI工具: [AbpHelper.GUI](https://github.com/EasyAbp/AbpHelper.GUI) 2. 如果以前安裝過,請使用以下命令更新它: `dotnet tool update EasyAbp.AbpHelper -g` 3. 使用 [ABP CLI](https://docs.abp.io/en/abp/latest/CLI) 建立一個ABP 應用 `abp new MyToDo` 4. 建立實體 ``` csharp public class Todo : FullAuditedEntity { public string Content { get; set; } public bool Done { get; set; } } ``` 5. 執行 AbpHelper `abphelper generate crud Todo -d C:\MyTodo` * `generate crud` 是生成CRUD檔案的子命令 * `Todo` 指定了我們先前建立的實體名 * `-d` 指定了由ABP CLI建立的ABP專案的根目錄 AbpHelper 將生成所有的CRUD , 甚至包括新增遷移和資料庫更新! 6. 執行這個 `DbMigrator` 專案去遷移資料庫 7. 啟動你的應用 8. 用預設的管理員帳戶登入,看到神奇的事發生了! ![執行demo](https://pic.downk.cc/item/5f22aaa114195aa594239ad9.png) > 如果看不到 TODO 選單,請檢查您的許可權並確保授予了TODO相關的許可權 ### 使用指南 * 執行`abphelper -h` 檢視幫助 * 類似地,您可以使用 `-h`或`--help` 選項檢視以下每個命令的詳細用法 ### 命令列 * generate 為ABP專案生成檔案. 使用 'abphelper generate --help' 獲取詳情 * crud 根據指定實體生成一組與CRUD相關的檔案 ``` abphelper generate crud Todo ``` ![](https://pic.downk.cc/item/5f22ac5314195aa594242da8.gif) * service 根據指定的名稱生成服務介面和類檔案 ``` abphelper generate service Project -f Projects ``` ![](https://pic.downk.cc/item/5f22ac5314195aa594242db3.gif) * methods Generate service method(s) according to the specified name(s) 根據指定名稱,給service 增加方法 ``` abphelper generate methods Login Logout -s Project ``` ![](https://pic.downk.cc/item/5f22ac5314195aa594242db0.gif) * localization Generate localization item(s) according to the specified name(s) 根據指定名稱生成localization 本地化項 ``` abphelper generate localization MyItem1 MyItem2 MyItem3 ``` ![](https://pic.downk.cc/item/5f22ac5314195aa594242daa.gif) * controller ``` abphelper generate controller Todo ``` Generate controller class and methods according to the specified service ![](https://pic.downk.cc/item/5f22ac5314195aa594242da4.gif) ### 技術點如下 - Scriban - Microsoft.Extensions.FileProviders.Embedded - Microsoft.CodeAnalysis.CSharp - System.CommandLine - Elsa - Humanizer.Core 如果我們想實現程式碼生成器,我們需要解決什麼問題呢。 1. 提供.NET介面的模板引擎,比如Razor,Sciban等 2. 模板一般放在檔案中,我們需要知道如何讀取這些資原始檔,文字檔案。 3. 如果我們使用code first,通常需要建立一個實體類,當建立好一個類後,怎麼解析出這個類名,屬性,名稱空間呢,而不是另外去輸入這些引數。(只需要程式碼的路徑) 1. 實體名Name,比如BaseItem 2. 名稱空間NameSpace LinCms.Base.BaseItems或Volo.Abp.BaseItems 3. 主鍵型別PrimaryKey,比如是Guid,還是int,還是long 4. 明確有哪些變數,如何控制輸入。 1. 模板的位置TemplatePath : ./Templates 2. 根據模板生成的程式碼的輸出目錄OutputDirectory : 相對路徑 或 絕對路徑 **./output** 或 **D:/code/github/code-scaffolding** #### Scriban Scriban是一種快速、強大、安全和輕量級的文字模板語言和.NET引擎,具有解析liquid模板的相容模式 - [【翻譯】Scriban是一種快速、強大、安全和輕量級的文字模板語言和.NET引擎,具有解析liquid模板的相容模式](https://www.cnblogs.com/igeekfan/p/13343331.html) - [【翻譯】 Scriban language( 待完成)]() - [【翻譯】Scriban runtime( 待完成)]() 建立一個xunit測試專案,引入包Sciban ```
``` 做一個小測試 ``` [Fact] public void Test1() { var template = Template.Parse("Hello {{name}}!"); var result = template.Render(new { Name = "World" }); Assert.Equal("Hello World!", result); } ``` ctrl+r ctrl+t 執行測試,正常。 寫一個我們倉儲介面。 ``` [Fact] public void Test9() { var template = Template.Parse(@"using LinCms.Core.Entities; namespace LinCms.Core.IRepositories { public interface I{{ entity_name }}Repository : IAuditBaseRepository<{{ entity_name }}> { } }"); var result = template.Render(new { EntityName = "Doc" }); Assert.Equal(@"using LinCms.Core.Entities; namespace LinCms.Core.IRepositories { public interface IDocRepository : IAuditBaseRepository { } }".Replace("\r\n", "").Replace(" ", ""), result.Replace("\r\n", "").Replace(" ", "")); } ``` 最終生成的效果是 ``` using LinCms.Core.Entities; namespace LinCms.Core.IRepositories { public interface IDocRepository : IAuditBaseRepository { } } ``` #### 通過Microsoft.Extensions.FileProviders.Embedded獲取嵌入資源 這是一個嵌入資源Provider,提供嵌入資源的獲取,比如我們寫的Sciban的模板檔案。 xunit測試專案引入包 ``` ``` 建立一個測試類FileTest ``` [Fact] public void FileProviderTest() { IFileProvider fileProvider = new ManifestEmbeddedFileProvider(Assembly.GetAssembly(typeof(FileTest))); } ``` 出現這個錯 System.InvalidOperationException:“Could not load the embedded file manifest 'Microsoft.Extensions.FileProviders.Embedded.Manifest.xml' for assembly 'OvOv.Test'.” 開啟OvOv.Test.csproject PropertyGroup增加如下一行 **true** 新建目錄Templates,新建文字檔案 IRepository.txt,右鍵屬性,生成操作(嵌入的資源),可不選複製到輸出目錄 ``` using LinCms.Core.Entities; namespace LinCms.Core.IRepositories { public interface I{{ entity_ame }}Repository : IAuditBaseRepository<{{ entity_ame }}> { } } ``` 可修改csproject檔案設定Templates目錄下都是嵌入式資源 ``` ``` 在測試方法中,通過GetFileInfo,得到IFileInfo.通過stream進行讀取文字,並輸出。 ``` private readonly ITestOutputHelper output; public FileTest(ITestOutputHelper output) { this.output = output; } [Fact] public void GetTextTest() { IFileProvider fileProvider = new ManifestEmbeddedFileProvider(Assembly.GetAssembly(typeof(FileTest))); IFileInfo fileInfo = fileProvider.GetFileInfo("./Templates/IRepository.txt"); string text; using (var stream = fileInfo.CreateReadStream()) { using (var streamReader = new StreamReader(stream, Encoding.UTF8, true)) { text = streamReader.ReadToEnd(); } } output.WriteLine(text); } ``` #### 通過靜態方法獲取檔案內容 不用嵌入式資源,需要右鍵檔案 屬性(複製到輸出目錄:如果較新則複製),可不選生成操作 ``` [Fact] public void ReadAllText() { string text = File.ReadAllText("./Templates/IRepository.txt"); output.WriteLine(text); } ``` #### 使用Microsoft.Extensions.FileProviders.Physical獲取檔案內容 引用包 ``` ``` ``` [Theory] [InlineData("./Templates/IRepository.txt")] public void PhysicalFileProviderReadText(string path) { var current = Environment.CurrentDirectory; var fileProvider = new PhysicalFileProvider(current); IFileInfo fileInfo = fileProvider.GetFileInfo(path); string text; using (var stream = fileInfo.CreateReadStream()) { using (var streamReader = new StreamReader(stream, Encoding.UTF8, true)) { text = streamReader.ReadToEnd(); } } output.WriteLine(text); } ``` var current = Environment.CurrentDirectory; 這行程式碼,能得到當前的目錄,因為設定為輸出 ,所以當前目錄下有templates資料夾,並有IRepository.txt ``` "D:\\code\\gitee\\Code\\OvOv.Test\\bin\\Debug\\netcoreapp3.1" ``` #### Microsoft.CodeAnalysis.CSharp 程式碼生成還需要什麼呢,建立一個實體類,根據此實體類生成表的CRUD程式碼。 修改OvOv.Test,引入包 ``` ``` 這個包是[https://github.com/dotnet/roslyn](https://github.com/dotnet/roslyn)的一部分.Roslyn 是.NET編譯器為C#和Visual Basic 提供了豐富的程式碼分析API。 再搞個CodeAnalysisTest測試類。這裡我們有一個字串,他是一個實體類,這個類有一些特點。比如 - 名稱空間namespace - 類名 class - 繼承的父類泛型型別 guid - 有二個屬性,author,title 如下程式碼,通過語法樹,解析出這個字串中的名稱空間,輸出 LinCms.Books。 說明: FullAduitEntity是一個包含CRUD的審計實體類,通常包含七個欄位(建立人,建立時間,修改人,修改時間,是否刪除,刪除人,刪除時間),另外還有一個主鍵。預設是long,具體可檢視此檔案[https://github.com/luoyunchong/lin-cms-dotnetcore/blob/master/src/LinCms.Core/Entities/FullAduitEntity.cs](https://github.com/luoyunchong/lin-cms-dotnetcore/blob/master/src/LinCms.Core/Entities/FullAduitEntity.cs) 你也可以使用諸如**Entity**,即一個泛型的實體類即可。 ``` public class Entity { public T Id { get; set; } } ``` ``` [Fact] public void GetNamespace() { string text = @" namespace LinCms.Books { public class Book : FullAduitEntity { public string Author { get; set; } public string Title { get; set; } } }"; SyntaxTree tree = CSharpSyntaxTree.ParseText(text); CompilationUnitSyntax root = tree.GetCompilationUnitRoot(); var @namespace = root.DescendantNodes().OfType().Single().Name.ToString(); output.WriteLine(@namespace); } ``` 獲取類名.className為Book ``` ClassDeclarationSyntax classDeclarationSyntax = root.DescendantNodes().OfType().Single(); string className = classDeclarationSyntax.Identifier.ToString(); ``` 獲取父類baseType為FullAduitEntity 主鍵型別primaryKey值為Guid ``` BaseListSyntax baseList = classDeclarationSyntax.BaseList!; var genericNameSyntax = baseList.DescendantNodes().OfType() .First(node => !node.ToFullString().StartsWith("I")) // Not interface .DescendantNodes().OfType() .FirstOrDefault(); string baseType; string? primaryKey; if (genericNameSyntax == null) { // No generic parameter -> Entity with Composite Keys baseType = baseList.DescendantNodes().OfType().Single().Type.ToString(); primaryKey = "long"; } else { // Normal entity baseType = genericNameSyntax.Identifier.ToString(); primaryKey = genericNameSyntax.DescendantNodes().OfType().Single().Arguments[0].ToString(); } ``` 獲取該類的屬性集合。 ``` var properties = root.DescendantNodes().OfType() .Select(prop => new PropertyInfo(prop.Type.ToString(), prop.Identifier.ToString())) .ToList(); ``` 其中PropertyInfo是用來儲存屬性集合的實體類 ``` public class PropertyInfo { public string Type { get; } public string Name { get; } public PropertyInfo(string type, string name) { Type = type; Name = name; } } ``` 我們通過debugger檢視區域性變數。 ![](https://pic.downk.cc/item/5f21d24214195aa594c2a365.jpg) #### Humanizer.Core Humanizer可以用來處理strings, enums, dates, times, timespans, numbers and quantities所有的需求。 - https://github.com/Humanizr/Humanizer 當我們寫程式碼時,總避免不了寫複數形式的程式碼,一些特殊的字尾不是直接加**s**就行的。 所以可以用Humanizer來處理這些特殊的變數 - 轉下劃線 Underscore - 複數形式(比如取集合資料時,變數名) Pluralize - 轉小駝峰寫法(比如變數) Camelize - 更多直接看README 通過擴充套件方法生成這些字串。 ``` public class EntityInfo { public EntityInfo(string name) { Name = name; } public string Name { get; } /// /// 複數 /// public string NamePluralized => Name.Pluralize(); /// /// 首字母小寫 /// public string NameCamelize => Name.Camelize(); /// /// 小寫+複數 /// public string NameCamelizePluralized => Name.Camelize().Pluralize(); } ``` #### System.CommandLine - [https://github.com/dotnet/command-line-api](https://github.com/dotnet/command-line-api) System.CommandLine是一組用於構建命令列應用程式的庫,包括解析,呼叫和渲染。 他能簡化命令列引數的處理,幫助我們構建自己的CLI。 對於程式碼生成器,不要是必須的。 #### Elsa - [https://github.com/elsa-workflows/elsa-core](https://github.com/elsa-workflows/elsa-core) Elsa Core是一個工作流庫,可在任何 .NET Core應用程式中執行工作流。工作流可以不僅使用程式碼來定義,也可作為JSON,YAML或XML。 程式碼生成器,流程多,可使用此程式工作流來處理。不是必須的。 ## AbpHelper.GUI - https://github.com/EasyAbp/AbpHelper.GUI - AbpHelper is a tool that helps you with developing Abp vNext applications. It can be used to call ABP CLI, generate code, manage modules, etc. ABP VNEXT的程式碼生成的視覺化介面,使用方式看README就好,不多介紹。 幫助ABP VNext的開發者快速構建單表的CRUD的。 如果你自己研究一下這些類庫的使用方法,特別是Sciban。我們也能實現程式碼生成器,幫助改善公司及自己已有專案的開發