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,并添加到项目中。

使用前请确保备份您的源文件!

入门

  1. 安装 AbpHelper CLI 工具

    dotnet tool install EasyAbp.AbpHelper -g

如果您更喜欢GUI,那么还有一个UI工具: AbpHelper.GUI

  1. 如果以前安装过,请使用以下命令更新它:

    dotnet tool update EasyAbp.AbpHelper -g

  2. 使用 ABP CLI 创建一个ABP 应用

    abp new MyToDo

  3. 创建实体

public class Todo : FullAuditedEntity<Guid>
{public string Content { get; set; }public bool Done { get; set; }
}
  1. 运行 AbpHelper

abphelper generate crud Todo -d C:\MyTodo

  • generate crud 是生成CRUD文件的子命令

  • Todo 指定了我们先前创建的实体名

  • -d 指定了由ABP CLI创建的ABP项目的根目录

AbpHelper 将生成所有的CRUD , 甚至包括添加迁移和数据库更新!

  1. 运行这个 DbMigrator 项目去迁移数据库

  2. 启动你的应用

  3. 用默认的管理员帐户登录,看到神奇的事发生了!

如果看不到 TODO 菜单,请检查您的权限并确保授予了TODO相关的权限

使用指南

  • 运行abphelper -h 查看帮助

  • 类似地,您可以使用 -h--help 选项查看以下每个命令的详细用法

命令行

  • generate

    为ABP项目生成文件. 使用 'abphelper generate --help' 获取详情

    • crud

      根据指定实体生成一组与CRUD相关的文件

      abphelper generate crud Todo
    • service

      根据指定的名称生成服务接口和类文件

      abphelper generate service Project -f Project
    • methods

      Generate service method(s) according to the specified name(s)

      根据指定名称,给service 增加方法

      abphelper generate methods Login Logout -s Project
    • localization

      Generate localization item(s) according to the specified name(s)

      根据指定名称生成localization 本地化项

      abphelper generate localization MyItem1 MyItem2 MyItem3
    • controller

      abphelper generate controller Todo
      

      Generate controller class and methods according to the specified service 

技术点如下

  • 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模板的兼容模式

  • 【翻译】 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。我们也能实现代码生成器,帮助改善公司及自己已有项目的开发流程。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/308555.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[RabbitMQ]整合SpringBoot

整合SpringBoot 创建项目 引入依赖 <dependencies><!--RabbitMQ 依赖--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId></dependency><dependency><…

mysql 固定符号分列显示_MySql中指定符号分割并分行展示

1.涉及到的函数三个&#xff1a;1.1 REPLACE(value,str1,str2)用法规则&#xff1a;使用str2替换掉value中的所有的str1;SELECT REPLACE(我来了,来,走)执行结果如下&#xff1a;1.2 LENGTH(str)用法规则&#xff1a;获取字符串的长度&#xff0c;使用 uft8(UNICODE 的一种变长字…

C++中 Map的了解与基本用法(代码演示+自我总结+map中一对多的用法)

C中 map的了解与基本用法&#xff08;代码演示&#xff09; 一&#xff1a;map的基本认识 Map是STL的一个关联容器&#xff0c;它提供一对一&#xff08;其中第一个可以称为关键字&#xff0c;每个关键字只能在map中出现一次&#xff0c;第二个可能称为该关键字的值&#xff…

[Redis6]跳跃表(跳表)

跳跃表(跳表) 简介 有序集合在生活中比较常见&#xff0c;例如根据成绩对学生排名&#xff0c;根据得分对玩家排名等。对于有序集合的底层实现&#xff0c;可以用数组、平衡树、链表等。数组不便元素的插入、删除&#xff1b;平衡树或红黑树虽然效率高但结构复杂&#xff1b;…

ASP.NET Core中的响应压缩

介绍响应压缩技术是目前Web开发领域中比较常用的技术&#xff0c;在带宽资源受限的情况下&#xff0c;使用压缩技术是提升带宽负载的首选方案。我们熟悉的Web服务器&#xff0c;比如IIS、Tomcat、Nginx、Apache等都可以使用压缩技术&#xff0c;常用的压缩类型包括Brotli、Gzip…

7-14 电话聊天狂人 (25 分)map做法 + 详解 + 思路分析

7-14 电话聊天狂人 (25 分)map做法 1&#xff1a;题目 给定大量手机用户通话记录&#xff0c;找出其中通话次数最多的聊天狂人。 输入格式: 输入首先给出正整数N&#xff08;≤10 ​5 ​​ &#xff09;&#xff0c;为通话记录条数。随后N行&#xff0c;每行给出一条通话记录…

[Redis6]配置文件详解

配置文件 单位 配置大小单位,开头定义了一些基本的度量单位&#xff0c;只支持bytes&#xff0c;不支持bit 大小写不敏感 INCLUDES包括 类似jsp中的include&#xff0c;多实例的情况可以把公用的配置文件提取出来 网络相关配置 bind 默认情况bind127.0.0.1只能接受本机的…

JWT是个什么鬼?

【答疑解惑】| 作者 / Edison Zhou这是恰童鞋骚年的第269篇原创内容前面一篇我们了解了微服务安全认证架构是如何演进而来的&#xff0c;但是发现v2.5架构仍然较重&#xff0c;有没有轻量级一点的方法呢&#xff1f;其实业界早已有了实践&#xff0c;它就是基于JWT的安全认证架…

