标签:demo 使用 type 使用指南 nal comm eth default 修改时间
命令行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
创建实体
public class Todo : FullAuditedEntity<Guid>
{
public string Content { get; set; }
public bool Done { get; set; }
}
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 Todo
service
根据指定的名称生成服务接口和类文件
abphelper generate service Project -f Projects
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是一种快速、强大、安全和轻量级的文本模板语言和.NET引擎,具有解析liquid模板的兼容模式
创建一个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>
{
}
}
这是一个嵌入资源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增加如下一行
新建目录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);
}
引用包
<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"
代码生成还需要什么呢,创建一个实体类,根据此实体类生成表的CRUD代码。
修改OvOv.Test,引入包
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.6.0" />
这个包是https://github.com/dotnet/roslyn的一部分.Roslyn 是.NET编译器为C#和Visual Basic 提供了丰富的代码分析API。
再搞个CodeAnalysisTest测试类。这里我们有一个字符串,他是一个实体类,这个类有一些特点。比如
如下代码,通过语法树,解析出这个字符串中的命名空间,输出 LinCms.Books。
说明: FullAduitEntity是一个包含CRUD的审计实体类,通常包含七个字段(创建人,创建时间,修改人,修改时间,是否删除,删除人,删除时间),另外还有一个主键。默认是long,具体可查看此文件https://github.com/luoyunchong/lin-cms-dotnetcore/blob/master/src/LinCms.Core/Entities/FullAduitEntity.cs
你也可以使用诸如Entity
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 Keys
baseType = baseList.DescendantNodes().OfType<SimpleBaseTypeSyntax>().Single().Type.ToString();
primaryKey = "long";
}
else
{
// Normal entity
baseType = 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可以用来处理strings, enums, dates, times, timespans, numbers and quantities所有的需求。
当我们写代码时,总避免不了写复数形式的代码,一些特殊的后缀不是直接加s就行的。
所以可以用Humanizer来处理这些特殊的变量
通过扩展方法生成这些字符串。
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是一组用于构建命令行应用程序的库,包括解析,调用和渲染。
他能简化命令行参数的处理,帮助我们构建自己的CLI。
对于代码生成器,不要是必须的。
Elsa Core是一个工作流库,可在任何 .NET Core应用程序中执行工作流。工作流可以不仅使用代码来定义,也可作为JSON,YAML或XML。
代码生成器,流程多,可使用此程序工作流来处理。不是必须的。
ABP VNEXT的代码生成的可视化界面,使用方式看README就好,不多介绍。
帮助ABP VNext的开发者快速构建单表的CRUD的。
如果你自己研究一下这些类库的使用方法,特别是Sciban。我们也能实现代码生成器,帮助改善公司及自己已有项目的开发流程。
标签:demo 使用 type 使用指南 nal comm eth default 修改时间
原文地址:https://www.cnblogs.com/igeekfan/p/abphelper-cli-start.html