Browse Source

Translate the best-practices/application-services document

pull/550/head
梁士伟 8 years ago
parent
commit
814610f37b
  1. 176
      docs/zh-Hans/Best-Practices/Application-Services.md

176
docs/zh-Hans/Best-Practices/Application-Services.md

@ -1,29 +1,29 @@
## Application Services Best Practices & Conventions ## 应用服务最佳实践 & 约定
* **Do** create an application service for each **aggregate root**. * **推荐** 为每个 **聚合根** 创建一个应用服务.
### Application Service Interface ### 应用服务接口
* **Do** define an `interface` for each application service in the **application contracts** package. * **推荐** 在 **application.contracts**层中为每一个应用服务定义一个`接口`.
* **Do** inherit from the `IApplicationService` interface. * **推荐** 继承 `IApplicationService` 接口 .
* **Do** use the `AppService` postfix for the interface name (ex: `IProductAppService`). * **推荐** 接口名称使用`AppService` 后缀 (如: `IProductAppService`).
* **Do** create DTOs (Data Transfer Objects) for inputs and outputs of the service. * **推荐** 为服务创建输入输出DTO(数据传输对象).
* **Do not** get/return entities for the service methods. * **不推荐** 服务中含有返回实体的方法.
* **Do** define DTOs based on the [DTO best practices](Data-Transfer-Objects.md). * **推荐** 根据[DTO 最佳实践](Data-Transfer-Objects.md)定义DTO.
#### Outputs #### 输出
* **Avoid** to define too many output DTOs for same or related entities. Instead, define a **basic** and a **detailed** DTO for an entity. * **避免** 为相同或相关实体定义过多的输出DTO. 为实体定义 **基础** 和 **详细** DTO.
##### Basic DTO ##### 基础DTO
**Do** define a **basic** DTO for an entity. **推荐** 为实体定义一个**基础**DTO.
- Include all the **primitive properties** directly on the entity. - 直接包含实体中所有的**原始属性**.
- Exception: Can **exclude** properties for **security** reasons (like User.Password). - 例外: 出于**安全**原因,可以**排除**某些属性(像 `User.Password`).
- Include all the **sub collections** of the entity where every item in the collection is a simple **relation DTO**. - 包含实体中所有**子集合**, 每个集合项都是一个简单的**关系DTO**.
Example: 示例:
```c# ```c#
public class IssueDto : FullAuditedEntityDto<Guid> public class IssueDto : FullAuditedEntityDto<Guid>
@ -41,17 +41,17 @@ public class IssueLabelDto
} }
``` ```
##### Detailed DTO ##### 详细DTO
**Do** define a **detailed** DTO for an entity if it has reference(s) to other aggregate roots. **Do** 如果实体持有对其他聚合根的引用,那么应该为其定义**详细**DTO.
* Include all the **primitive properties** directly on the entity. * 直接包含实体中所有的 **原始属性**.
- Exception-1: Can **exclude** properties for **security** reasons (like `User.Password`). - 例外-1: 出于**安全**原因,可以**排除**某些属性(像 `User.Password`).
- Exception-2: **Do** exclude reference properties (like `MilestoneId` in the example above). Will already add details for the reference properties. - 例外-2: **推荐** 排除引用属性(如上例中的 `MilestoneId`). 为其添加引用属性的详细信息.
* Include a **basic DTO** property for every reference property. * 为每个引用属性添加其**基本DTO** .
* Include all the **sub collections** of the entity where every item in the collection is the **basic DTO** of the related entity. * 包含实体的**所有子集合**, 集合中的每项都是相关实体的基本DTO.
Example: 示例:
````C# ````C#
public class IssueWithDetailsDto : FullAuditedEntityDto<Guid> public class IssueWithDetailsDto : FullAuditedEntityDto<Guid>
@ -75,58 +75,57 @@ public class LabelDto : EntityDto<Guid>
} }
```` ````
#### Inputs #### 输入
* **Do not** define any property in an input DTO that is not used in the service class. * **不推荐** 在输入DTO中定义未在服务类中使用的属性.
* **Do not** share input DTOs between application service methods. * **不推荐** 在应用服务方法之间共享输入DTO.
* **Do not** inherit an input DTO class from another one. * **不推荐** 继承另一个输入DTO类.
* **May** inherit from an abstract base DTO class and share some properties between different DTOs in that way. However, should be very careful in that case because manipulating the base DTO would effect all related DTOs and service methods. Avoid from that as a good practice. * **可以** 继承自抽象基础DTO类, 并以这种方式在不同的DTO之间共享一些属性. 但是在这种情况下需要非常小心, 因为更新基础DTO会影响所有相关的DTO和服务方法. 所以避免这样做是一种好习惯.
#### Methods #### 方法
* **Do** define service methods as asynchronous with **Async** postfix. * **推荐** 为异步方法使用 **Async** 后缀.
* **Do not** repeat the entity name in the method names. * **不推荐** 在方法名中重复实体的名称.
* Example: Define `GetAsync(...)` instead of `GetProductAsync(...)` in the `IProductAppService`. * 例如: 在 `IProductAppService` 中定义`GetProductAsync(...)` 而不是 `GetAsync(...)` .
##### Getting A Single Entity ##### 获取单一实体
* **Do** use the `GetAsync` **method name**. * **推荐** 使用 `GetAsync` 做为**方法名**.
* **Do** get Id with a **primitive** method parameter. * **推荐** 使用id做为方法参数.
* Return the **detailed DTO**. Example: * 返回 **详细DTO**. 示例:
````C# ````C#
Task<QuestionWithDetailsDto> GetAsync(Guid id); Task<QuestionWithDetailsDto> GetAsync(Guid id);
```` ````
##### Getting A List Of Entities ##### 获取实体集合
* **Do** use the `GetListAsync` **method name**. * **推荐** 使用 `GetListAsync` 做为**方法名**.
* **Do** get a single DTO argument for **filtering**, **sorting** and **paging** if necessary. * **推荐** 如果需要获取单个DTO可以使用参数进行 **过滤**, **排序** 和 **分页**.
* **Do** implement filters optional where possible. * **推荐** 尽可能让过滤参数可选.
* **Do** implement sorting & paging properties as optional and provide default values. * **推荐** 将排序与分页属性设置为可选, 并且提供默认值.
* **Do** limit maximum page size (for performance reasons). * **推荐** 限制最大页数大小 (基本性能考虑).
* **Do** return a list of **detailed DTO**s. Example: * **推荐** 返回 **详细DTO**集合. 示例:
````C# ````C#
Task<List<QuestionWithDetailsDto>> GetListAsync(QuestionListQueryDto queryDto); Task<List<QuestionWithDetailsDto>> GetListAsync(QuestionListQueryDto queryDto);
```` ````
##### Creating A New Entity ##### 创建一个新实体
* **Do** use the `CreateAsync` **method name**. * **推荐** 使用 `CreateAsync` 做为**方法名**.
* **Do** get a **specialized input** DTO to create the entity. * **推荐** 使用**专门的输入DTO**来创建实体.
* **Do** use **data annotations** for input validation. * **推荐** 使用 **data annotations** 进行输入验证.
* Share constants between domain wherever possible (via constants defined in the **domain shared** package). * 尽可能在**领域**之间共享常量(通过域**domain shared** package定义的常量).
* **Do** return **the detailed** DTO for new created entity. * **推荐** 只需要创建实体的**最少**信息, 但是提供了其他可选属性.
* **Do** only require the **minimum** info to create the entity but provide possibility to set others as optional properties.
Example **method**: 示例**方法**:
````C# ````C#
Task<QuestionWithDetailsDto> CreateAsync(CreateQuestionDto questionDto); Task<QuestionWithDetailsDto> CreateAsync(CreateQuestionDto questionDto);
```` ````
The related **DTO**: 输入**DTO**:
````C# ````C#
public class CreateQuestionDto public class CreateQuestionDto
@ -142,68 +141,65 @@ public class CreateQuestionDto
} }
```` ````
##### Updating An Existing Entity ##### 更新已存在的实体
- **Do** use the `UpdateAsync` **method name**. - **推荐** 使用 `UpdateAsync` 做为**方法名**.
- **Do** get a **specialized input** DTO to update the entity. - **推荐** 使用**专门的输入DTO**来更新实体.
- **Do** get the Id of the entity as a separated primitive parameter. Do not include to the update DTO. - **推荐** 获取实体的id做为分离的原始参数. 不要包含更新DTO.
- **Do** use **data annotations** for input validation. - **推荐** 使用 **data annotations** 进行输入验证.
- Share constants between domain wherever possible (via constants defined in the **domain shared** package). - 尽可能在**领域**之间共享常量(通过域**domain shared** package定义的常量).
- **Do** return **the detailed** DTO for the updated entity. - **推荐** 返回更新实体的**详细**DTO.
Example: 示例:
````C# ````C#
Task<QuestionWithDetailsDto> UpdateAsync(Guid id, UpdateQuestionDto updateQuestionDto); Task<QuestionWithDetailsDto> UpdateAsync(Guid id, UpdateQuestionDto updateQuestionDto);
```` ````
##### Deleting An Existing Entity ##### 删除已存在的实体
- **Do** use the `DeleteAsync` **method name**. - **推荐** 使用 `DeleteAsync` 做为**方法名**.
- **Do** get Id with a **primitive** method parameter. Example: - **推荐** 使用原始参数 id. 示例:
````C# ````C#
Task DeleteAsync(Guid id); Task DeleteAsync(Guid id);
```` ````
##### Other Methods ##### 其他方法
* **Can** define additional methods to perform operations on the entity. Example: * **可以** 定义其他方法以对实体执行操作. 示例:
````C# ````C#
Task<int> VoteAsync(Guid id, VoteType type); Task<int> VoteAsync(Guid id, VoteType type);
```` ````
This method votes a question and returns the current score of the question. 此方法为试题投票并返回试题的当前分数.
### Application Service Implementation ### 应用服务实现
* **Do** develop the application layer **completely independent from the web layer**. * **推荐** 开发**完全独立于web层**的应用层.
* **Do** implement application service interfaces in the **application layer**. * **推荐** 在**应用层**实现应用服务接口.
* **Do** use the naming convention. Ex: Create `ProductAppService` class for the `IProductAppService` interface. * **推荐** 使用命名约定. 如: 为 `IProductAppService` 接口创建 `ProductAppService` 类.
* **Do** inherit from the `ApplicationService` base class. * **推荐** 继承自 `ApplicationService` 基类.
#### Using Repositories #### 使用仓储
* **Do** use the specifically designed repositories (like `IProductRepository`). * **推荐** 使用专门设计的仓储 (如 `IProductRepository`).
* **Do not** use generic repositories (like `IRepository<Product>`). * **不推荐** 使用泛型仓储 (如 `IRepository<Product>`).
#### Querying Data #### 查询数据
* **Do not** use LINQ/SQL for querying data from database inside the application service methods. It's repository's responsibility to perform LINQ/SQL queries from the data source. * **不推荐** 在应用程序服务方法中使用linq/sql查询来自数据库的数据. 让仓储负责从数据源执行linq/sql查询.
#### Manipulating / Deleting Entities #### 操作/删除 实体
* **Do** always get all the related entities from repositories to perform the operations on them.
#### Using Other Application Services
* **Do not** use other application services of the same module/application. Instead;
* Use domain layer to perform the required task.
* Extract a new class and share between the application services to accomplish the code reuse when necessary.
* **Can** use application services of others only if;
* They are parts of another module / microservice.
* The current module has only reference to the application contracts of the used module.
* **推荐** 总是从数据库中获取所有的相关实体以对他们执行操作.
#### 使用其他应用服务
* **不推荐** 使用相同 **模块/应用程序** 的其他应用服务. 相反;
* 使用领域层执行所需的任务.
* 提取新类并在应用程序服务之间共享, 在必要时代码重用.
* **可以** 在以下情况下使用其他应用服务;
* 它们是另一个模块/微服务的一部分.
* 当前模块仅引用已使用模块的application contracts.
Loading…
Cancel
Save