[Redis6]发布和订阅

Redis6的发布和订阅 什么是发布和订阅 Redis 发布订阅 (pub/sub) 是一种消息通信模式&#xff1a;发送者 (pub) 发送消息&#xff0c;订阅者 (sub) 接收消息。 Redis 客户端可以订阅任意数量的频道。 发布订阅命令行实现 打开一个客户端订阅channel1 打开另一个客户端&…

mysql innodb log_教你如何理解mysql中的innoDB log

前言:之前一直弄不清楚mysql里面bin log和innodb log文件的区别&#xff0c;在脑子里面一直有个疑问binlog日志文件已经可以用来进行数据库的日志备份恢复了&#xff0c;怎么又多了一个redo log文件了。相信也有很多人有这个疑惑&#xff0c;现在把整个过程文档整理出来&#x…

微服务框架Demo.MicroServer运行手册

一.背景说明&#xff1a;之前分享过一个微服务开发框架&#xff0c; “分享一个集成.NET CoreSwaggerConsulPollyOcelotIdentityServer4ExceptionlessApolloSkyWalking的微服务开发框架”&#xff0c;前两天在Github上收到一个Issues&#xff0c;是想我这边提供下完整的运行文档…

[Redis6]新数据类型_Bitmaps

Bitmaps 简介 现代计算机用二进制&#xff08;位&#xff09; 作为信息的基础单位&#xff0c; 1个字节等于8位&#xff0c; 例如“abc”字符串是由3个字节组成&#xff0c; 但实际在计算机存储时将其用二进制表示&#xff0c; “abc”分别对应的ASCII码分别是97、 98、 99&a…

mysql qps如何查看_一款查看mysql QPS的脚本

本脚本黏贴就可以使用绝对不坑人&#xff01;&#xff01;&#xff01;(此脚本来源如一位大神网友)执行效果&#xff1a;脚本&#xff1a;#!/bin/bashPWEqipay20150504mysqladmin -P3306 -uroot -p$PW -r -i 1 ext |\awk -F"|" \"BEGIN{ count0; }"\{ if($…

.Net Core 自定义配置源从配置中心读取配置

配置&#xff0c;几乎所有的应用程序都离不开它。.Net Framework时代我们使用App.config、Web.config&#xff0c;到了.Net Core的时代我们使用appsettings.json&#xff0c;这些我们再熟悉不过了。然而到了容器化、微服务的时代&#xff0c;这些本地文件配置有的时候就不太合适…

[Redis6]Bitmaps与set对比

Bitmaps与set对比 但Bitmaps并不是万金油&#xff0c; 假如该网站每天的独立访问用户很少&#xff0c; 例如只有10万&#xff08;大量的僵尸用户&#xff09; &#xff0c; 那么两者的对比如下表所示&#xff0c; 很显然&#xff0c; 这时候使用Bitmaps就不太合适了&#xff0c…

MySQL分布式ID_分布式唯一ID系列(3)——数据库自增ID机制适合做分布式ID吗

数据库自增ID机制原理介绍在分布式里面&#xff0c;数据库的自增ID机制的主要原理是&#xff1a;数据库自增ID和mysql数据库的replace_into()函数实现的。这里的replace数据库自增ID和mysql数据库的replace_into()函数实现的。这里的replace into跟insert功能类似&#xff0c;不…

7-15 QQ帐户的申请与登陆 (25 分)(map做法+思路分析)

一&#xff1a;题目 实现QQ新帐户申请和老帐户登陆的简化版功能。最大挑战是&#xff1a;据说现在的QQ号码已经有10位数了。 输入格式: 输入首先给出一个正整数N&#xff08;≤10 ​5 ​​ &#xff09;&#xff0c;随后给出N行指令。每行指令的格式为&#xff1a;“命令符&a…

[Redis6]新数据类型_HyperLogLog

HyperLogLog 简介 在工作当中&#xff0c;我们经常会遇到与统计相关的功能需求&#xff0c;比如统计网站PV&#xff08;PageView页面访问量&#xff09;,可以使用Redis的incr、incrby轻松实现。 但像UV&#xff08;UniqueVisitor&#xff0c;独立访客&#xff09;、独立IP数…

每天都在支付,你真的了解信息流和资金流?

作为一个财务类的产品经理&#xff0c;除了每天被财务“虐待”千百遍&#xff0c;还需要对整个资金流向很清楚&#xff1a;钱给谁&#xff0c;怎么给&#xff0c;怎么做逆向流程&#xff0c;谁参与容错等。财务很在意资金的流转安全&#xff0c;但又极不愿意花时间关注它。诸如…

mysql改表字段类型导致数据丢失_故障分析 | 记一次 MySQL 主从双写导致的数据丢失问题【转】...

一、问题起源不久前用户反馈部门的 MySQL 数据库发生了数据更新丢失。为了解决这个问题&#xff0c;当时对用户使用的场景进行了分析。发现可能是因为用户在两台互为主从的机器上都进行了写入导致的数据丢失。如图所示&#xff0c;是正常和异常情况下应用写入数据库的示例。随后…