From d3bdb3a2de0ab5e6aa9acb3586f5909f2b9e3127 Mon Sep 17 00:00:00 2001 From: edison Date: Fri, 12 Oct 2018 17:47:50 +0800 Subject: [PATCH 1/9] Update document Multi-Tenancy.md --- docs/zh-Hans/Multi-Tenancy.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/zh-Hans/Multi-Tenancy.md b/docs/zh-Hans/Multi-Tenancy.md index 154c5df91c..a28b2e7fad 100644 --- a/docs/zh-Hans/Multi-Tenancy.md +++ b/docs/zh-Hans/Multi-Tenancy.md @@ -285,7 +285,7 @@ ITenantStore跟 **TenantInformation**类一起工作,并且包含了几个租户 * **ConnectionStrings**:如果这个租户有专门的数据库来存储数据.它可以提供数据库的字符串(它可以具有默认的连接字符串和每个模块的连接字符串). -一个多租户程序可能需要额外的租户属性,但上面的属性是多租户框架最基本的. +多租户应用程序可能需要其他租户属性,但这些属性是框架与多个租户一起使用的最低要求. #### 代码中改变租户 From 1612bddbf82939ff699bae0e98d71c0dbda60e52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A2=81=E5=A3=AB=E4=BC=9F?= Date: Sat, 13 Oct 2018 13:25:30 +0800 Subject: [PATCH 2/9] Translate the bast-practices/repositories document --- .../Best-Practices/Data-Transfer-Objects.md | 2 +- docs/zh-Hans/Best-Practices/Repositories.md | 52 +++++++++---------- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/docs/zh-Hans/Best-Practices/Data-Transfer-Objects.md b/docs/zh-Hans/Best-Practices/Data-Transfer-Objects.md index f38dc07084..0a523beb71 100644 --- a/docs/zh-Hans/Best-Practices/Data-Transfer-Objects.md +++ b/docs/zh-Hans/Best-Practices/Data-Transfer-Objects.md @@ -1,4 +1,4 @@ -## 数据传输对象最佳实践&约定 +## 数据传输对象最佳实践 & 约定 * **推荐** 在 **application.contracts** 层中定义DTO. * **推荐** 在可能和必要的情况下从预构建的 **基础DTO类** 继承 (如 `EntityDto`, `CreationAuditedEntityDto`, `AuditedEntityDto`, `FullAuditedEntityDto` 等). diff --git a/docs/zh-Hans/Best-Practices/Repositories.md b/docs/zh-Hans/Best-Practices/Repositories.md index c0058df433..26431a633f 100644 --- a/docs/zh-Hans/Best-Practices/Repositories.md +++ b/docs/zh-Hans/Best-Practices/Repositories.md @@ -1,14 +1,14 @@ -## Repository Best Practices & Conventions +## 仓储最佳实践 & 约定 -### Repository Interfaces +### 仓储接口 -* **Do** define repository interfaces in the **domain layer**. -* **Do** define a repository interface (like `IIdentityUserRepository`) and create its corresponding implementations for **each aggregate root**. - * **Do** always use the created repository interface from the application code. - * **Do not** use generic repository interfaces (like `IRepository`) from the application code. - * **Do not** use `IQueryable` features in the application code (domain, application... layers). +* **推荐** 在**领域层**中定义仓储接口. +* **推荐** 为**每个聚合根**定义仓储接口(如 `IIdentityUserRepository`)并创建相应的实现. + * **推荐** 在应用代码中使用仓储时应该注入仓储接口. + * **不推荐** 在应用代码中使用泛型仓储接口(如 `IRepository`). + * **不推荐** 在应用代码(领域, 应用... 层)中使用 `IQueryable` 特性. -For the example aggregate root: +聚合根的示例: ````C# public class IdentityUser : AggregateRoot @@ -17,7 +17,7 @@ public class IdentityUser : AggregateRoot } ```` -Define the repository interface as below: +定义仓储接口, 如下所示: ````C# public interface IIdentityUserRepository : IBasicRepository @@ -26,14 +26,14 @@ public interface IIdentityUserRepository : IBasicRepository } ```` -* **Do not** inherit the repository interface from the `IRepository` interface. Because it inherits the `IQueryable` and the repository should not expose `IQueryable` to the application. -* **Do** inherit the repository interface from `IBasicRepository` (as normally) or a lower-featured interface, like `IReadOnlyRepository` (if it's needed). -* **Do not** define repositories for entities those are **not aggregate roots**. +* **不推荐** 仓储接口继承 `IRepository` 接口. 因为它继承了 `IQueryable` 而仓储不应该将`IQueryable`暴漏给应用. +* **推荐** 通常仓储接口继承自 `IBasicRepository` 或更低级别的接口, 如 `IReadOnlyRepository` (在需要的时候). +* **不推荐** 为实体定义仓储接口,因为它们**不是聚合根**. -### Repository Methods +### 仓储方法 -* **Do** define all repository methods as **asynchronous**. -* **Do** add an **optional** `cancellationToken` parameter to every method of the repository. Example: +* **推荐** 所有的仓储方法定义为 **异步**. +* **推荐** 为仓储的每个方法添加 **可选参数** `cancellationToken` . 例: ````C# Task FindByNormalizedUserNameAsync( @@ -42,7 +42,7 @@ Task FindByNormalizedUserNameAsync( ); ```` -* **Do** create a **synchronous extension** method for each asynchronous repository method. Example: +* **推荐** 为仓储的每个异步方法创建一个 **同步扩展** 方法. 示例: ````C# public static class IdentityUserRepositoryExtensions @@ -58,9 +58,9 @@ public static class IdentityUserRepositoryExtensions } ```` -This will allow synchronous code to use the repository methods easier. +对于同步方法而言, 这会让它们更方便的调用仓储方法. -* **Do** add an optional `bool includeDetails = true` parameter (default value is `true`) for every repository method which returns a **single entity**. Example: +* **推荐** 为仓储中返回**单个实体**的方法添加一个可选参数 `bool includeDetails = true` (默认值为`true`). 示例: ````C# Task FindByNormalizedUserNameAsync( @@ -70,9 +70,9 @@ Task FindByNormalizedUserNameAsync( ); ```` -This parameter will be implemented for ORMs to eager load sub collections of the entity. +该参数由ORM实现, 用来加载实体子集合. -* **Do** add an optional `bool includeDetails = false` parameter (default value is `false`) for every repository method which returns a **list of entities**. Example: +* **推荐** 为仓储中返回**实体列表**的方法添加一个可选参数 `bool includeDetails = false` (默认值为`false`). 示例: ````C# Task> GetListByNormalizedRoleNameAsync( @@ -82,11 +82,11 @@ Task> GetListByNormalizedRoleNameAsync( ); ```` -* **Do not** create composite classes to combine entities to get from repository with a single method call. Examples: *UserWithRoles*, *UserWithTokens*, *UserWithRolesAndTokens*. Instead, properly use `includeDetails` option to add all details of the entity when needed. -* **Avoid** to create projection classes for entities to get less property of an entity from the repository. Example: Avoid to create BasicUserView class to select a few properties needed for the use case needs. Instead, directly use the aggregate root class. However, there may be some exceptions for this rule, where: - * Performance is so critical for the use case and getting the whole aggregate root highly impacts the performance. +* **不推荐** 创建复合类通过调用仓储单个方法返回组合实体. 比如: *UserWithRoles*, *UserWithTokens*, *UserWithRolesAndTokens*. 相反, 正确的使用 `includeDetails` 选项, 在需要时加载实体所有的详细信息. +* **避免** 为了从仓储中获取实体的部分属性而为实体创建投影类. 比如: 避免通过创建BasicUserView来选择所需的一些属性. 相反可以直接使用聚合根类. 不过这条规则有例外情况: + * 性能对于用例来说非常重要,而且使用整个聚合根对性能的影响非常大. -### See Also +### 另外请参阅 -* [Entity Framework Core Integration](Entity-Framework-Core-Integration.md) -* [MongoDB Integration](MongoDB-Integration.md) +* [Entity Framework Core 集成](Entity-Framework-Core-Integration.md) +* [MongoDB 集成](MongoDB-Integration.md) From 8eda5dcb5c19cf7ad8188109290cd40704d2fa8d Mon Sep 17 00:00:00 2001 From: edison Date: Sat, 13 Oct 2018 15:30:09 +0800 Subject: [PATCH 3/9] Translate document Part-I.md --- .../Tutorials/AspNetCore-Mvc/Part-I.md | 206 +++++++++--------- 1 file changed, 104 insertions(+), 102 deletions(-) diff --git a/docs/zh-Hans/Tutorials/AspNetCore-Mvc/Part-I.md b/docs/zh-Hans/Tutorials/AspNetCore-Mvc/Part-I.md index 5ed244a53c..252090d248 100644 --- a/docs/zh-Hans/Tutorials/AspNetCore-Mvc/Part-I.md +++ b/docs/zh-Hans/Tutorials/AspNetCore-Mvc/Part-I.md @@ -1,30 +1,30 @@ -## ASP.NET Core MVC Tutorial - Part I +## ASP.NET Core MVC 介绍 - 第一章 -### About this Tutorial +### 关于本教程 -In this tutorial series, you will build an application that is used to manage a list of books & their authors. **Entity Framework Core** (EF Core) will be used as the ORM provider (as it comes pre-configured with the [startup template](https://abp.io/Templates)). +本教程中,你会创建一个用于管理书籍和书籍作者的程序.会用到 **Entity Framework Core** (EF Core)作为ORM([启动模板](https://abp.io/Templates)中预配置的ORM). -This is the first part of the tutorial series. See all parts: +这是本教程所有章节中的第一章,下面是所有的章节: -- **Part I: Create the project and a book list page (this tutorial)** -- [Part II: Create, Update and Delete books](Part-II.md) -- [Part III: Integration Tests](Part-III.md) +- **Part I: 创建项目和书籍列表页面(本章)** +- [Part II: 创建,编辑,删除书籍](Part-II.md) +- [Part III: 集成测试](Part-III.md) -You can download the **source code** of the application [from here](https://github.com/volosoft/abp/tree/master/samples/BookStore). +你可以从[这里](https://github.com/volosoft/abp/tree/master/samples/BookStore)下载本程序的源码. -### Creating the Project +### 创建项目 -Go to the [startup template page](https://abp.io/Templates) and download a new project named `Acme.BookStore`, create the database and run the application by following the [template document](../../Getting-Started-AspNetCore-MVC-Template.md). +打开[启动模板页](https://abp.io/Templates)并下载一个新的项目叫做`Acme.BookStore`.根据[模板文档](../../Getting-Started-AspNetCore-MVC-Template.md)创建数据库并运行这个程序. -### Solution Structure +### 解决方案的结构 -This is the how the layered solution structure looks after it's created from the startup template: +下面的图片展示了从启动模板创建的项目是如何分层的. ![bookstore-visual-studio-solution](images/bookstore-visual-studio-solution.png) -### Create the Book Entity +### 创建Book实体 -Define [entities](../../Entities.md) in the **domain layer** (`Acme.BookStore.Domain` project) of the solution. The main entity of the application is the `Book`: +在 **领域层** 定义[实体](../../Entities.md)(`Acme.BookStore.Domain` 中).这个项目最主要的实体就是`Book`: ````C# using System; @@ -50,14 +50,14 @@ namespace Acme.BookStore } ```` -* ABP has two fundamental base classes for entities: `AggregateRoot` and `Entity`. **Aggregate Root** is one of the **Domain Driven Design (DDD)** concepts. See [entity document](../../Entities.md) for more details and best practices. -* `Book` entity inherits `AuditedAggregateRoot` which adds some auditing properties (`CreationTime`, `CreatorId`, `LastModificationTime`... etc.) on top of the `AggregateRoot` class. -* `Guid` is the **primary key type** of the `Book` entity. -* Used **data annotation attributes** in this code for EF Core mappings. Alternatively you could use EF Core's [fluent mapping API](https://docs.microsoft.com/en-us/ef/core/modeling) instead. +* ABP有两个基本的实体基类: `AggregateRoot` 和 `Entity`.**Aggregate Root**是 **领域驱动设计(DDD)** 中的概念.查看[实体](../../Entities.md)的更多信息和最佳实践. +* `Book`实体继承了`AuditedAggregateRoot`,`AuditedAggregateRoot`类在`AggregateRoot`类的基础上添加了(`CreationTime`, `CreatorId`, `LastModificationTime`... 等.)审计属性. +* `Book`实体的主键类型是`Guid`类型. +* 使用 **数据注解** 为EF Core添加映射.或者你也可以使用 EF Core 自带的[fluent mapping API](https://docs.microsoft.com/en-us/ef/core/modeling). -#### BookType Enum +#### BookType枚举 -The `BookType` enum used above is defined as below: +下面是所有要用到的`BookType`枚举: ````C# namespace Acme.BookStore @@ -77,9 +77,9 @@ namespace Acme.BookStore } ```` -#### Add Book Entity to Your DbContext +#### 将Book实体添加到DbContext中 -EF Core requires you to relate entities with your DbContext. The easiest way to do this is to add a `DbSet` property to the `BookStoreDbContext` class in the `Acme.BookStore.EntityFrameworkCore` project, as shown below: +EF Core需要你将实体和DbContext建立关联.最简单的做法是在`Acme.BookStore.EntityFrameworkCore`项目的`BookStoreDbContext`类中添加`DbSet`属性.如: ````C# public class BookStoreDbContext : AbpDbContext @@ -89,31 +89,31 @@ public class BookStoreDbContext : AbpDbContext } ```` -#### Add New Migration & Update the Database +#### 添加新的Migration并更新数据库 -The Startup template uses [EF Core Code First Migrations](https://docs.microsoft.com/en-us/ef/core/managing-schemas/migrations/) to create and maintain the database schema. Open the **Package Manager Console (PMC)** (under the *Tools/Nuget Package Manager* menu), select the `Acme.BookStore.EntityFrameworkCore` as the **default project** and execute the following command: +这个启动模板使用了[EF Core Code First Migrations](https://docs.microsoft.com/en-us/ef/core/managing-schemas/migrations/)来创建并维护数据库结构.打开 **Package Manager Console (PMC)** (工具/Nuget包管理器菜单),选择 `Acme.BookStore.EntityFrameworkCore`作为默认的项目然后执行下面的命令: ![bookstore-pmc-add-book-migration](images/bookstore-pmc-add-book-migration.png) -This will create a new migration class inside the `Migrations` folder. Then execute the `Update-Database` command to update the database schema: +这样就会在`Migrations`文件夹中创建一个新的migration类.然后执行`Update-Database`命令更新数据库结构. ```` PM> Update-Database ```` -#### Add Sample Data +#### 添加示例数据 -`Update-Database` command created the `Books` table in the database. Open your database and enter a few sample rows, so you can show them on the page: +`Update-Database`命令会在数据库中创建`Books`表.打开这个表添加几行数据,然后就可以把这些数据展示到页面上: ![bookstore-books-table](images/bookstore-books-table.png) -### Create the Application Service +### 创建应用服务 -The next step is to create an [application service](../../Application-Services.md) to manage (create, list, update, delete...) the books. +下一步是创建[应用服务](../../Application-Services.md)来管理(创建,列出,更新,删除...)书籍. #### BookDto -Create a DTO class named `BookDto` into the `Acme.BookStore.Application` project: +在`Acme.BookStore.Application`项目中添加一个名为`BookDto`的DTO类: ````C# using System; @@ -136,14 +136,14 @@ namespace Acme.BookStore } ```` -* **DTO** classes are used to **transfer data** between the *presentation layer* and the *application layer*. See the [Data Transfer Objects document](../../Data-Transfer-Objects.md) for more details. -* `BookDto` is used to transfer book data to the presentation layer in order to show the book information on the UI. -* `BookDto` is derived from the `AuditedEntityDto` which has audit properties just like the `Book` class defined above. -* `[AutoMapFrom(typeof(Book))]` is used to create AutoMapper mapping from the `Book` class to the `BookDto` class. In this way, you get automatic convertion of `Book` objects to `BookDto` objects (instead of manually copy all properties). +* **DTO**类被用来在 **基础设施层** 和 **应用层** **传递数据**.查看[DTO文档](../../Data-Transfer-Objects.md)查看更多信息. +* 为了在页面上展示书籍信息,`BookDto`被用来将书籍数据传递到基础设施层. +* `BookDto`继承自 `AuditedEntityDto`.跟上面定义的`Book`类一样具有一些审计属性. +* `[AutoMapFrom(typeof(Book))]`用来创建从`Book`类到`BookDto`的映射.使用这种方法.你可以将`Book`对象自动转换成`BookDto`对象(而不是手动复制所有的属性). #### CreateUpdateBookDto -Create a DTO class named `CreateUpdateBookDto` into the `Acme.BookStore.Application` project: +在`Acme.BookStore.Application`项目中创建一个名为`CreateUpdateBookDto`的DTO类: ````c# using System; @@ -171,12 +171,12 @@ namespace Acme.BookStore } ```` -* This DTO class is used to get book information from the user interface while creating or updating a book. -* It defines data annotation attributes (like `[Required]`) to define validations for the properties. DTOs are automatically validated by ABP. +* 这个DTO类在创建和更新书籍的时候被使用,用来从页面获取图书信息. +* 类中的属性定义了数据注解(如`[Required]`)用来定义有效性验证.ABP会自动校验DTO的数据有效性. #### IBookAppService -Define an interface named `IBookAppService` for the book application service: +为应用服务定义一个名为 `IBookAppService` 的接口: ````C# using System; @@ -186,25 +186,26 @@ using Volo.Abp.Application.Services; namespace Acme.BookStore { public interface IBookAppService : - IAsyncCrudAppService< //Defines CRUD methods - BookDto, //Used to show books - Guid, //Primary key of the book entity - PagedAndSortedResultRequestDto, //Used for paging/sorting on getting a list of books - CreateUpdateBookDto, //Used to create a new book - CreateUpdateBookDto> //Used to update a book + IAsyncCrudAppService< //定义了CRUD方法 + BookDto, //用来展示书籍 + Guid, //Book实体的主键 + PagedAndSortedResultRequestDto, //获取书籍的时候用于分页和排序 + CreateUpdateBookDto, //用于创建书籍 + CreateUpdateBookDto> //用户更新书籍 { } } ```` -* Defining interfaces for application services is not required by the framework. However, it's suggested as best practice. -* `IAsyncCrudAppService` defines common **CRUD** methods: `GetAsync`, `GetListAsync`, `CreateAsync`, `UpdateAsync` and `DeleteAsync`. It's not required to extend it. Instead, you could inherit from the empty `IApplicationService` interface and define your own methods. -* There are some variations of the `IAsyncCrudAppService` where you can use a single DTO or separated DTOs for each method. +* 为应用服务定义接口不是必须的,不过,我们推荐这么做. +* `IAsyncCrudAppService`中定义了基础的 **CRUD**方法:`GetAsync`, `GetListAsync`, `CreateAsync`, `UpdateAsync` 和 `DeleteAsync`.不需要扩展它.取而代之,你可以继承空的`IApplicationService`接口定义你自己的方法. +* `IAsyncCrudAppService`有很多的泛型,你可以为每一个方法使用单个或者多个的DTO. + #### BookAppService -Implement the `IBookAppService` as named `BookAppService`: +创建 `BookAppService` 并实现 `IBookAppService`接口: ````C# using System; @@ -228,75 +229,76 @@ namespace Acme.BookStore } ```` -* `BookAppService` is derived from `AsyncCrudAppService<...>` which implements all the CRUD methods defined above. -* `BookAppService` injects `IRepository` which is the default repository created for the `Book` entity. ABP automatically creates repositories for each aggregate root (or entity). See the [repository document](../../Repositories.md). -* `BookAppService` uses `IObjectMapper` to convert `Book` objects to `BookDto` objects and `CreateUpdateBookDto` objects to `Book` objects. The Startup template uses the [AutoMapper](http://automapper.org/) library as object mapping provider. You defined mappings using the `AutoMapFrom` and the `AutoMapTo` attributes above. See the [AutoMapper integration document](../../AutoMapper-Integration.md) for details. +* `BookAppService`继承了`AsyncCrudAppService<...>`.`AsyncCrudAppService<...>`实现了上面定义的CRUD方法. +* `BookAppService`注入了`IRepository`,`IRepository`是默认为`Book`创建的仓储.ABP会自动为每一个聚合根(或实体)创建仓储.参考[仓储](../../Repositories.md). +* `BookAppService`使用了 `IObjectMapper` 将`Book`转换成`BookDto`,将`CreateUpdateBookDto`转换成`Book`.启动模板中使用了[AutoMapper](http://automapper.org/)作为映射工具.你可以像上面那样使用`AutoMapFrom` 和 `AutoMapTo`定义映射.查看[AutoMapper继承](../../AutoMapper-Integration.md)获取更多信息. -### Auto API Controllers +### 自动生成API Controllers -You normally create **Controllers** to expose application services as **HTTP API** endpoints. Thus allowing browser or 3rd-party clients to call them via AJAX. +你通常需要创建 **Controllers** 将应用服务暴露为 **HTTP API**.这样浏览器或第三方客户端可以通过AJAX的方式访问它们. -ABP can **automagically** configures your application services as MVC API Controllers by convention. +ABP可以 **自动地** 将应用服务转换成MVC API Controllers. #### Swagger UI -The startup template is configured to run the [swagger UI](https://swagger.io/tools/swagger-ui/) using the [Swashbuckle.AspNetCore](https://github.com/domaindrivendev/Swashbuckle.AspNetCore) library. Run the application and enter `http://localhost:53929/swagger/` as URL on your browser. +启动模板使用了[Swashbuckle.AspNetCore](https://github.com/domaindrivendev/Swashbuckle.AspNetCore)库配置了[swagger UI](https://swagger.io/tools/swagger-ui/).运行程序并在浏览器中输入`http://localhost:53929/swagger/`. -You will see some built-in service endpoints as well as the `Book` service and its REST-style endpoints: +你会看到一些内置的接口和`Book`的接口,它们都是REST风格的: ![bookstore-swagger](images/bookstore-swagger.png) -### Dynamic JavaScript Proxies +### 动态JavaScript代理 -It's common to call HTTP API endpoints via AJAX from the **JavaScript** side. You can use `$.ajax` or another tool to call the endpoints. However, ABP offers a better way. +通过AJAX的方式调用HTTP API接口是很常见的,你可以使用`$.ajax`或这其他的工具来调用接口.当然,ABP中提供了更好的方式. -ABP **dynamically** creates JavaScript **proxies** for all API endpoints. So, you can use any **endpoint** just like calling a **JavaScript function**. +ABP **自动** 为所有的API接口创建了JavaScript **代理**.因此,你可以像调用 **JavaScript function**一样调用任何接口. -#### Testing in the Browser Developer Console +#### 在浏览器的开发者控制台中测试接口 -You can easily test the JavaScript proxy using your favorite browser's **Developer Console** now. Run the application again, open your browser's **developer tools** (shortcut: F12), switch to the **Console** tab, type the following code and press enter: +你可以使用你最爱的浏览器的 **开发者控制台** 中轻松测试JavaScript代理.运行程序,并打开浏览器的 **开发者工具**(快捷键:F12),切换到 **Console**,输入下面的代码并回车: ````js acme.bookStore.book.getList({}).done(function (result) { console.log(result); }); ```` -* `acme.bookStore` is the namespace of the `BookAppService` converted to [camelCase](https://en.wikipedia.org/wiki/Camel_case). -* `book` is the conventional name for the `BookAppService` (removed AppService postfix and converted to camelCase). -* `getList` is the conventional name for the `GetListAsync` method defined in the `AsyncCrudAppService` base class (removed Async postfix and converted to camelCase). -* `{}` argument is used to send an empty object to the `GetListAsync` method which normally expects an object of type `PagedAndSortedResultRequestDto` which is used to send paging and sorting options to the server. -* `getList` function returns a `promise`. So, you can pass a callback to the `done` (or `then`) function to get the result from the server. +* `acme.bookStore`是`BookAppService`的命名空间,转换成了[驼峰命名](https://en.wikipedia.org/wiki/Camel_case). +* `book`是`BookAppService`转换后的名字(去除了AppService后缀并转成了驼峰命名). +* `getList`是定义在`AsyncCrudAppService`基类中的`GetListAsync`方法转换后的名字(去除了Async后缀并转成了驼峰命名). +* `{}`参数用来传递一个空的对象给`GetListAsync`方法.GetListAsync期望的参数是`PagedAndSortedResultRequestDto`类型,`PagedAndSortedResultRequestDto`类型中定义了分页和排序. +* `getList`方法返回了一个`promise`.因此,你可以传递一个回调函数到`done`(或者`then`)方法中来获取服务返回的结果. -Running this code produces the following output: +运行这段代码会产生下面的输出: ![bookstore-test-js-proxy-getlist](images/bookstore-test-js-proxy-getlist.png) -You can see the **book list** returned from the server. You can also check the **network** tab of the developer tools to see the client to server communication: +你可以看到服务器返回的 **book list**.你还可以切换到开发者工具的 **network** 查看客户端和服务器的连接: ![bookstore-test-js-proxy-getlist-network](images/bookstore-test-js-proxy-getlist-network.png) -Let's **create a new book** using the `create` function: +我们使用`create`方法 **创建一本新书**: ````js acme.bookStore.book.create({ name: 'Foundation', type: 7, publishDate: '1951-05-24', price: 21.5 }).done(function (result) { console.log('successfully created the book with id: ' + result.id); }); ```` -You should see a message in the console something like that: +你会看到控制台会显示类似这样的输出: ```` successfully created the book with id: f3f03580-c1aa-d6a9-072d-39e75c69f5c7 ```` -Check the `books` table in the database to see the new book row. You can try `get`, `update` and `delete` functions too. +检查数据库表`books`中的数据,你会发现多了一行新数据,你也可以尝试`get`, `update` 和 `delete`方法. + +### 创建书籍页面 -### Create the Books Page +现在我们来创建一些可见的可用的东西,我们使用[Razor Pages UI](https://docs.microsoft.com/en-us/aspnet/core/tutorials/razor-pages/razor-pages-start)代替经典的MVC.微软也推荐使用Razor Pages UI -It's time to create something visible and usable! Instead of classic MVC, we will use the new [Razor Pages UI](https://docs.microsoft.com/en-us/aspnet/core/tutorials/razor-pages/razor-pages-start) approach which is recommended by Microsoft. -Create a new `Books` folder under the `Pages` folder of the `Acme.BookStore.Web` project and add a new Razor Page named `Index.html`: +在 `Acme.BookStore.Web`项目的`Pages`文件夹下创建一个新的文件夹叫`Books`并添加一个名叫`Index.html`的Razor Page. ![bookstore-add-index-page](images/bookstore-add-index-page.png) -Open the `Index.cshtml` and change the content as shown below: +打开`Index.cshtml`并把内容修改成下面这样: ````html @page @@ -307,11 +309,11 @@ Open the `Index.cshtml` and change the content as shown below:

