diff --git a/docs/en/CLI.md b/docs/en/CLI.md index 68a5923a9f..837ba26a11 100644 --- a/docs/en/CLI.md +++ b/docs/en/CLI.md @@ -178,6 +178,29 @@ Logs you out by removing the session token from your computer. abp logout ``` +### generate-proxy + +Generates typescript service proxies and DTOs + +Basic usage: + +````bash +abp generate-proxy [options] +```` + +Example: + +````bash +abp generate-proxy --apiUrl https://localhost:44305 --ui angular --module all +```` + +#### Options + +* `--apiUrl` or `-a`: If you don't give this option, the default api url in your environment.ts file is used, but you can always use a specific api source with this option. +* `--ui` or `-u`: Specifies the UI framework. Default framework is angular. Currently there is only angular option, but we will increase the options with our new cli updates. Stay tuned! +* `--module` or `-m`: Specifies the module name. Default module name is app. If you want to all modules. You can give `--module all` command. + + ### help Writes basic usage information of the CLI. @@ -193,4 +216,4 @@ Examples: ````bash abp help # Shows a general help. abp help new # Shows help about the "new" command. -```` \ No newline at end of file +```` diff --git a/docs/zh-Hans/CLI.md b/docs/zh-Hans/CLI.md index c65312e0d5..ab1eba8fe7 100644 --- a/docs/zh-Hans/CLI.md +++ b/docs/zh-Hans/CLI.md @@ -59,6 +59,7 @@ abp new Acme.BookStore * `--output-folder` 或者 `-o`: 指定输出文件夹,默认是当前目录. * `--version` 或者 `-v`: 指定ABP和模板的版本.它可以是 [release tag](https://github.com/abpframework/abp/releases) 或者 [branch name](https://github.com/abpframework/abp/branches). 如果没有指定,则使用最新版本.大多数情况下,您会希望使用最新的版本. * `--template-source` 或者 `-ts`: 指定自定义模板源用于生成项目,可以使用本地源和网络源(例如 `D\localTemplate` 或 `https://.zip`). +* `--create-solution-folder` 或者 `-csf`: 指定项目是在输出文件夹中的新文件夹中还是直接在输出文件夹中. ### add-package @@ -171,6 +172,28 @@ abp login abp logout ``` +### generate-proxy + +生成typescript服务和DTO代理 + +基本用法: + +````bash +abp generate-proxy [options] +```` + +示例: + +````bash +abp generate-proxy --apiUrl https://localhost:44305 --ui angular --module all +```` + +#### Options + +* `--apiUrl` 或者 `-a`:如果未指定这个选项,默认使用你的environment.ts文件的API URL, 你可以随时使用这个选项指定API源. +* `--ui` 或者 `-u`: 指定UI框架,默认框架是angular.当前只有angular一个选项, 但我们会通过更改CLI增加新的选项. 尽请关注! +* `--module` 或者 `-m`:指定模块名. 默认模块名称为app. 如果你想所有模块,你可以指定 `--module all` 命令. + ### help CLI的基本用法信息. diff --git a/docs/zh-Hans/Customizing-Application-Modules-Extending-Entities.md b/docs/zh-Hans/Customizing-Application-Modules-Extending-Entities.md index ea5345f822..745861e2c3 100644 --- a/docs/zh-Hans/Customizing-Application-Modules-Extending-Entities.md +++ b/docs/zh-Hans/Customizing-Application-Modules-Extending-Entities.md @@ -1,3 +1,148 @@ # 自定义应用模块: 扩展实体 -TODO... \ No newline at end of file +在某些情况下你可能希望为依赖模块中定义的实体添加一些额外的属性(和数据库字段). 本节将介绍一些实现这一目标的不同方法. + +## Extra Properties + +[Extra properties](Entities.md)是一种存储实体的一些额外数据但不用更改实体的方式. 实体应该实现 `IHasExtraProperties` 接口. 所有预构建模块定义的聚合根实体都实现了 `IHasExtraProperties` 接口,所以你可以在这些实体中存储额外的属性. + +示例: + +````csharp +//SET AN EXTRA PROPERTY +var user = await _identityUserRepository.GetAsync(userId); +user.SetProperty("Title", "My custom title value!"); +await _identityUserRepository.UpdateAsync(user); + +//GET AN EXTRA PROPERTY +var user = await _identityUserRepository.GetAsync(userId); +return user.GetProperty("Title"); +```` + +这种方法开箱即用并且非常简单,你可以使用不同的属性名称(如这里的`Title`)在同一时间存储多个属性. + +对于EF Core额外的属性被格式化成单个 `JSON` 字符值串存储在数据库中. 对于MongoDB它们做为单独的字段存储. + +参阅[实体文档](Entities.md)了解更多关于额外系统. + +> 可以基于额外的属性执行**业务逻辑**. 你可以**override**服务方法获取或设置值. 重写服务在下面进行讨论. + +## 创建新实体映射到同一个数据库表/Collection + +尽管额外属性方法**易于使用**并且适用于一些场景,但它具有[实体文档](Entities.md)中描述的一些缺点. + +另一个方法是**创建你自己的实体**映射到**同一个数据库库**(对于MongoDB数据库是collection) + +[应用程序启动模板](Startup-Templates/Application.md)的 `AppUser` 已经实现了这种方法. [EF Core迁移文档](Entity-Framework-Core-Migrations.md)描述了在这些情况下如何实现和管理**EF Core数据库迁移**. 这种方法同样适用于MongoDB,但你不需要处理数据库迁移问题. + +## 创建一个拥有自己数据库表/Collection的新实体 + +映射你的实体到依赖模块的**已存在的表**有一些缺点; + +* 你需要处理EF Core的**数据库迁移架构**. 需要特别注意迁移代码,特别是当你需要在实体间添加**关系**时. +* 你的应用程序数据库和模块数据库将是 **同一个物理数据库**. 通常需要时可以将模块数据库分开,但使用相同的表会对其进行限制. + +如果你想要使你的实体或模块定义的实体**低耦合**,那么可以创建自己的数据库表/collection并且将你的实体映射到自己的数据库表. + +在这种情况下你需要处理**同步问题**,尤其是你要**复制**相关实体的某些属性/字段时,有一些解决方案; + +* 如果你构建的是一个 **单体** 应用程序(或者在同一进程管理你的实体和依赖模块的实体),那么你可以使用[本地事件总线](Local-Event-Bus.md)监听实体更改. +* 如果你构建的是一个 **分布式** 系统,模块的实体和你的实体在不同的 进程/服务 管理(创建/更新/删除),那么你可以使用[分布式事件总线](Distributed-Event-Bus.md)订阅实体的更改事件. + +在你处理事件时,你可以在自己的数据库中更改自己的实体. + +### 订阅本地事件总线 + +[本地事件总线](Local-Event-Bus.md)系统是发布和订阅同一应用程序中发生的事件的方法. + +假设你想要获取 `IdentityUser` 实体的更改信息(创建,更改或删除). 你可以创建一个类实现 `ILocalEventHandler>` 接口. + +````csharp +public class MyLocalIdentityUserChangeEventHandler : + ILocalEventHandler>, + ITransientDependency +{ + public async Task HandleEventAsync(EntityChangedEventData eventData) + { + var userId = eventData.Entity.Id; + var userName = eventData.Entity.UserName; + //... + } +} +```` + +* `EntityChangedEventData` 涵盖了给定实体的创建,更新或删除事件. 如果你需要你可以分别订阅创建,更新或删除事件(在同一个类或不同的类中). +* 这里的代码在**本地事务之外执行**,因为它监听 `EntityChanged` 事件. 如果当前[工作单元](Unit-Of-Work.md)是事务性的,你可以订阅 `EntityChangingEventData` 事件,它在**同一本地(进行)事务**中执行事件处理. + +> 提醒:这些方法需要在包含处理类的同一进程中更改 `IdentityUser` 实体. 即使在集群环境(同一应用程序的多个实例在不同的服务器进行),它也完美工作. + +### 订阅分布式事件总线 + +[分布式事件总线](Distributed-Event-Bus.md)是在一个应用程序中发布事件,并在相同服务器或不同服务器运行的相同应用程序或不同应用程序中接收事件的方法. + +假设你想要获取 `IdentityUser` 实体的创建,更改或删除信息. 你可以像以下一样创建一个类: + +````csharp +public class MyDistributedIdentityUserChangeEventHandler : + IDistributedEventHandler>, + IDistributedEventHandler>, + IDistributedEventHandler>, + ITransientDependency +{ + public async Task HandleEventAsync(EntityCreatedEto eventData) + { + if (eventData.Entity.EntityType == "Volo.Abp.Identity.IdentityUser") + { + var userId = Guid.Parse(eventData.Entity.KeysAsString); + //...handle the "created" event + } + } + + public async Task HandleEventAsync(EntityUpdatedEto eventData) + { + if (eventData.Entity.EntityType == "Volo.Abp.Identity.IdentityUser") + { + var userId = Guid.Parse(eventData.Entity.KeysAsString); + //...handle the "updated" event + } + } + + public async Task HandleEventAsync(EntityDeletedEto eventData) + { + if (eventData.Entity.EntityType == "Volo.Abp.Identity.IdentityUser") + { + var userId = Guid.Parse(eventData.Entity.KeysAsString); + //...handle the "deleted" event + } + } +} +```` + +* 它实现了多个 `IDistributedEventHandler` 接口: **创建**,**更改**和**删除**,因为分布式事件总线单独发布事件,没有本地事件总线那样的"Changed"事件. +* 它订阅了 `EntityEto`, 这是一个通用的事件类,ABP框架针对所有类型的实体**自动发布**. 这就是为什么它检查**实体类型**(因为我们没有假设有对 `IdentityUser` 实体有安全的类型引用,所以它是字符串类型的). + +预构建应用模块没有定义专门的事件类型(如`IdentityUserEto` - "ETO" 意思是 "事件传输对象"). 此功能在路线图上([关注这个issue](https://github.com/abpframework/abp/issues/3033)),一旦完成后,你就可以订阅独立的实体类型: + +````csharp +public class MyDistributedIdentityUserCreatedEventHandler : + IDistributedEventHandler>, + ITransientDependency +{ + public async Task HandleEventAsync(EntityCreatedEto eventData) + { + var userId = eventData.Entity.Id; + var userName = eventData.Entity.UserName; + //...handle the "created" event + } + + //... +} +```` + +* 这个处理程序只会在新用户创建时执行. + +> 唯一预定义的专门事件类是 `UserEto`, 你可以订阅 `EntityCreatedEto` 获取用户创建时的通知. 此事件也适用于身份模块. + +## 另请参阅 + +* [自定义已存在的模块](Customizing-Application-Modules-Guide.md) \ No newline at end of file diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/NewCommand.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/NewCommand.cs index 28fcf4b3f6..3afc32ec4d 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/NewCommand.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/NewCommand.cs @@ -55,6 +55,12 @@ namespace Volo.Abp.Cli.Commands Logger.LogInformation("Version: " + version); } + var isTiered = commandLineArgs.Options.ContainsKey(Options.Tiered.Long); + if (isTiered) + { + Logger.LogInformation("Tiered: yes"); + } + var databaseProvider = GetDatabaseProvider(commandLineArgs); if (databaseProvider != DatabaseProvider.NotSpecified) { @@ -96,14 +102,9 @@ namespace Volo.Abp.Cli.Commands var outputFolderRoot = outputFolder != null ? Path.GetFullPath(outputFolder) : Directory.GetCurrentDirectory(); - if (createSolutionFolder) - { - outputFolder = Path.Combine(outputFolderRoot, SolutionName.Parse(projectName).FullName); - } - else - { - outputFolder = outputFolderRoot; - } + outputFolder = createSolutionFolder ? + Path.Combine(outputFolderRoot, SolutionName.Parse(projectName).FullName) : + outputFolderRoot; if (!Directory.Exists(outputFolder)) { @@ -232,7 +233,7 @@ namespace Volo.Abp.Cli.Commands } } - private UiFramework GetUiFramework(CommandLineArgs commandLineArgs) + protected virtual UiFramework GetUiFramework(CommandLineArgs commandLineArgs) { var optionValue = commandLineArgs.Options.GetOrNull(Options.UiFramework.Short, Options.UiFramework.Long); switch (optionValue) @@ -248,7 +249,7 @@ namespace Volo.Abp.Cli.Commands } } - private MobileApp GetMobilePreference(CommandLineArgs commandLineArgs) + protected virtual MobileApp GetMobilePreference(CommandLineArgs commandLineArgs) { var optionValue = commandLineArgs.Options.GetOrNull(Options.Mobile.Short, Options.Mobile.Long); switch (optionValue) @@ -316,6 +317,11 @@ namespace Volo.Abp.Cli.Commands public const string Short = "csf"; public const string Long = "create-solution-folder"; } + + public static class Tiered + { + public const string Long = "tiered"; + } } } } diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/TemplateProjectBuilder.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/TemplateProjectBuilder.cs index f7d9eaf3be..6d3fa4b7b8 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/TemplateProjectBuilder.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/TemplateProjectBuilder.cs @@ -82,7 +82,7 @@ namespace Volo.Abp.Cli.ProjectBuilding // Exclude unwanted or known options. var options = args.ExtraProperties .Where(x => !x.Key.Equals(CliConsts.Command, StringComparison.InvariantCultureIgnoreCase)) - .Where(x => !x.Key.Equals("tiered", StringComparison.InvariantCultureIgnoreCase)) + .Where(x => !x.Key.Equals(NewCommand.Options.Tiered.Long, StringComparison.InvariantCultureIgnoreCase)) .Where(x => !x.Key.Equals(NewCommand.Options.DatabaseProvider.Long, StringComparison.InvariantCultureIgnoreCase) && !x.Key.Equals(NewCommand.Options.DatabaseProvider.Short, StringComparison.InvariantCultureIgnoreCase)) .Where(x => !x.Key.Equals(NewCommand.Options.OutputFolder.Long, StringComparison.InvariantCultureIgnoreCase) && @@ -102,7 +102,7 @@ namespace Volo.Abp.Cli.ProjectBuilding Tool = Options.ToolName, Command = args.ExtraProperties.ContainsKey(CliConsts.Command) ? args.ExtraProperties[CliConsts.Command] : "", DatabaseProvider = args.DatabaseProvider.ToProviderName(), - IsTiered = args.ExtraProperties.ContainsKey("tiered"), + IsTiered = args.ExtraProperties.ContainsKey(NewCommand.Options.Tiered.Long), UiFramework = args.UiFramework.ToFrameworkName(), Options = JsonSerializer.Serialize(options), ProjectName = args.SolutionName.FullName, diff --git a/npm/get-version.js b/npm/get-version.js index 7f3dd79e3b..5198ee913a 100644 --- a/npm/get-version.js +++ b/npm/get-version.js @@ -1,3 +1,10 @@ -const fse = require("fs-extra"); +const fse = require('fs-extra'); -console.log(fse.readJSONSync("package.json").version); +const commonProps = fse.readFileSync('../common.props').toString(); + +const versionTag = ''; +const versionEndTag = ''; +const first = commonProps.indexOf(versionTag) + versionTag.length; +const last = commonProps.indexOf(versionEndTag); + +console.log(commonProps.substring(first, last));