ABPHelper.CLI及其依赖项简单介绍
圖片gif無法查看,請查看原文至博客園查看詳情。
目錄
目錄
ABPHelper.CLI
Scriban
通過Microsoft.Extensions.FileProviders.Embedded獲取嵌入資源
通過靜態方法獲取文件內容
使用Microsoft.Extensions.FileProviders.Physical獲取文件內容
Microsoft.CodeAnalysis.CSharp
Humanizer.Core
System.CommandLine
Elsa
入門
使用指南
命令行
技術點如下
AbpHelper.GUI
ABPHelper.CLI
AbpHelper is a tool that helps you with developing Abp vNext applications.
https://github.com/EasyAbp/AbpHelper.CLI
命令行CLI實現ABP VNEXT中CRUD代碼的生成,用戶只需要創建一個實體類,即可生成該表的CRUD,并添加到項目中。
使用前請確保備份您的源文件!
入門
安裝 AbpHelper CLI 工具
dotnet tool install EasyAbp.AbpHelper -g
如果您更喜歡GUI,那么還有一個UI工具:?AbpHelper.GUI
如果以前安裝過,請使用以下命令更新它:
dotnet tool update EasyAbp.AbpHelper -g
使用?ABP CLI?創建一個ABP 應用
abp new MyToDo
創建實體
運行 AbpHelper
abphelper generate crud Todo -d C:\MyTodo
generate crud?是生成CRUD文件的子命令
Todo?指定了我們先前創建的實體名
-d?指定了由ABP CLI創建的ABP項目的根目錄
AbpHelper 將生成所有的CRUD , 甚至包括添加遷移和數據庫更新!
運行這個?DbMigrator?項目去遷移數據庫
啟動你的應用
用默認的管理員帳戶登錄,看到神奇的事發生了!
如果看不到 TODO 菜單,請檢查您的權限并確保授予了TODO相關的權限
使用指南
運行abphelper -h?查看幫助
類似地,您可以使用?-h或--help?選項查看以下每個命令的詳細用法
命令行
generate
為ABP項目生成文件. 使用 'abphelper generate --help' 獲取詳情
crud
根據指定實體生成一組與CRUD相關的文件
abphelper generate crud Todoservice
根據指定的名稱生成服務接口和類文件
abphelper generate service Project -f Projectmethods
Generate service method(s) according to the specified name(s)
根據指定名稱,給service 增加方法
abphelper generate methods Login Logout -s Projectlocalization
Generate localization item(s) according to the specified name(s)
根據指定名稱生成localization 本地化項
abphelper generate localization MyItem1 MyItem2 MyItem3controller
abphelper generate controller TodoGenerate controller class and methods according to the specified service?
技術點如下
Scriban
Microsoft.Extensions.FileProviders.Embedded
Microsoft.CodeAnalysis.CSharp
System.CommandLine
Elsa
Humanizer.Core
如果我們想實現代碼生成器,我們需要解決什么問題呢。
提供.NET接口的模板引擎,比如Razor,Sciban等
模板一般放在文件中,我們需要知道如何讀取這些資源文件,文本文件。
如果我們使用code first,通常需要創建一個實體類,當創建好一個類后,怎么解析出這個類名,屬性,命名空間呢,而不是另外去輸入這些參數。(只需要代碼的路徑)
實體名Name,比如BaseItem
命名空間NameSpace LinCms.Base.BaseItems或Volo.Abp.BaseItems
主鍵類型PrimaryKey,比如是Guid,還是int,還是long
明確有哪些變量,如何控制輸入。
模板的位置TemplatePath :./Templates
根據模板生成的代碼的輸出目錄OutputDirectory :相對路徑 或 絕對路徑?./output?或?D:/code/github/code-scaffolding
Scriban
Scriban是一種快速、強大、安全和輕量級的文本模板語言和.NET引擎,具有解析liquid模板的兼容模式
【翻譯】Scriban是一種快速、強大、安全和輕量級的文本模板語言和.NET引擎,具有解析liquid模板的兼容模式
【翻譯】 Scriban language( 待完成)
【翻譯】Scriban runtime( 待完成)
創建一個xunit測試項目,引入包Sciban
<PackageReference Include="Scriban" Version="3.0.0-alpha.3" />做一個小測試
[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<Doc>{}}".Replace("\r\n", "").Replace(" ", ""), result.Replace("\r\n", "").Replace(" ", ""));}最終生成的效果是
using LinCms.Core.Entities; namespace LinCms.Core.IRepositories {public interface IDocRepository : IAuditBaseRepository<Doc>{} }通過Microsoft.Extensions.FileProviders.Embedded獲取嵌入資源
這是一個嵌入資源Provider,提供嵌入資源的獲取,比如我們寫的Sciban的模板文件。
xunit測試項目引入包
<PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" Version="3.1.6" />創建一個測試類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增加如下一行<GenerateEmbeddedFilesManifest>true</GenerateEmbeddedFilesManifest>
新建目錄Templates,新建文本文件 IRepository.txt,右鍵屬性,生成操作(嵌入的資源),可不選復制到輸出目錄
using LinCms.Core.Entities; namespace LinCms.Core.IRepositories {public interface I{{ entity_ame }}Repository : IAuditBaseRepository<{{ entity_ame }}>{} }可修改csproject文件設置Templates目錄下都是嵌入式資源
<ItemGroup><EmbeddedResource Include="Templates\**\**" /> </ItemGroup>在測試方法中,通過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獲取文件內容
引用包
<PackageReference Include="Microsoft.Extensions.FileProviders.Physical" Version="3.1.6" /> [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,引入包
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.6.0" />這個包是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
你也可以使用諸如Entity<Guid>,即一個泛型的實體類即可。
public class Entity<T> {public T Id { get; set; } } [Fact] public void GetNamespace() {string text = @" namespace LinCms.Books {public class Book : FullAduitEntity<Guid>{public string Author { get; set; }public string Title { get; set; }} }";SyntaxTree tree = CSharpSyntaxTree.ParseText(text);CompilationUnitSyntax root = tree.GetCompilationUnitRoot();var @namespace = root.DescendantNodes().OfType<NamespaceDeclarationSyntax>().Single().Name.ToString();output.WriteLine(@namespace); }獲取類名.className為Book
ClassDeclarationSyntax classDeclarationSyntax = root.DescendantNodes().OfType<ClassDeclarationSyntax>().Single(); string className = classDeclarationSyntax.Identifier.ToString();獲取父類baseType為FullAduitEntity 主鍵類型primaryKey值為Guid
BaseListSyntax baseList = classDeclarationSyntax.BaseList!; var genericNameSyntax = baseList.DescendantNodes().OfType<SimpleBaseTypeSyntax>().First(node => !node.ToFullString().StartsWith("I")) // Not interface.DescendantNodes().OfType<GenericNameSyntax>().FirstOrDefault();string baseType; string? primaryKey; if (genericNameSyntax == null) {// No generic parameter -> Entity with Composite KeysbaseType = baseList.DescendantNodes().OfType<SimpleBaseTypeSyntax>().Single().Type.ToString();primaryKey = "long"; } else {// Normal entitybaseType = genericNameSyntax.Identifier.ToString();primaryKey = genericNameSyntax.DescendantNodes().OfType<TypeArgumentListSyntax>().Single().Arguments[0].ToString(); }獲取該類的屬性集合。
var properties = root.DescendantNodes().OfType<PropertyDeclarationSyntax>().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查看局部變量。
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; }/// <summary>/// 復數/// </summary>public string NamePluralized => Name.Pluralize();/// <summary>/// 首字母小寫/// </summary>public string NameCamelize => Name.Camelize();/// <summary>/// 小寫+復數/// </summary>public string NameCamelizePluralized => Name.Camelize().Pluralize();}System.CommandLine
https://github.com/dotnet/command-line-api
System.CommandLine是一組用于構建命令行應用程序的庫,包括解析,調用和渲染。
他能簡化命令行參數的處理,幫助我們構建自己的CLI。
對于代碼生成器,不要是必須的。
Elsa
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。我們也能實現代碼生成器,幫助改善公司及自己已有項目的開發流程。
總結
以上是生活随笔為你收集整理的ABPHelper.CLI及其依赖项简单介绍的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 7月30日 举办专注于微服务的.NET
- 下一篇: JWT是个什么鬼?