Books

```` -* Change the default inhertitance of the Razor View Page Model so it **inherits** from the `BookStorePageBase` class (instead of `PageModel`). The `BookStorePageBase` class which comes with the startup template and provides some shared properties/methods used by all pages. +* 改变Razor View Page Model默认的继承,使页面的 **inherits** 来自`BookStorePageBase`类(代替`PageModel`).`BookStorePageBase`类来自启动模板并提供了一些公开的属性/方法,这些属性/方法可以被所有的页面使用. -#### Add Books Page to the Main Menu +#### 将Books页面添加到主菜单 -Open the `BookStoreMenuContributor` class in the `Menus` folder and add the following code to the end of the `ConfigureMainMenuAsync` method: +打开`Menus`文件夹中的 `BookStoreMenuContributor` 类,在`ConfigureMainMenuAsync`方法的底部添加如下代码: ````c# context.Menu.AddItem( @@ -320,13 +322,13 @@ context.Menu.AddItem( ); ```` -#### Localizing the Menu Items +#### 本地化菜单 -Localization texts are located under the `Localization/BookStore` folder of the `Acme.BookStore.Domain` project: +本地化的文本在`Acme.BookStore.Domain`项目的`Localization/BookStore`文件夹中. ![bookstore-localization-files](images/bookstore-localization-files.png) -Open the `en.json` file and add localization texts for `Menu:BookStore` and `Menu:Books` keys: +打开`en.json`文件,为`Menu:BookStore` 和 `Menu:Books`添加本地化文本: ````json { @@ -339,22 +341,22 @@ Open the `en.json` file and add localization texts for `Menu:BookStore` and `Men } ```` -* ABP's localization system is built on [ASP.NET Core's standard localization](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/localization) system and extends it in many ways. See the [localization document](../../Localization.md) for details. -* Localization key names are arbitrary, you can set any name. We prefer to add `Menu` namespace for menu items to distinguish from other texts. If a text is not defined in the localization file, it **fallbacks** to the localization key (ASP.NET Core's standard behavior). +* ABP的本地化功能建立在[ASP.NET Core's standard localization]((https://docs.microsoft.com/en-us/aspnet/core/fundamentals/localization))之上并增加了一些扩展.查看[本地化文档](../../Localization.md). +* 本地化中key的名字是随便定义的,你可以随意命名.我们喜欢为菜单添加`Menu`命名空间,以区别于其他的文本.如果文本没有在本地化文件中定义,就会 **返回** 本地的化的key(ASP.NET Core的标准做法). -Run the application and see the menu items are added to the top bar: +运行程序就会看到菜单已经添加到了顶部: ![bookstore-menu-items](images/bookstore-menu-items.png) -When you click to the Books menu item, you are redirected to the new Books page. +点击菜单就会调转到新增书籍的页面. -#### Book List +#### 书籍列表 -We will use the [Datatables.net](https://datatables.net/) JQuery plugin to show list of tables on the page. Datatables can completely work via AJAX, so it is fast and provides a good user experience. Datatables plugin is configured in the startup template, so you can directly use it in any page without including any style or script file to your page. +我们会在页面上使用JQuery插件[Datatables.net](https://datatables.net/)来展示列表.Datatables可以完全通过AJAX工作,所以它很快而且有良好的用户体验.启动模板中已经配置好了Datatables,因此你可以在你的页面中直接使用,不需要引用样式和脚本文件. -##### Index.cshtml Changes +##### 修改Index.cshtml -Change the `Pages/Books/Index.cshtml` as following: +将`Pages/Books/Index.cshtml`改成下面的样子: ````html @page @@ -385,17 +387,17 @@ Change the `Pages/Books/Index.cshtml` as following: ```` -* `abp-script` [tag helper](https://docs.microsoft.com/en-us/aspnet/core/mvc/views/tag-helpers/intro) is used to add external **scripts** to the page. It has many additional features compared to standard `script` tag. It handles **minification** and **versioning** for example. See the [bundling & minification document](../../AspNetCore/Bundling-Minification.md) for details. -* `abp-card` and `abp-table` are **tag helpers** for Twitter Bootstrap's [card component](http://getbootstrap.com/docs/4.1/components/card/). There are many tag helpers in ABP to easily use most of the [bootstrap](https://getbootstrap.com/) components. You can also use regular HTML tags instead of these tag helpers, but using tag helpers reduces HTML code and prevents errors by help of the intellisense and compile time type checking. See the [tag helpers document](../../AspNetCore/Tag-Helpers.md). -* You can **localize** the column names in the localization file as you did for the menu items above. +* `abp-script` [tag helper](https://docs.microsoft.com/en-us/aspnet/core/mvc/views/tag-helpers/intro)可以将添加外部的 **scripts**添加到页面中.它比标准的`script`标签多了很多额外的功能.它可以处理 **最小化**和 **版本**.查看[bundling & minification 文档](../../AspNetCore/Bundling-Minification.md)获取更多信息. +* `abp-card` 和 `abp-table` 是为Twitter Bootstrap的[card component](http://getbootstrap.com/docs/4.1/components/card/)封装的 **tag helpers**.ABP中有很多tag helpers,可以很方便的使用大多数[bootstrap](https://getbootstrap.com/)组件.你也可以使用原生的HTML标签代替tag helpers.使用tag helper可以通过智能提示和编译时类型检查减少HTML代码并防止错误.查看[tag helpers 文档](../../AspNetCore/Tag-Helpers.md). +* 你可以像上面本地化菜单一样 **本地化** 列名. -##### Add a Script File +#### 添加脚本文件 -Create `index.js` JavaScript file under the `Pages/Books/` folder: +在`Pages/Books/`文件夹中创建 `index.js`文件 ![bookstore-index-js-file](images/bookstore-index-js-file.png) -`index.js` content is shown below: +`index.js`的内容如下: ````js $(function () { @@ -412,15 +414,15 @@ $(function () { }); ```` -* `abp.libs.datatables.createAjax` is a helper function to adapt ABP's dynamic JavaScript API proxies to Datatable's format. -* `abp.libs.datatables.normalizeConfiguration` is another helper function. There's no requirment to use it, but it simplifies the datatables configuration by providing conventional values for missing options. -* `acme.bookStore.book.getList` is the function to get list of books (you have seen it before). -* See [Datatable's documentation](https://datatables.net/manual/) for more configuration options. +* `abp.libs.datatables.createAjax`是帮助ABP的动态JavaScript API代理跟Datatable的格式相适应的辅助方法. +* `abp.libs.datatables.normalizeConfiguration`是另一个辅助方法.不是必须的, 但是它通过为缺少的选项提供常规值来简化数据表配置. +* `acme.bookStore.book.getList`是获取书籍列表的方法(上面已经介绍过了) +* 查看 [Datatable's 文档](https://datatables.net/manual/) 了解更多配置项. -The final UI is shown below: +最终的页面如下: ![bookstore-book-list](images/bookstore-book-list.png) -### Next Part +### 下一章 -See the [next part](Part-II.md) of this tutorial. +点击查看 [下一章](Part-II.md) 的介绍. From 57b7c35e001d2c94e9d711a7ad62ac6d39ba8335 Mon Sep 17 00:00:00 2001 From: edison Date: Sat, 13 Oct 2018 16:31:55 +0800 Subject: [PATCH 4/9] Update document Part-I.md --- docs/zh-Hans/Tutorials/AspNetCore-Mvc/Part-I.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/zh-Hans/Tutorials/AspNetCore-Mvc/Part-I.md b/docs/zh-Hans/Tutorials/AspNetCore-Mvc/Part-I.md index 252090d248..d536b550c6 100644 --- a/docs/zh-Hans/Tutorials/AspNetCore-Mvc/Part-I.md +++ b/docs/zh-Hans/Tutorials/AspNetCore-Mvc/Part-I.md @@ -200,7 +200,8 @@ namespace Acme.BookStore * 为应用服务定义接口不是必须的,不过,我们推荐这么做. * `IAsyncCrudAppService`中定义了基础的 **CRUD**方法:`GetAsync`, `GetListAsync`, `CreateAsync`, `UpdateAsync` 和 `DeleteAsync`.不需要扩展它.取而代之,你可以继承空的`IApplicationService`接口定义你自己的方法. -* `IAsyncCrudAppService`有很多的泛型,你可以为每一个方法使用单个或者多个的DTO. +* `IAsyncCrudAppService`有一些变体,你可以为每一个方法使用单个或者多个的DTO.(译者注:意思是类似EntityDto和UpdateEntityDto可以用同一个,也可以分别单独指定 +) #### BookAppService From cfa29ed00cc62b58df3c295498b19fcfe874bd17 Mon Sep 17 00:00:00 2001 From: maliming Date: Sat, 13 Oct 2018 18:46:27 +0800 Subject: [PATCH 5/9] Translate documents under docs/zh-Hans/AspNetCore --- .../AspNetCore/Bundling-Minification.md | 158 +++++++++--------- .../Client-Side-Package-Management.md | 86 +++++----- docs/zh-Hans/Index.md | 2 +- 3 files changed, 125 insertions(+), 121 deletions(-) diff --git a/docs/zh-Hans/AspNetCore/Bundling-Minification.md b/docs/zh-Hans/AspNetCore/Bundling-Minification.md index af92d91243..85af544385 100644 --- a/docs/zh-Hans/AspNetCore/Bundling-Minification.md +++ b/docs/zh-Hans/AspNetCore/Bundling-Minification.md @@ -1,24 +1,25 @@ -## ASP.NET Core MVC Bundling & Minification +## ASP.NET Core MVC 捆绑 & 压缩 -There are many ways of bundling & minification of client side resources (JavaScript and CSS files). Most common ways are: +有许多方法可以捆绑&压缩客户端资源(JavaScript和CSS文件). 最常见的方式是: -* Using the [Bundler & Minifier](https://marketplace.visualstudio.com/items?itemName=MadsKristensen.BundlerMinifier) Visual Studio extension or the [NuGet package](https://www.nuget.org/packages/BuildBundlerMinifier/). -* Using [Gulp](https://gulpjs.com/)/[Grunt](https://gruntjs.com/) task managers and their plugins. +* 使用Visual Studio[捆绑&压缩](https://marketplace.visualstudio.com/items?itemName=MadsKristensen.BundlerMinifier)扩展或者其它的[NuGet相关包](https://www.nuget.org/packages/BuildBundlerMinifier/). -ABP offers a simple, dynamic, powerful, modular and built-in way. +* 使用[Gulp](https://gulpjs.com/)/[Grunt](https://gruntjs.com/)及其插件. -### Volo.Abp.AspNetCore.Mvc.UI.Bundling Package +ABP内置了简单,动态,强大,模块化的方式. -> This package is already installed by default with the startup templates. So, most of the time, you don't need to install it manually. +### Volo.Abp.AspNetCore.Mvc.UI.Bundling 包 -Install the `Volo.Abp.AspNetCore.Mvc.UI.Bundling` nuget package to your project: +> 默认情况下已在启动模板安装此软件包. 大多数情况下,你不需要手动安装它. + +将`Volo.Abp.AspNetCore.Mvc.UI.Bundling` nuget包安装到您的项目中: ```` install-package Volo.Abp.AspNetCore.Mvc.UI.Bundling ```` -Then you can add the `AbpAspNetCoreMvcUiBundlingModule` dependency to your module: +然后将`AbpAspNetCoreMvcUiBundlingModule`依赖项添加到你的模块上: ````C# using Volo.Abp.Modularity; @@ -36,7 +37,7 @@ namespace MyCompany.MyProject ### Razor Bundling Tag Helpers -The simplest way of creating a bundle is to use `abp-script-bundle` or `abp-style-bundle` tag helpers. Example: +创建bundle的最简单方法是使用`abp-script-bundle`或`abp-style-bundle` tag helpers. 例如: ````html @@ -47,26 +48,26 @@ The simplest way of creating a bundle is to use `abp-script-bundle` or `abp-styl ```` -This bundle defines a style bundle with a **unique name**: `MyGlobalBundle`. It's very easy to understand how to use it. Let's see how it *works*: +`abp-script-bundle`定义了一个带有**唯一名称**的样式包:`MyGlobalBundle`. 使用方法很容易理解. 让我们看看它是如何*工作的*: -* ABP creates the bundle as **lazy** from the provided files when it's **first requested**. For the subsequent calls, it's returned from the **cache**. That means if you conditionally add the files to the bundle, it's executed only once and any changes of the condition will not effect the bundle for the next requests. -* ABP adds bundle files **individually** to the page for the `development` environment. It automatically bundles & minifies for other environments (`staging`, `production`...). -* The bundle files may be **physical** files or [**virtual/embedded** files](../Virtual-File-System.md). -* ABP automatically adds **version query string** to the bundle file URL to prevent browsers from caching when the bundle is being updated. (like ?_v=67872834243042 - generated from last change date of the related files). The versioning works even if the bundle files are individually added to the page (on the development environment). +* 当首次请求时,ABP从提供的文件中 **(延迟)lazy** 创建. 后续将从 **缓存** 中返回内容. 这意味着如果你有条件地将文件添加到包中,它只执行一次, 并且条件的任何更改都不会影响下一个请求的包. +* 在`development`环境中ABP会将包文件**单独**添加到页面中, 其他环境(`staging`,`production`...)会自动捆绑和压缩. +* 捆绑文件可以是**物理**文件或[**虚拟/嵌入**](../Virtual-File-System.md)的文件. +* ABP自动将 **版本查询字符串(version query string)** 添加到捆绑文件的URL中,以防止浏览器缓存. 如:?_v=67872834243042(从文件的上次更改日期生成). 即使捆绑文件单独添加到页面(在`development`环境中), 版本控制仍然有效. -#### Importing The Bundling Tag Helpers +#### 导入 Bundling Tag Helpers -> This is already imported by default with the startup templates. So, most of the time, you don't need to add it manually. +> 默认情况下已在启动模板导入. 大多数情况下,你不需要手动安装它. -In order to use bundle tag helpers, you need to add it into your `_ViewImports.cshtml` file or into your page: +要使用`bundle tag helpers`, 你需要将其添加到`_ViewImports.cshtml`文件或页面中: ```` @addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI.Bundling ```` -#### Unnamed Bundles +#### 未命名的 Bundles -The `name` is **optional** for the razor bundle tag helpers. If you don't define a name, it's automatically **calculated** based on the used bundle file names (they are **concatenated** and **hashed**). Example: +对于razor bundle tag helpers, `name`是**可选**. 如果没有定义一个名字,它将根据使用的捆绑文件名自动**计算生成**(they are **concatenated** and **hashed**) 例: ````html @@ -80,33 +81,36 @@ The `name` is **optional** for the razor bundle tag helpers. If you don't define ```` -This will potentially create **two different bundles** (one incudes the `my-global-style.css` and other does not). +这将潜在地创建**两个不同的bundles**(一个包括`my-global-style.css`而另一个则不包括). -Advantages of **unnamed** bundles: +**未命名的** bundles优点: -* Can **conditionally add items** to the bundle. But this may lead to multiple variations of the bundle based on the conditions. +* 可以**有条件地将项目**添加到捆绑包中. 但这可能会导致基于条件的捆绑的存在多种变化. -Advantages of **named** bundles: +**命名** bundles优点: * Other **modules can contribute** to the bundle by its name (see the sections below). +* 其他模块可以通过其名称为捆绑包做出贡献(参见下面的部分). -#### Single File +#### 单个文件 -If you need to just add a single file to the page, you can use the `abp-script` or `abp-style` tag without a wrapping in the `abp-script-bundle` or `abp-style-bundle` tag. Example: +如果你只需要在页面中添加一个文件, 你可以使用`abp-script`或`abp-style`而不需要包含在`abp-script-bundle`或`abp-style-bundle`中. 例: ````xml ```` -The bundle name will be *scripts.my-scripts* for the example above ("/" is replaced by "."). All bundling features are work as expected for single file bundles too. +对于上面的示例,包名称将是 *scripts.my-scripts*("/"替换为"."). 所有捆绑功能也可以按预期应用于单个文件. -### Bundling Options +### Bundling 选项 If you need to use same bundle in **multiple pages** or want to use some more **powerful features**, you can configure bundles **by code** in your [module](../Module-Development-Basics.md) class. -#### Creating A New Bundle +如果你需要在 **多个页面中使用相同的包** 或想要使用更多 **强大功能**, 你可以在[模块](../Module-Development-Basics.md)类中进行**配置**. + +#### 创建一个新的捆绑包 -Example usage: +用法示例: ````C# [DependsOn(typeof(AbpAspNetCoreMvcUiBundlingModule))] @@ -131,20 +135,20 @@ public class MyWebModule : AbpModule } ```` -> You can use the same name (*MyGlobalBundle* here) for a script & style bundle since they are added to different collections (`ScriptBundles` and `StyleBundles`). +> 您可以在脚本和样式包中使用相同的名称(*MyGlobalBundle*), 因为它们被添加到不同的集合(`ScriptBundles`和`StyleBundles`). -After defining such a bundle, it can be included into a page using the same tag helpers defined above. Example: +在定义bundle之后, 可以使用上面定义的相同tag helpers将其包括在页面中. 例如: ````html ```` -This time, no file defined in the tag helper definition because the bundle files are defined by the code. +这次tag helper定义中没有定义文件, 因为捆绑文件是由代码定义的. -#### Configuring An Existing Bundle +#### 配置现有的 Bundle -ABP supports [modularity](../Module-Development-Basics.md) for bundling as well. A module can modify an existing bundle that is created by a dependant module. -Example: +ABP也支持[模块化](../Module-Development-Basics.md)捆绑. 模块可以修改由依赖模块创建的捆绑包. +例如: ````C# [DependsOn(typeof(MyWebModule))] @@ -166,13 +170,13 @@ public class MyWebExtensionModule : AbpModule } ```` -> It's not possible to configure unnamed bundle tag helpers by code, because their name are not known at the development time. It's suggested to always use a name for a bundle tag helper. +> 无法通过代码配置未命名的bundle tag helpers, 因为它们的名称在开发时是未知的. 建议始终使用bundle tag helper的名称. -### Bundle Contributors +### Bundle 贡献者 -Adding files to an existing bundle seems useful. What if you need to **replace** a file in the bundle or you want to **conditionally** add files? Defining a bundle contributor provides extra power for such cases. +将文件添加到现有bundle似乎很有用. 如果你需要**替换**bundle中的文件或者你想**有条件地**添加文件怎么办? 定义bundle贡献者可为此类情况提供额外的功能. -An example bundle contributor that replaces bootstrap.css with a customized version: +一个bundle的贡献者使用自定义版本bootstrap.css替换示例: ````C# public class MyExtensionGlobalStyleContributor : BundleContributor @@ -187,7 +191,7 @@ public class MyExtensionGlobalStyleContributor : BundleContributor } ```` -Then you can use this contributor as below: +然后你可以按照下面的代码使用这个贡献者: ````C# services.Configure(options => @@ -200,8 +204,8 @@ services.Configure(options => }); ```` -Contributors can also be used in the bundle tag helpers. -Example: +贡献者也可以在bundle tag helpers中使用. +例如: ````xml @@ -211,12 +215,12 @@ Example: ```` -`abp-style` and `abp-script` tags can get `type` attributes (instead of `src` attributes) as shown in this sample. When you add a bundle contributor, its dependencies are also automatically added to the bundle. +`abp-style`和`abp-script`标签可以使用`type`属性(而不是`src`属性), 如本示例所示. 添加bundle贡献者时, 其依赖关系也会自动添加到bundle中. #### Contributor Dependencies -A bundle contributor can have one or more dependencies to other contributors. -Example: +bundle贡献者可以与其他贡献者具有一个或多个依赖关系. +例如: ````C# [DependsOn(typeof(MyDependedBundleContributor))] //Define the dependency @@ -226,19 +230,19 @@ public class MyExtensionStyleBundleContributor : BundleContributor } ```` -When a bundle contributor is added, its dependencies are **automatically and recursively** added. Dependencies added by the **dependency order** by preventing **duplicates**. Duplicates are prevented even if they are in separated bundles. ABP organizes all bundles in a page and eliminates duplications. +添加bundle贡献者时,其依赖关系将 **自动并递归** 添加. **依赖顺序** 通过阻止 **重复** 添加的依赖关系. 即使它们处于分离的束中,也会阻止重复. ABP在页面中组织所有bundle并消除重复. -Creating contributors and defining dependencies is a way of organizing bundle creation across different modules. +创建贡献者和定义依赖关系是一种跨不同模块组织包创建的方法. -#### Accessing to the IServiceProvider +#### 访问 IServiceProvider -While it is rarely needed, `BundleConfigurationContext` has a `ServiceProvider` property that you can resolve service dependencies inside the `ConfigureBundle` method. +虽然很少需要它, 但是`BundleConfigurationContext`有一个`ServiceProvider`属性, 你可以在`ConfigureBundle`方法中解析服务依赖. -#### Standard Package Contributors +#### 标准包装贡献者 -Adding a specific NPM package resource (js, css files) into a bundle is pretty straight forward for that package. For example you always add the `bootstrap.css` file for the bootstrap NPM package. +将特定的NPM包资源(js,css文件)添加到包中对于该包非常简单. 例如, 你总是为bootstrap NPM包添加`bootstrap.css`文件. -There are built-in contributors for all [standard NPM packages](Client-Side-Package-Management.md). For example, if your contributor depends on the bootstrap, you can just declare it, instead of adding the bootstrap.css yourself. +所有[标准NPM包](Client-Side-Package-Management.md)都有内置的贡献者. 例如,如果你的贡献者依赖于引导程序,你可以声明它,而不是自己添加bootstrap.css. ````C# [DependsOn(typeof(BootstrapStyleContributor))] //Define the bootstrap style dependency @@ -248,25 +252,25 @@ public class MyExtensionStyleBundleContributor : BundleContributor } ```` -Using the built-in contributors for standard packages; +使用标准包的内置贡献者: -* Prevents you typing **invalid the resource paths**. -* Prevents changing your contributor if the resource **path changes** (the dependant contributor will handle it). -* Prevents multiple modules adding the **duplicate the files**. -* Manages **dependencies recursively** (adds dependencies of dependencies, if necessary). +* 防止你输入**无效的资源路径**. +* 如果资源 **路径发生变化** (依赖贡献者将处理它),则防止更改你的贡献者. +* 防止多个模块添加**重复文件**. +* 以递归方式管理依赖项(如果需要,添加依赖项的依赖项). -##### Volo.Abp.AspNetCore.Mvc.UI.Packages Package +##### Volo.Abp.AspNetCore.Mvc.UI.Packages 包 -> This package is already installed by default in the startup templates. So, most of the time, you don't need to install it manually. +> 默认情况下已在启动模板安装此软件包. 大多数情况下,你不需要手动安装它. -Standard package contributors are defined in the `Volo.Abp.AspNetCore.Mvc.UI.Packages` NuGet package. -To install it to your project: +标准包贡献者在`Volo.Abp.AspNetCore.Mvc.UI.Packages` NuGet包中定义. +安装到你的项目中: ```` install-package Volo.Abp.AspNetCore.Mvc.UI.Packages ```` -Then add the `AbpAspNetCoreMvcUiPackagesModule` module dependency to your own module; +然后将`AbpAspNetCoreMvcUiPackagesModule`模块依赖项添加到你的模块中; ````C# using Volo.Abp.Modularity; @@ -284,8 +288,8 @@ namespace MyCompany.MyProject #### Bundle Inheritance -In some specific cases, it may be needed to create a **new** bundle **inherited** from other bundle(s). Inheriting from a bundle (recursively) inherits all files/contributors of that bundle. Then the derived bundle can add or modify files/contributors **without modifying** the original bundle. -Example: +在某些特定情况下, 可能需要从其他bundle创建一个 **新** bundle **继承**, 从bundle继承(递归)继承该bundle的所有文件/贡献者. 然后派生的bundle可以添加或修改文件/贡献者**而无需修改**原始包. +例如: ````c# services.Configure(options => @@ -302,22 +306,22 @@ services.Configure(options => }); ```` -### Themes +### 主题 -Themes uses the standard package contributors to add library resources to page layouts. Themes may also define some standard/global bundles, so any module can contribute to these standard/global bundles. See the [theming documentation](Theming.md) for more. +主题使用标准包贡献者将库资源添加到页面布局. 主题还可以定义一些标准/全局包, 因此任何模块都可以为这些标准/全局包做出贡献. 有关更多信息, 请参阅[主题文档](Theming.md). -### Best Practices & Suggestions +### 最佳实践 & 建议 -It's suggested to define multiple bundles for an application, each one is used for different purposes. +建议为应用程序定义多个包, 每个包用于不同的目的. -* **Global bundle**: Global style/script bundles are included to every page in the application. Themes already defines global style & script bundles. Your module can contribute to them. -* **Layout bundles**: This is a specific bundle to an individual layout. Only contains resources shared among all the pages use the layout. Use the bundling tag helpers to create the bundle as a good practice. -* **Module bundles**: For shared resources among the pages of an individual module. -* **Page bundles**: Specific bundles created for each page. Use the bundling tag helpers to create the bundle as a best practice. +* **全局包**: 应用程序中的每个页面都包含全局样式/脚本包. 主题已经定义了全局样式和脚本包. 您的模块可以为他们做出贡献. +* **布局包**: 这是针对单个布局的特定包. 仅包含在所有页面之间共享的资源使用布局. 使用bundling tag helpers创建捆绑包是一种很好的做法. +* **模块包**: 用于单个模块页面之间的共享资源. +* **页面包**: 为每个页面创建的特定包. 使用bundling tag helpers创建捆绑包作为最佳实践. -Establish a balance between performance, network bandwidth usage and count of many bundles. +在性能,网络带宽使用和捆绑包的数量之间建立平衡. -### See Also +### 参见 -* [Client Side Package Management](Client-Side-Package-Management.md) -* [Theming](Theming.md) +* [客户端包管理](Client-Side-Package-Management.md) +* [主题](Theming.md) diff --git a/docs/zh-Hans/AspNetCore/Client-Side-Package-Management.md b/docs/zh-Hans/AspNetCore/Client-Side-Package-Management.md index 3c1785daa5..79ea9c4afe 100644 --- a/docs/zh-Hans/AspNetCore/Client-Side-Package-Management.md +++ b/docs/zh-Hans/AspNetCore/Client-Side-Package-Management.md @@ -1,73 +1,73 @@ -## ASP.NET Core MVC Client Side Package Management +## ASP.NET Core MVC 客户端包管理 -ABP framework can work with any type of client side package management systems. You can even decide to use no package management system and manage your dependencies manually. +ABP框架可以与任何类型的客户端包管理系统一起使用. 甚至你可以决定不使用包管理系统并手动管理依赖项. -However, ABP framework works best with **NPM/Yarn**. By default, built-in modules are configured to work with NPM/Yarn. +但是, ABP框架最适用于**NPM/Yarn**. 默认情况下,内置模块配置为与NPM/Yarn一起使用. -Finally, we suggest the [**Yarn**](https://yarnpkg.com/) over the NPM since it's faster, stable and also compatible with the NPM. +最后, 我们建议[**Yarn**](https://yarnpkg.com/)而不是NPM,因为它更快,更稳定并且与NPM兼容. ### @ABP NPM Packages -ABP is a modular platform. Every developer can create modules and the modules should work together in a **compatible** and **stable** state. +ABP是一个模块化平台. 每个开发人员都可以创建模块, 模块应该在**兼容**和**稳定**状态下协同工作. -One challenge is the **versions of the dependant NPM packages**. What if two different modules use the same JavaScript library but its different (and potentially incompatible) versions. +一个挑战是依赖NPM包的**版本**. 如果两个不同的模块使用相同的JavaScript库但其不同(并且可能不兼容)的版本会怎样. -To solve the versioning problem, we created a **standard set of packages** those depends on some common third-party libraries. Some example packages are [@abp/jquery](https://www.npmjs.com/package/@abp/jquery), [@abp/bootstrap](https://www.npmjs.com/package/@abp/bootstrap) and [@abp/font-awesome](https://www.npmjs.com/package/@abp/font-awesome). You can see the **list of packages** from the [Github repository](https://github.com/volosoft/abp/tree/master/npm/packs). +为了解决版本问题, 我们创建了一套**标准包**, 这取决于一些常见的第三方库. 一些示例包是[@abp/jquery](https://www.npmjs.com/package/@abp/jquery), [@ abp/bootstrap](https://www.npmjs.com/package/@abp/bootstrap)和[@abp/font-awesome](https://www.npmjs.com/package/@abp/font-awesome). 你可以从[Github存储库](https://github.com/volosoft/abp/tree/master/npm/packs)中查看**列表**. -The benefit of a **standard package** is: +**标准包**的好处是: -* It depends on a **standard version** of a package. Depending on this package is **safe** because all modules depend on the same version. -* It contains the gulp task to copy library resources (js, css, img... files) from the **node_modules** folder to **wwwroot/libs** folder. See the *Mapping The Library Resources* section for more. - -Depending on a standard package is easy. Just add it to your **package.json** file like you normally do. Example: +* 它取决于包装的**标准版本**。 取决于此包是**安全**,因为所有模块都依赖于相同的版本。 +* 它包含将库资源(js,css,img...文件)从**node_modules**文件夹复制到**wwwroot/libs**文件夹的gulp任务. 有关更多信息, 请参阅 *映射库资源* 部分. +依赖标准包装很容易. 只需像往常一样将它添加到**package.json**文件中. 例如: +```` { ... "dependencies": { "@abp/bootstrap": "^1.0.0" } } +```` +建议依赖于标准软件包, 而不是直接依赖于第三方软件包. -It's suggested to depend on a standard package instead of directly depending on a third-party package. - -#### Package Installation +#### 安装包 -After depending on a NPM package, all you should do is to run the **yarn** command from the command line to install all the packages and their dependencies: +依赖于NPM包后, 你应该做的就是从命令行运行**yarn**命令来安装所有包及其依赖项: ```` yarn ```` -Alternatively, you can use `npm install` but [Yarn](https://yarnpkg.com/) is suggested as mentioned before. +虽然你可以使用`npm install`,但如前所述,建议使用[Yarn](https://yarnpkg.com/). -#### Package Contribution +#### 贡献包 -If you need a third-party NPM package that is not in the standard set of packages, you can create a Pull Request on the Github [repository](https://github.com/volosoft/abp). A pull request that follows these rules is accepted: +如果你需要不在标准软件包中的第三方NPM软件包,您可以在Github[repository](https://github.com/volosoft/abp)上创建Pull请求. 接受遵循这些规则的拉取请求: -* Package name should be named as `@abp/package-name` for a `package-name` on NPM (example: `@abp/bootstrap` for the `bootstrap` package). -* It should be the **latest stable** version of the package. -* It should only depend a **single** third-party package. It can depend on multiple `@abp/*` packages. -* The package should include a `abp.resourcemapping.js` file formatted as defined in the *Mapping The Library Resources* section. This file should only map resources for the depended package. -* You also need to create [bundle contributor(s)](Bundling-Minification.md) for the package you have created. +* 对于NPM上的`package-name`, 包名称应该命名为`@abp/package-name`(例如:`bootstrap`包的`@abp/bootstrap`). +* 它应该是**最新的稳定**版本的包. +* 它应该只依赖于**单个**第三方包. 它可以依赖于多个`@abp/*`包. +* 包应包含一个`abp.resourcemapping.js`文件格式,如*映射库资源*部分中所定义. 此文件应仅映射所依赖包的资源. +* 你还需要为你创建的包创建[bundle贡献者](Bundling-Minification.md). -See current standard packages for examples. +有关示例, 请参阅当前标准包. -### Mapping The Library Resources +### 映射库资源 -Using NPM packages and NPM/Yarn tool is the de facto standard for client side libraries. NPM/Yarn tool creates a **node_modules** folder in the root folder of your web project. +使用NPM包和NPM/Yarn工具是客户端库的事实标准. NPM/Yarn工具在Web项目的根文件夹中创建一个**node_modules**文件夹. -Next challenge is copying needed resources (js, css, img... files) from the `node_modules` into a folder inside the **wwwroot** folder to make it accessible to the clients/browsers. +下一个挑战是将所需的资源(js,css,img ...文件)从`node_modules`复制到**wwwroot**文件夹内的文件夹中,以使其可供客户端/浏览器访问. -ABP defines a [Gulp](https://gulpjs.com/) based task to **copy resources** from **node_modules** to **wwwroot/libs** folder. Each **standard package** (see the *@ABP NPM Packages* section) defines the mapping for its own files. So, most of the time, you only configure dependencies. +ABP将基于[Gulp](https://gulpjs.com/)的任务定义为**将资源**从**node_modules**复制到**wwwroot/libs**文件夹. 每个**标准包**(参见*@ABP NPM Packages*部分)定义了自己文件的映射. 因此, 大多数情况你只配置依赖项. -The **startup templates** are already configured to work all these out of the box. This section will explain the configuration options. +**启动模板**已经配置为开箱即用的所有这些。 本节将介绍配置选项。 -#### Resource Mapping Definition File +#### 资源映射定义文件 -A module should define a JavaScript file named `abp.resourcemapping.js` which is formatted as in the example below: +模块应该定义一个名为`abp.resourcemapping.js`的JavaScript文件,其格式如下例所示: ````js module.exports = { @@ -84,11 +84,11 @@ module.exports = { } ```` -* **aliases** section defines standard aliases (placeholders) that can be used in the mapping paths. **@node_modules** and **@libs** are required (by the standard packages), you can define your own aliases to reduce duplication. -* **clean** section is a list of folders to clean before copying the files. -* **mappings** section is a list of mappings of files/folders to copy. This example does not copy any resource itself, but depends on a standard package. +* **aliases**部分定义了可在映射路径中使用的标准别名(占位符). **@node_modules**和 **@libs**是必需的(通过标准包), 你可以定义自己的别名以减少重复. +* **clean**部分是在复制文件之前要清理的文件夹列表. +* **mappings**部分是要复制的文件/文件夹的映射列表.此示例不会复制任何资源本身,但取决于标准包. -An example mapping configuration is shown below: +示例映射配置如下所示: ````js mappings: { @@ -97,19 +97,19 @@ mappings: { } ```` -#### Using The Gulp +#### 使用 Gulp -Once you properly configure the `abp.resourcemapping.js` file, you can run the gulp command from the command line: +正确配置`abp.resourcemapping.js`文件后, 可以从命令行运行gulp命令: ```` gulp ```` -When you run the `gulp`, all packages will copy their own resources into the **wwwroot/libs** folder. Running `yarn & gulp` is only necessary if you make a change in your dependencies in the **package.json** file. +当你运行`gulp`时,所有包都会将自己的资源复制到**wwwroot/libs**文件夹中. 只有在**package.json**文件中对依赖项进行更改时, 才需要运行`yarn&gulp`. -> When you run the Gulp command, dependencies of the application are resolved using the package.json file. The Gulp task automatically discovers and maps all resources from all dependencies (recursively). +> 运行Gulp命令时, 使用package.json文件解析应用程序的依赖关系. Gulp任务自动发现并映射来自所有依赖项的所有资源(递归). -#### See Also +#### 参见 -* [Bundling & Minification](Bundling-Minification.md) -* [Theming](Theming.md) +* [捆绑 & 压缩](Bundling-Minification.md) +* [主题](Theming.md) diff --git a/docs/zh-Hans/Index.md b/docs/zh-Hans/Index.md index c94c3f1948..6c607ce84b 100644 --- a/docs/zh-Hans/Index.md +++ b/docs/zh-Hans/Index.md @@ -57,7 +57,7 @@ * [客户端包管理](AspNetCore/Client-Side-Package-Management.md) * [捆绑&压缩](AspNetCore/Bundling-Minification.md) * [Tag Helpers](Tag-Helpers.md) - * [主题化](AspNetCore/Theming.md) + * [主题](AspNetCore/Theming.md) * 数据访问 * [Entity Framework Core 集成](Entity-Framework-Core.md) * [MongoDB 集成](MongoDB.md) From b61f05ae49c49224258f0423225db20d6759a17d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A2=81=E5=A3=AB=E4=BC=9F?= Date: Sun, 14 Oct 2018 15:17:24 +0800 Subject: [PATCH 6/9] Translate the base-practices/module-architecture document --- .../zh-Hans/Best-Practices/Domain-Services.md | 2 +- .../Best-Practices/Module-Architecture.md | 164 +++++++++--------- 2 files changed, 83 insertions(+), 83 deletions(-) diff --git a/docs/zh-Hans/Best-Practices/Domain-Services.md b/docs/zh-Hans/Best-Practices/Domain-Services.md index 4ca2115283..d7916ffa96 100644 --- a/docs/zh-Hans/Best-Practices/Domain-Services.md +++ b/docs/zh-Hans/Best-Practices/Domain-Services.md @@ -1,3 +1,3 @@ -## Domain Services Best Practices & Conventions +## 领域服务最佳实践 & 约定 TODO \ No newline at end of file diff --git a/docs/zh-Hans/Best-Practices/Module-Architecture.md b/docs/zh-Hans/Best-Practices/Module-Architecture.md index f37d60d68b..ad38509ef8 100644 --- a/docs/zh-Hans/Best-Practices/Module-Architecture.md +++ b/docs/zh-Hans/Best-Practices/Module-Architecture.md @@ -1,89 +1,89 @@ -## Module Architecture Best Practices & Conventions +## 模块化架构最佳实践 & 约定 -### Solution Structure +### 解决方案结构 -* **Do** create a separated Visual Studio solution for every module. -* **Do** name the solution as *CompanyName.ModuleName* (for core ABP modules, it's *Volo.Abp.ModuleName*). -* **Do** develop the module as layered, so it has several packages (projects) those are related to each other. - * Every package has its own module definition file and explicitly declares the dependencies for the depended packages/modules. +* **推荐** 在Visual Sudio中为每个模块创建一个单独的解决方案. +* **推荐** 将解决方案命名为*CompanyName.ModuleName*(对于ABP核心模块来说,它的命名方式是*Volo.Abp.ModuleName*). +* **推荐** 一个模块做为分层项目开发,因为它有几个包(项目)是相互关联的. + * 每个包都有自己的模块定义文件,并显式声明所依赖的包/模块的依赖关系. -### Layers & Packages +### 层(layers) & 包(packages) -The following diagram shows the packages of a well-layered module and dependencies of those packages between them: +下面展示了一个分层良好的模块中的包以及它们之间的依赖关系: ![module-layers-and-packages](../images/module-layers-and-packages.jpg) -The ultimate goal is to allow an application to use the module in a flexible manner. Example applications: - -* **A)** A **monolithic** application; - * Adds references to the **Web** and the **Application** packages. - * Adds a reference to one of the **EF Core** or the **MongoDB** packages based on the preference. - * The result; - * The application **can show UI** of the module. - * It hosts the **application** and **domain** layers in the **same process** (that's why it needs to have a reference to a database integration package). - * This application also **serves** the module's **HTTP API** (since it includes the HttpApi package through the Web package). -* **B)** An application that just serves the module as a **microservice**; - * Adds a reference to **HttpApi** and **Application** packages. - * Adds a reference to one of the **EF Core** or the **MongoDB** packages based on the preference. - * The result; - * The application **can not show UI** of the module since it does not have a reference to the Web package. - * It hosts the **application** and **domain** layers in the **same process** (that's why it needs to have a reference to a database integration package). - * This application **serves** the module's **HTTP API** (as the main goal of the application). -* **C)** An application that shows the module **UI** but does not host the application (just uses it as a remote service that is hosted by the application A or B); - * Adds a reference to the **Web** and the **HttpApi.Client** packages. - * Configures the remote endpoint for the HttpApi.Client package. - * The result; - * The application **can show UI** of the module. - * It does not host the application and domain layers of the module in the same process. Instead, uses it as a **remote service**. - * This application also **serves** the module's **HTTP API** (since it includes the HttpApi package through the Web package). -* **D)** A **client** application (or microservice) that just uses the module as a remote service (that is hosted by the application A, B or C); - * Adds a reference to the **HttpApi.Client** package. - * Configures the remote endpoint for the HttpApi.Client package. - * The result; - * The application can use all the functionality of the module as a **remote client**. - * The application is just a client and **can not serve** the **HTTP API** of the module. - * The application is just a client and **can not show** the **UI** of the module. -* **E**) A proxy application that hosts the HTTP API of the module but just forwards all requests to another application (that is hosted by the application A, B or C); - * Adds a reference to the **HttpApi** and **HttpApi.Client** packages. - * Configures the remote endpoint for the HttpApi.Client package. - * The result; - * The application can use all the functionality of the module as a **remote client**. - * This application also **serves** the module's **HTTP API**, but actually works just like a proxy by redirecting all requests (for the module) to another remote server. - -Next section describes the packages in more details. - -#### Domain Layer - -* **Do** divide the domain layer into two projects: - * **Domain.Shared** package, named as *CompanyName.ModuleName.Domain.Shared*, that contains constants, enums and other types those can be safely shared with the all layers of the module. This package can also be shared to 3rd-party clients. It can not contain entities, repositories, domain services or any other business objects. - * **Domain** package, named as *CompanyName.ModuleName.Domain*, that contains entities, repository interfaces, domain service interfaces and their implementations and other domain objects. - * Domain package depends on the **Domain.Share** package. - -#### Application Layer - -* **Do** divide the application layer into two projects: - * **Application.Contracts** package, named as *CompanyName.ModuleName.Application.Contracts*, that contains application service interfaces and related data transfer objects. - * Application contract package depends on the **Domain.Shared** package. - * **Application** package, named as *CompanyName.ModuleName.Application*, that contains application service implementations. - * Application package depends on the **Domain** and the **Application.Contracts** packages. - -#### Infrastructure Layer - -* **Do** create a separated integration package for each ORM/database integration like Entity Framework Core and MongoDB. - * **Do**, for instance, create a *CompanyName.ModuleName.EntityFrameworkCore* package that abstracts the Entity Framework Core integration. ORM integration packages depend on the **Domain** package. - * **Do not** depend on other layers from the ORM/database integration package. -* **Do** create a separated integration package for each major library that is planned to be replaceable by another library without effecting the other packages. - -#### HTTP Layer - -* **Do** create an **HTTP API** package, named as *CompanyName.ModuleName.HttpApi*, to develop a REST style HTTP API for the module. - * HTTP API package only depends on the **Application.Contracts** package. It does not depend on the Application package. - * **Do** create a Controller for each application service (generally by implementing their interfaces). These controllers uses the application service interfaces to delegate the actions. It just configures routes, HTTP methods and other web related stuffs if needed. -* **Do** create an **HTTP API Client** package, named as *CompanyName.ModuleName.HttpApi.Client*, to provide client services for the HTTP API package. Those client services implement application interfaces as clients to a remote endpoint. - * HTTP API Client package only depends on the **Application.Contracts** package. - * **Do** use dynamic HTTP C# client proxy feature of the ABP framework. - -#### Web Layer - -* Do create a **Web** package, named as *CompanyName.ModuleName.Web*, that contains pages, views, scripts, styles, images and other UI components. - * Web package only depends on the **HttpApi** package. \ No newline at end of file +最终的目地是让应用程序以灵活的方式使用该模块. 示例应用程序: + +* **A)** **单体**应用程序; + * 添加对**Web**和**Application**包的引用. + * 根据需要添加对**EF Core** 或 **MongoDB** 包的引用. + * 效果; + * 应用程序可以显示**模块的UI**. + * 它在**同一进程**中托管**应用层**和**领域层** (这就是为什么它引用对数据库集成包). + * 此应用程序还提供了模块的**HTTP API**(因为它通过Web包引用了HttpApi包). +* **B)** 仅为**微服务**提供模块的应用程序; + * 添加对**HttpApi**和**Application**包的引用. + * 根据需要添加对**EF Core** 或 **MongoDB** 包的引用. + * 效果; + * 应用程序**无法显示模块的UI**, 因为它没有对Web包的引用. + * 它在**同一进程**中托管**应用层**和**领域层** (这就是为什么它引用对数据库集成包). + * 此应用程序提供了模块的**HTTP API**(它的主要目标). +* **C)** 显示模块**UI**但是不托管应用层的应用程序(仅将其用作由应用程序A或B托管的远程服务) + * 添加对**Web**和**HttpApi.Client**包的引用. + * 配置HttpApi.Client包的远程端点. + * 效果; + * 应用程序可以显示**模块的UI**. + * 它不会在同一进程中托管模块的应用层和领域层. 而是将其用作**远程服务**. + * 此应用程序还提供了模块的**HTTP API**(因为它通过Web包引用了HttpApi包). +* **D)** **客户端**应用程序 (或微服务) 只使用模块作为远程服务(由应用程序A,B或C托管); + * 添加对**HttpApi.Client**包的引用. + * 配置HttpApi.Client包的远程端点. + * 效果; + * 应用程序可以使用模块的所有功能作为**远程客户端**. + * 应用程序只是一个客户端,**无法提供**模块的**HTTP API**. + * 应用程序只是一个客户端,**无法显示**模块的**UI**. +* **E**) 托管模块的HTTP API但只是将所有请求转发给另一个应用程序的代理应用程序 (由应用程序A, B或C托管); + * 添加对**HttpApi**和**HttpApi.Client**包的引用. + * 配置HttpApi.Client包的远程端点. + * 效果; + * 应用程序可以将模块的所有功能用作**远程客户端**. + * 应用程序也服务于模块的**HTTP API**, 但实际上它的工作方式与代理一样,将所有请求(模块)重定向到另一个远程服务器. + +下一节将详细地介绍这些包. + +#### 领域层 + +* **推荐** 将领域层划分为两个项目: + * **Domain.Shared** 包(项目) 命名为*CompanyName.ModuleName.Domain.Shared*,包含常量,枚举和其他类型, 它不能包含实体,存储库,域服务或任何其他业务对象. 可以安全地与模块中的所有层使用. 此包也可以与第三方客户端使用. + * **Domain** 包(项目) 命名为*CompanyName.ModuleName.Domain*, 包含实体, 仓储接口,领域服务接口及其实现和其他领域对象. + * Domain package 依赖于 **Domain.Share** package. + +#### 应用服务层 + +* **推荐** 将应用服务层划分为两个项目: + * **Application.Contracts** 包(项目) 命名为*CompanyName.ModuleName.Application.Contracts,包含应用服务接口和相关的数据传输对象(DTO). + * Application contract package 依赖于 **Domain.Shared** package. + * **Application** 包(项目)命名为*CompanyName.ModuleName.Application*,包含应用服务实现. + * Application package 依赖于 **Domain** 和 **Application.Contracts** packages. + +#### 基础设施层 + +* **推荐** 为每个orm/数据库集成创建一个独立的集成包, 比如Entity Framework Core 和 MongoDB. + * **推荐** 例如, 创建一个抽象Entity Framework Core集成的*CompanyName.ModuleName.EntityFrameworkCore* package. ORM 集成 package 依赖于 **Domain** package. + * **不推荐** 依赖于orm/数据库集成包中的其他层. +* **推荐** 为每个主要的库创建一个独立的集成包, 在不影响其他包的情况下可以被另一个库替换. + +#### HTTP 层 + +* **推荐** 创建命名为*CompanyName.ModuleName.HttpApi*的**HTTP API**包, 为模块开发REST风格的HTTP API. + * HTTP API package 只依赖于 **Application.Contracts** package. 不要依赖 Application package. + * **推荐** 为每个应用服务创建一个Controller (通常通过实现其接口). 这些控制器使用应用服务接口来委托操作. 它根据需要配置路由, HTTP方法和其他与Web相关的东西. +* **推荐** 创建一个为HTTP API包提供客户端服务的**HTTP API Client**包, 它的命名为*companyname.modulename.httpapi*. 这些客户端服务将应用服务接口实现远程端点的客户端. + * HTTP API Client package 仅依赖于 **Application.Contracts** package. + * **推荐** 使用ABP框架提供的动态代理HTTP C#客户端的功能. + +#### Web 层 + +* **推荐** 创建命名为*CompanyName.ModuleName.Web*的 **Web**包. 包含页面,视图,脚本,样式,图像和其他UI组件. + * Web package 仅依赖于 **HttpApi** package. \ No newline at end of file From ae26de50a865909c2474d3dc2f9d9c4e1ed3f09e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A2=81=E5=A3=AB=E4=BC=9F?= Date: Mon, 15 Oct 2018 14:15:07 +0800 Subject: [PATCH 7/9] Translate the base-practices/mongodb-integration document --- .../Entity-Framework-Core-Integration.md | 2 +- .../Best-Practices/MongoDB-Integration.md | 69 ++++++++++--------- 2 files changed, 36 insertions(+), 35 deletions(-) diff --git a/docs/zh-Hans/Best-Practices/Entity-Framework-Core-Integration.md b/docs/zh-Hans/Best-Practices/Entity-Framework-Core-Integration.md index 4e74c7bb46..1e59793a7f 100644 --- a/docs/zh-Hans/Best-Practices/Entity-Framework-Core-Integration.md +++ b/docs/zh-Hans/Best-Practices/Entity-Framework-Core-Integration.md @@ -73,7 +73,7 @@ protected override void OnModelCreating(ModelBuilder builder) } ```` -- **不推荐** 直接在 `OnModelCreating` 方法中配置model,而是为 `ModelBuilder` 定义一个 **扩展方法**. 使用Configure*ModuleName*作为方法名称. 例如: +- **不推荐** 直接在 `OnModelCreating` 方法中配置model, 而是为 `ModelBuilder` 定义一个 **扩展方法**. 使用Configure*ModuleName*作为方法名称. 例如: ````C# public static class IdentityDbContextModelBuilderExtensions diff --git a/docs/zh-Hans/Best-Practices/MongoDB-Integration.md b/docs/zh-Hans/Best-Practices/MongoDB-Integration.md index 32eefadd6a..4c71a58f90 100644 --- a/docs/zh-Hans/Best-Practices/MongoDB-Integration.md +++ b/docs/zh-Hans/Best-Practices/MongoDB-Integration.md @@ -1,12 +1,12 @@ -## MongoDB Integration +## MongoDB 集成 -* Do define a separated `MongoDbContext` interface and class for each module. +* **推荐** 为每个模块定义一个独立的 `MongoDbContext` 接口与实现类. -### MongoDbContext Interface +### MongoDbContext 接口 -- **Do** define an **interface** for the `MongoDbContext` that inherits from `IAbpMongoDbContext`. -- **Do** add a `ConnectionStringName` **attribute** to the `MongoDbContext` interface. -- **Do** add `IMongoCollection` **properties** to the `MongoDbContext` interface only for the aggregate roots. Example: +- **推荐** 定义 `MongoDbContext` **接口** 时继承自 `IAbpMongoDbContext`. +- **推荐** 添加 `ConnectionStringName` **attribute** 到 `MongoDbContext` 接口. +- **推荐** 只把聚合根做为 `IMongoCollection` **properties** 添加到 `MongoDbContext` 接口. 示例: ````C# [ConnectionStringName("AbpIdentity")] @@ -17,11 +17,11 @@ public interface IAbpIdentityMongoDbContext : IAbpMongoDbContext } ```` -### MongoDbContext class +### MongoDbContext 类 -- **Do** inherit the `MongoDbContext` from the `AbpMongoDbContext` class. -- **Do** add a `ConnectionStringName` attribute to the `MongoDbContext` class. -- **Do** implement the corresponding `interface` for the `MongoDbContext` class. Example: +- **推荐** `MongoDbContext` 继承自 `AbpMongoDbContext` 类. +- **推荐** 添加 `ConnectionStringName` **attribute** 到 `MongoDbContext` 类. +- **推荐** `MongoDbContext` 类实现相对应的**接口**. 示例: ```c# [ConnectionStringName("AbpIdentity")] @@ -34,21 +34,21 @@ public class AbpIdentityMongoDbContext : AbpMongoDbContext, IAbpIdentityMongoDbC } ``` -### Collection Prefix +### Collection 前缀 -- **Do** add static `CollectionPrefix` **property** to the `DbContext` class. Set default value from a constant. Example: +- **推荐** 添加静态 `CollectionPrefix` **property** 到 `DbContext` 类中并使用常量为其设置默认值. 示例: ```c# public static string CollectionPrefix { get; set; } = AbpIdentityConsts.DefaultDbTablePrefix; ``` -Used the same constant defined for the EF Core integration table prefix in this example. +在此示例中使用与EF Core集成表前缀相同的常量. -- **Do** always use a short `CollectionPrefix` value for a module to create **unique collection names** in a shared database. `Abp` collection prefix is reserved for ABP core modules. +- **推荐** 总是使用简短的 `CollectionPrefix` 值为模块在共享数据库中创建 **unique collection names**. `Abp` collection前缀是为ABP Core模块保留的. -### Collection Mapping +### Collection 映射 -- **Do** explicitly **configure all aggregate roots** by overriding the `CreateModel` method of the `MongoDbContext`. Example: +- **推荐** 通过重写 `MongoDbContext` 的 `CreateModel` 方法 **配置所有的聚合根** . 示例: ```c# protected override void CreateModel(IMongoModelBuilder modelBuilder) @@ -62,7 +62,7 @@ protected override void CreateModel(IMongoModelBuilder modelBuilder) } ``` -- **Do not** configure model directly in the `CreateModel` method. Instead, create an **extension method** for the `IMongoModelBuilder`. Use Configure*ModuleName* as the method name. Example: +- **不推荐** 直接在 `CreateModel` 方法中配置model,而是为 `IMongoModelBuilder` 定义一个 **扩展方法**. 使用Configure*ModuleName*作为方法名称. 示例: ```c# public static class AbpIdentityMongoDbContextExtensions @@ -90,7 +90,7 @@ public static class AbpIdentityMongoDbContextExtensions } ``` -- **Do** create a **configuration options** class by inheriting from the `MongoModelBuilderConfigurationOptions`. Example: +- **推荐** 通过继承 `MongoModelBuilderConfigurationOptions` 来创建 **configuration Options** 类. 示例: ```c# public class IdentityMongoModelBuilderConfigurationOptions @@ -103,7 +103,7 @@ public class IdentityMongoModelBuilderConfigurationOptions } ``` -* **Do** explicitly configure `BsonClassMap` for all entities. Create a static method for this purpose. Example: +* **推荐** 创建一个静态方法, 显示地为所有的实体配置 `BsonClassMap`. 示例: ````C# public static class AbpIdentityBsonClassMap @@ -129,11 +129,11 @@ public static class AbpIdentityBsonClassMap } ```` -`BsonClassMap` works with static methods. So, it is only needed to configure entities once in an application. `OneTimeRunner` guarantees that it runs in a thread safe manner and only once in the application life. Such a mapping above ensures that unit test properly run. This code will be called by the **module class** below. +`BsonClassMap` 适用于静态方法. 所以只需要在应用程序配置一次实体. `OneTimeRunner` 以线程安全的方式运行, 并且在应用程序生命周期中只运行一次. 上面代码中的映射确保单元测试可以正确运行. 此代码将由下面的**模块类**调用. -### Repository Implementation +### 仓储实现 -- **Do** **inherit** the repository from the `MongoDbRepository` class and implement the corresponding repository interface. Example: +- **推荐** 仓储 **继承自** `MongoDbRepository` 类并且实现其相应的接口. 示例: ```c# public class MongoIdentityUserRepository @@ -148,7 +148,7 @@ public class MongoIdentityUserRepository } ``` -- **Do** pass the `cancellationToken` to the MongoDB Driver using the `GetCancellationToken` helper method. Example: +- **推荐** 使用 `GetCancellationToken` 帮助方法将 `cancellationToken` 传递给MongoDB驱动程序. 示例: ```c# public async Task FindByNormalizedUserNameAsync( @@ -164,19 +164,20 @@ public async Task FindByNormalizedUserNameAsync( } ``` -`GetCancellationToken` fallbacks to the `ICancellationTokenProvider.Token` to obtain the cancellation token if it is not provided by the caller code. +如果调用者代码中未提供取消令牌, 则 `GetCancellationToken` 会从`ICancellationTokenProvider.Token` 获取取消令牌 +`GetCancellationToken`. -* **Do** ignore the `includeDetails` parameters for the repository implementation since MongoDB loads the aggregate root as a whole (including sub collections) by default. -* **Do** use the `GetMongoQueryable()` method to obtain an `IQueryable` to perform queries wherever possible. Because; - * `GetMongoQueryable()` method automatically uses the `ApplyDataFilters` method to filter the data based on the current data filters (like soft delete and multi-tenancy). - * Using `IQueryable` makes the code as much as similar to the EF Core repository implementation and easy to write and read. -* **Do** implement data filtering if it is not possible to use the `GetMongoQueryable()` method. +* **推荐** 忽略仓储实现中的 `includeDetails` 参数, 因为MongoDB在默认情况下将聚合根作为一个整体(包括子集合)加载. +* **推荐** 使用 `GetMongoQueryable()` 方法获取 `IQueryable` 以尽可能执行查询use the `GetMongoQueryable()` method to obtain an `IQueryable` to perform queries wherever possible. 因为; + * `GetMongoQueryable()` 方法在内部使用 `ApplyDataFilters` 方法根据当前的过滤器 (如 软删除与多租户)过滤数据. + * 使用`IQueryable`让代码与EF Core仓储实现类似, 易于使用. +* **推荐** 如果无法使用 `GetMongoQueryable()` 方法, 则应自行实现数据过滤. -### Module Class +### 模块类 -- **Do** define a module class for the MongoDB integration package. -- **Do** add `MongoDbContext` to the `IServiceCollection` using the `AddMongoDbContext` method. -- **Do** add implemented repositories to the options for the `AddMongoDbContext` method. Example: +- **推荐** 为MongoDB集成包定义一个模块类. +- **推荐** 使用 `AddMongoDbContext` 方法将 `MongoDbContext` 添加到 `IServiceCollection`. +- **推荐** 将已实现的仓储添加到 `AddMongoDbContext` 方法options中. 示例: ```c# [DependsOn( @@ -198,4 +199,4 @@ public class AbpIdentityMongoDbModule : AbpModule } ``` -Notice that this module class also calls the static `BsonClassMap` configuration method defined above. \ No newline at end of file +需要注意的是, 模块类还调用上面定义的静态 `BsonClassMap` 配置方法. \ No newline at end of file From d80ca9711727ae336150b18a8156be3a483bfa5b Mon Sep 17 00:00:00 2001 From: personball Date: Tue, 16 Oct 2018 10:36:49 +0800 Subject: [PATCH 8/9] complete translation of docs/zh-Hans/Tutorials/AspNetCore-Mvc/Part-II.md --- .../Tutorials/AspNetCore-Mvc/Part-II.md | 114 +++++++++--------- 1 file changed, 57 insertions(+), 57 deletions(-) diff --git a/docs/zh-Hans/Tutorials/AspNetCore-Mvc/Part-II.md b/docs/zh-Hans/Tutorials/AspNetCore-Mvc/Part-II.md index e35c4d5243..13c1aaa674 100644 --- a/docs/zh-Hans/Tutorials/AspNetCore-Mvc/Part-II.md +++ b/docs/zh-Hans/Tutorials/AspNetCore-Mvc/Part-II.md @@ -1,30 +1,30 @@ -## ASP.NET Core MVC Tutorial - Part II +## ASP.NET Core MVC 教程 - 第二章 -### About this Tutorial +### 关于本教程 -This is the second part of the tutorial series. See all parts: +这是本教程所有章节中的第二章。下面是所有的章节: -* [Part I: Create the project and a book list page](Part-I.md) -* **Part II: Create, Update and Delete books (this tutorial)** -* [Part III: Integration Tests](Part-III.md) +* [Part I: 创建项目和书籍列表页面](Part-I.md) +* **Part II: 创建,编辑,删除书籍(本章)** +* [Part III: 集成测试](Part-III.md) -You can download the **source code** of the application [from here](https://github.com/volosoft/abp/tree/master/samples/BookStore). +你可以从 [这里](https://github.com/volosoft/abp/tree/master/samples/BookStore) 下载本程序的**源码**。 -### Creating a New Book +### 新增 Book 实体 -In this section, you will learn how to create a new modal dialog form to create a new book. The result dialog will be like that: +通过本节, 你将会了解如何创建一个 modal form 来实现新增书籍的功能。 最终成果如下图所示: ![bookstore-create-dialog](images/bookstore-create-dialog.png) -#### Create the Modal Form +#### 新建 modal form -Create a new razor page, named `CreateModal.cshtml` under the `Pages/Books` folder of the `Acme.BookStore.Web` project: +在 `Acme.BookStore.Web` 项目的 `Pages/Books` 目录下新建一个 `CreateModal.cshtml` Razor页面: ![bookstore-add-create-dialog](images/bookstore-add-create-dialog.png) ##### CreateModal.cshtml.cs -Open the `CreateModal.cshtml.cs` file (`CreateModalModel` class) and replace with the following code: +展开 `CreateModal.cshtml`,打开 `CreateModal.cshtml.cs` 代码文件,用如下代码替换 `CreateModalModel` 类的实现: ````C# using System.Threading.Tasks; @@ -53,13 +53,13 @@ namespace Acme.BookStore.Pages.Books } ```` -* This class is derived from the `BookStorePageModelBase` instead of standard `PageModel`. `BookStorePageModelBase` inherits the `PageModel` and adds some common properties/methods those can be used by your page model classes. -* `[BindProperty]` attribute on the `Book` property binds post request data to this property. -* This class simply injects the `IBookAppService` in its constructor and calls the `CreateAsync` method in the `OnPostAsync` handler. +* 这个类继承了 `BookStorePageModelBase` 而非默认的 `PageModel`。 `BookStorePageModelBase` 继承了 `PageModel` 并且添加了一些Razor页面模型通用的属性和方法。 +* 该类在 `Book` 属性上标记的 `[BindProperty]` 特性绑定了post请求提交上来的数据。 +* 该类通过构造函数注入了 `IBookAppService` 应用服务,并且在 `OnPostAsync` 方法中调用了服务的 `CreateAsync` 方法。 ##### CreateModal.cshtml -Open the `CreateModal.cshtml` file and paste the code below: +打开 `CreateModal.cshtml` 文件并粘贴如下代码: ````html @page @@ -80,14 +80,14 @@ Open the `CreateModal.cshtml` file and paste the code below: ```` -* This modal uses `abp-dynamic-form` tag helper to automatically create the form from the `CreateBookViewModel` class. - * `abp-model` attribute indicates the model object, the `Book` property in this case. - * `data-ajaxForm` attribute makes the form submitting via AJAX, instead of a classic page post. - * `abp-form-content` tag helper is a placeholder to render the form controls (this is optional and needed only if you added some other content in the `abp-dynamic-form` tag, just like in this view). +* 这个 modal 使用 `abp-dynamic-form` Tag Helper 根据 `CreateBookViewModel` 类自动构建了表单。 + * `abp-model` 指定了 `Book` 属性为模型对象。 + * `data-ajaxForm` 设置了表单通过AJAX提交。 + * `abp-form-content` tag helper 作为表单控件渲染位置的占位符 (这是可选的,只有你在 `abp-dynamic-form` 中像本示例这样添加了其他内容才需要). -#### Add the "New book" Button +#### 添加 "New book" 按钮 -Open the `Pages/Books/Index.cshtml` and change the `abp-card-header` tag as shown below: +打开 `Pages/Books/Index.cshtml` 并按如下代码修改 `abp-card-header` : ````html @@ -105,11 +105,11 @@ Open the `Pages/Books/Index.cshtml` and change the `abp-card-header` tag as show ```` -Just added a **New book** button to the **top right** of the table: +如下图所示,只是在表格 **右上方** 添加了 **New book** 按钮: ![bookstore-new-book-button](images/bookstore-new-book-button.png) -Open the `wwwroot/pages/books/index.js` and add the following code just after the datatable configuration: +打开 `wwwroot/pages/books/index.js` 在datatable配置代码后面添加如下代码: ````js var createModal = new abp.ModalManager(abp.appPath + 'Books/CreateModal'); @@ -124,19 +124,19 @@ $('#NewBookButton').click(function (e) { }); ```` -* `abp.ModalManager` is a helper class to open and manage modals in the client side. It internally uses Twitter Bootstrap's standard modal, but abstracts many details by providing a simple API. +* `abp.ModalManager` 是一个在客户端打开和管理modal的辅助类。它基于Twitter Bootstrap的标准modal组件通过简化的API抽象隐藏了许多细节. -Now, you can **run the application** and add new books using the new modal form. +现在,你可以 **运行程序** 通过新的 modal form 来创建书籍了。 -### Updating An Existing Book +### 编辑更新已存在的 Book 实体 -Create a new razor page, named `EditModal.cshtml` under the `Pages/Books` folder of the `Acme.BookStore.Web` project: +在 `Acme.BookStore.Web` 项目的 `Pages/Books` 目录下新建一个名叫 `EditModal.cshtml` 的Razor页面: ![bookstore-add-edit-dialog](images/bookstore-add-edit-dialog.png) #### EditModal.cshtml.cs -Open the `EditModal.cshtml.cs` file (`EditModalModel` class) and replace with the following code: +展开 `EditModal.cshtml`,打开 `EditModal.cshtml.cs` 文件( `EditModalModel` 类) 并替换成以下代码: ````C# using System; @@ -176,13 +176,13 @@ namespace Acme.BookStore.Pages.Books } ```` -* `[HiddenInput]` and `[BindProperty]` are standard ASP.NET Core MVC attributes. Used `SupportsGet` to be able to get Id value from query string parameter of the request. -* Mapped `BookDto` (received from the `BookAppService.GetAsync`) to `CreateUpdateBookDto` in the `GetAsync` method. -* The `OnPostAsync` simply uses `BookAppService.UpdateAsync` to update the entity. +* `[HiddenInput]` 和 `[BindProperty]` 是标准的 ASP.NET Core MVC 特性。这里启用 `SupportsGet` 从Http请求的查询字符串中获取Id的值。 +* 在 `OnGetAsync` 方法中,将 `BookAppService.GetAsync` 方法返回的 `BookDto` 映射成 `CreateUpdateBookDto` 并赋值给Book属性。 +* `OnPostAsync` 方法直接使用 `BookAppService.UpdateAsync` 来更新实体。 #### CreateUpdateBookDto -In order to perform `BookDto` to `CreateUpdateBookDto` object mapping, change the `CreateUpdateBookDto` class as shown below: +为了执行从 `BookDto` 到 `CreateUpdateBookDto` 的对象映射, 按如下所示修改 `CreateUpdateBookDto`类: ````C# using System; @@ -211,11 +211,11 @@ namespace Acme.BookStore } ```` -* Just added the `[AutoMapFrom(typeof(BookDto))]` attribute to create the mapping. +* 仅仅是添加 `[AutoMapFrom(typeof(BookDto))]` 特性就可以创建上述映射关系。 #### EditModal.cshtml -Replace `EditModal.cshtml` content with the following content: +将 `EditModal.cshtml` 页面内容替换成如下代码: ````html @page @@ -238,18 +238,18 @@ Replace `EditModal.cshtml` content with the following content: ```` -This page is very similar to the `CreateModal.cshtml` except; +除了以下几点,这个页面内容和 `CreateModal.cshtml` 非常相似: -* It includes an `abp-input` for the `Id` property to store id of the editing book. -* It uses `Books/EditModal` as the post URL and *Update* text as the modal header. +* 此页面包含了一个 `abp-input` 以保存所编辑book实体的 `Id` 属性。 +* 此页面指定的post地址是 `Books/EditModal` ,并用文本 *Update* 作为 modal 标题。 -#### Add "Actions" Dropdown to the Table +#### 为表格添加 "操作(Actions)" 下拉菜单 -We will add a dropdown button ("Actions") for each row of the table. The final UI looks like this: +我们将为表格每行添加下拉按钮 ("Actions") 。 最终效果如下: ![bookstore-books-table-actions](images/bookstore-books-table-actions.png) -Open the `Pages/Books/Index.cshtml` page and change the table section as shown below: +打开 `Pages/Books/Index.cshtml` 页面,并按下方所示修改表格部分的代码: ````html @@ -266,9 +266,9 @@ Open the `Pages/Books/Index.cshtml` page and change the table section as shown b ```` -* Just added a new `th` tag for the "Actions". +* 只是为"Actions"增加了一个 `th` 标签. -Open the `wwwroot/pages/books/index.js` and replace the content as below: +打开 `wwwroot/pages/books/index.js` 并用以下内容进行替换: ````js $(function () { @@ -318,16 +318,16 @@ $(function () { }); ```` -* Used `abp.localization.getResource('BookStore')` to be able to use the same localization texts defined on the server side. -* Added a new `ModalManager` named `editModal` to open the edit modal dialog. -* Added a new column at the beginning of the `columnDefs` section. This column is used for the "Actions" dropdown button. -* "Edit" action simply calls `editModal.open` to open the edit dialog. +* 通过 `abp.localization.getResource('BookStore')` 可以在客户端使用服务器端定义的相同的本地化语言文本。 +* 定义 `editModal` 为 `ModalManager` 来打开编辑用的 modal 对话框。 +* 在 `columnDefs` 起始处新增一列作为 "Actions" 下拉按钮。 +* "Edit" 操作只是简单调用 `editModal.open` 来打开编辑对话框。 -You can run the application and edit any book by selecting the edit action. +现在,你可以运行程序,通过编辑操作来更新任一个book实体。 -### Deleting an Existing Book +### 删除一个已有的Book实体 -Open the `wwwroot/pages/books/index.js` and add a new item to the `rowAction` `items`: +打开 `wwwroot/pages/books/index.js` 文件,在 `rowAction` `items` 下新增一项: ````js { @@ -346,11 +346,11 @@ Open the `wwwroot/pages/books/index.js` and add a new item to the `rowAction` `i } ```` -* `confirmMessage` option is used to ask a confirmation question before executing the `action`. -* Used `acme.bookStore.book.delete` javascript proxy function to perform an AJAX request to delete a book. -* `abp.notify.info` is used to show a toastr notification just after the deletion. +* `confirmMessage` 用来在实际执行 `action` 之前向用户进行确认。 +* 通过javascript代理方法 `acme.bookStore.book.delete` 执行一个AJAX请求来删除一个book实体。 +* `abp.notify.info` 用来提示用户操作成功。 -The final `index.js` content is shown below: +最终的 `index.js` 文件内容如下所示: ````js $(function () { @@ -414,8 +414,8 @@ $(function () { }); ```` -Run the application and try to delete a book. +运行程序并尝试删除一个book实体。 -### Next Part +### 下一章 -See the [next part](Part-III.md) of this tutorial. \ No newline at end of file +查看本教程的 [下一章](Part-III.md) 。 \ No newline at end of file From b50af885d058598f7a29164c658f178ebf324e7c Mon Sep 17 00:00:00 2001 From: personball Date: Tue, 16 Oct 2018 11:24:42 +0800 Subject: [PATCH 9/9] complete translation of docs/zh-Hans/Tutorials/AspNetCore-Mvc/Part-III.md --- .../Tutorials/AspNetCore-Mvc/Part-III.md | 52 +++++++++---------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/docs/zh-Hans/Tutorials/AspNetCore-Mvc/Part-III.md b/docs/zh-Hans/Tutorials/AspNetCore-Mvc/Part-III.md index a45d406ce6..8469dca520 100644 --- a/docs/zh-Hans/Tutorials/AspNetCore-Mvc/Part-III.md +++ b/docs/zh-Hans/Tutorials/AspNetCore-Mvc/Part-III.md @@ -2,32 +2,32 @@ ### About this Tutorial -This is the third part of the tutorial series. See all parts: +这是本教程所有章节中的第三章。下面是所有的章节: -- [Part I: Create the project and a book list page](Part-I.md) -- [Part II: Create, Update and Delete books](Part-II.md) -- **Part III: Integration Tests (this tutorial)** +- [Part I: 创建项目和书籍列表页面](Part-I.md) +- [Part II: 创建,编辑,删除书籍](Part-II.md) +- **Part III: 集成测试(本章)** -You can download the **source code** of the application [from here](https://github.com/volosoft/abp/tree/master/samples/BookStore). +你可以从 [这里](https://github.com/volosoft/abp/tree/master/samples/BookStore) 下载本程序的**源码**。 -### Test Projects in the Solution +### 解决方案中的测试项目 -There are two test projects in the solution: +本解决方案中有两个测试项目: ![bookstore-test-projects](images/bookstore-test-projects.png) -* `Acme.BookStore.Application.Tests` is for unit & integration tests. You can write tests for application service methods. It uses **EF Core SQLite in-memory** database. -* `Acme.BookStore.Web.Tests` is for full stack integration tests including the web layer. So, you can write tests for UI pages too. +* `Acme.BookStore.Application.Tests` 项目用于单元测试和集成测试。你可以在这个项目中为Application Service方法写测试代码。这个项目使用了 **EF Core SQLite in-memory** 数据库。 +* `Acme.BookStore.Web.Tests` 项目用于包含Web层的完整集成测试。所以,你也可以在这里写关于UI页面的测试。 -Test projects use the following libraries for testing: +测试项目使用了以下库: -* [xunit](https://xunit.github.io/) as the main test framework. -* [Shoudly](http://shouldly.readthedocs.io/en/latest/) as an assertion library. -* [NSubstitute](http://nsubstitute.github.io/) as a mocking library. +* [xunit](https://xunit.github.io/) 作为主测试框架。 +* [Shoudly](http://shouldly.readthedocs.io/en/latest/) 作为断言库。 +* [NSubstitute](http://nsubstitute.github.io/) 作为模拟库。 -### Adding Test Data +### 添加测试用数据 -Startup template contains the `BookStoreTestDataBuilder` class in the `Acme.BookStore.Application.Tests` project that creates some data to run tests on. It's shown below: +起始模板在 `Acme.BookStore.Application.Tests` 项目中包含了 `BookStoreTestDataBuilder` 类,用于创建一些测试用数据。 相关代码如下所示: ````C# using System.Threading.Tasks; @@ -59,10 +59,10 @@ namespace Acme.BookStore } ```` -* It simply uses `IIdentityDataSeeder` which is implemented by the identity module and creates an admin role and admin user. You can use them in your tests. -* You can add new test data in the `BuildInternalAsync` method. +* 这里直接使用了identity模块实现的 `IIdentityDataSeeder` 接口,创建了一个admin角色和admin用户。你同样可以在你的测试代码中直接使用这些代码。 +* 你可以在 `BuildInternalAsync` 方法中添加你自己的测试数据。 -Change the `BookStoreTestDataBuilder` class as show below: +按下方所示修改 `BookStoreTestDataBuilder` 类: ````C# using System; @@ -122,11 +122,11 @@ namespace Acme.BookStore } ```` -* Injected `IRepository` and used it in the `BuildInternalAsync` to create two book entities. +* 通过构造函数注入 `IRepository`,在 `BuildInternalAsync` 方法中用它创建两个book实体。 -### Testing the BookAppService +### 测试 BookAppService -Create a test class named `BookAppService_Tests` in the `Acme.BookStore.Application.Tests` project: +在 `Acme.BookStore.Application.Tests` 项目中创建一个名叫 `BookAppService_Tests` 的测试类: ````C# using System.Threading.Tasks; @@ -161,9 +161,9 @@ namespace Acme.BookStore } ```` -* `Should_Get_List_Of_Books` test simply uses `BookAppService.GetListAsync` method to get and check the list of users. +* 测试方法 `Should_Get_List_Of_Books` 直接使用 `BookAppService.GetListAsync` 方法来获取用户列表,并执行检查。 -Add a new test that creates a valid new book: +新增测试方法,用以测试创建一个合法book实体的场景: ````C# [Fact] @@ -186,7 +186,7 @@ public async Task Should_Create_A_Valid_Book() } ```` -Add a new test that tries to create an invalid book and fails: +新增测试方法,用以测试创建一个非法book实体失败的场景: ````C# [Fact] @@ -210,8 +210,8 @@ public async Task Should_Not_Create_A_Book_Without_Name() } ```` -* Since the `Name` is empty, ABP throws an `AbpValidationException`. +* 由于 `Name` 是空值, ABP 抛出一个 `AbpValidationException` 异常。 -### Testing Web Pages +### 测试 Web 页面 TODO \ No newline at end of file