Browse Source

Merge branch 'dev' of https://github.com/abpframework/abp into dev

pull/3235/head
Arkat Erol 6 years ago
parent
commit
1dc4556e34
  1. 25
      docs/en/CLI.md
  2. 23
      docs/zh-Hans/CLI.md
  3. 147
      docs/zh-Hans/Customizing-Application-Modules-Extending-Entities.md
  4. 26
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/NewCommand.cs
  5. 4
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/TemplateProjectBuilder.cs
  6. 11
      npm/get-version.js

25
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.
````
````

23
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://<your url>.zip`).
* `--create-solution-folder` 或者 `-csf`: 指定项目是在输出文件夹中的新文件夹中还是直接在输出文件夹中.
### add-package
@ -171,6 +172,28 @@ abp login <username>
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的基本用法信息.

147
docs/zh-Hans/Customizing-Application-Modules-Extending-Entities.md

@ -1,3 +1,148 @@
# 自定义应用模块: 扩展实体
TODO...
在某些情况下你可能希望为依赖模块中定义的实体添加一些额外的属性(和数据库字段). 本节将介绍一些实现这一目标的不同方法.
## 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<string>("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<EntityChangedEventData<IdentityUser>>` 接口.
````csharp
public class MyLocalIdentityUserChangeEventHandler :
ILocalEventHandler<EntityChangedEventData<IdentityUser>>,
ITransientDependency
{
public async Task HandleEventAsync(EntityChangedEventData<IdentityUser> eventData)
{
var userId = eventData.Entity.Id;
var userName = eventData.Entity.UserName;
//...
}
}
````
* `EntityChangedEventData<T>` 涵盖了给定实体的创建,更新或删除事件. 如果你需要你可以分别订阅创建,更新或删除事件(在同一个类或不同的类中).
* 这里的代码在**本地事务之外执行**,因为它监听 `EntityChanged` 事件. 如果当前[工作单元](Unit-Of-Work.md)是事务性的,你可以订阅 `EntityChangingEventData<T>` 事件,它在**同一本地(进行)事务**中执行事件处理.
> 提醒:这些方法需要在包含处理类的同一进程中更改 `IdentityUser` 实体. 即使在集群环境(同一应用程序的多个实例在不同的服务器进行),它也完美工作.
### 订阅分布式事件总线
[分布式事件总线](Distributed-Event-Bus.md)是在一个应用程序中发布事件,并在相同服务器或不同服务器运行的相同应用程序或不同应用程序中接收事件的方法.
假设你想要获取 `IdentityUser` 实体的创建,更改或删除信息. 你可以像以下一样创建一个类:
````csharp
public class MyDistributedIdentityUserChangeEventHandler :
IDistributedEventHandler<EntityCreatedEto<EntityEto>>,
IDistributedEventHandler<EntityUpdatedEto<EntityEto>>,
IDistributedEventHandler<EntityDeletedEto<EntityEto>>,
ITransientDependency
{
public async Task HandleEventAsync(EntityCreatedEto<EntityEto> 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<EntityEto> 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<EntityEto> 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<EntityCreatedEto<IdentityUserEto>>,
ITransientDependency
{
public async Task HandleEventAsync(EntityCreatedEto<IdentityUserEto> eventData)
{
var userId = eventData.Entity.Id;
var userName = eventData.Entity.UserName;
//...handle the "created" event
}
//...
}
````
* 这个处理程序只会在新用户创建时执行.
> 唯一预定义的专门事件类是 `UserEto`, 你可以订阅 `EntityCreatedEto<UserEto>` 获取用户创建时的通知. 此事件也适用于身份模块.
## 另请参阅
* [自定义已存在的模块](Customizing-Application-Modules-Guide.md)

26
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";
}
}
}
}

4
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,

11
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 = '<Version>';
const versionEndTag = '</Version>';
const first = commonProps.indexOf(versionTag) + versionTag.length;
const last = commonProps.indexOf(versionEndTag);
console.log(commonProps.substring(first, last));

Loading…
Cancel
Save