Application Service Implementation Logic
Files referenced in this document
- MyEntityNameAppService.cs
- IMyEntityNameAppService.cs
- IMyEntityNameRepository.cs
- MyEntityName.cs
- MyEntityNameAutoMapperProfile.cs
Table of Contents
- Introduction
- Dependency Injection and Service Coordination
- Core Method Execution Flow
- Batch Operation Implementation Strategy
- Error Handling and Validation Mechanism
- Transaction Boundaries and Performance Considerations
- Extensibility and Responsibility Boundaries
Introduction
MyEntityNameAppService is the core application service in the CMS plugin responsible for handling business logic for the MyEntityName entity. Following Domain-Driven Design (DDD) principles, this service coordinates domain entities, repository interfaces, and object mappers via dependency injection to implement entity CRUD and batch operations. This document deeply analyzes its concrete implementation mechanisms to help developers understand service layer responsibility division and extension methods.
Section sources
Dependency Injection and Service Coordination
The MyEntityNameAppService class decouples access to domain layer services by injecting IMyEntityNameRepository and the base class inherited ObjectMapper via the constructor.
- IMyEntityNameRepository: Defines the data access contract for
MyEntityNameentities, encapsulating database operation details. - IObjectMapper: Provided by the base class
CMSPluginAppService, used for automatic mapping between domain entityMyEntityNameand Data Transfer Objects (DTOs). - GuidGenerator: Used to generate unique identifiers, ensuring global uniqueness of new entity IDs.
This design pattern concentrates business orchestration logic in the application service layer while maintaining low coupling with infrastructure and domain models.
Diagram sources
Core Method Execution Flow
CreateAsync Method Flow
The CreateAsync method is used to create a new MyEntityName entity, with the following execution flow:
- Call
CheckCreateOrUpdateDtoAsyncto validate input DTO parameters. - Check if the name already exists; if so, throw a user-friendly exception.
- Get the current maximum sort value to use as the default sort for the new entity.
- Create a new
MyEntityNameentity instance and map extra properties. - Call the repository's
InsertAsyncmethod to persist the entity. - If a sort value is specified and different from the default, call
AdjustSortAsyncto adjust sorting. - Return the mapped DTO.
Diagram sources
UpdateAsync Method Flow
The UpdateAsync method is used to update an existing entity:
- Execute DTO parameter validation.
- Retrieve the existing entity from the repository.
- Check if the new name conflicts with other entities (excluding itself).
- Update the entity's
ConcurrencyStampand extra properties. - Call the entity's
Updatemethod to set business fields. - Persist the updated entity.
- Return the DTO.
Diagram sources
DeleteAsync and GetListAsync Methods
- DeleteAsync: Directly delegates to the repository's
DeleteAsyncmethod to implement logical or physical deletion. - GetListAsync: Receives pagination and filtering parameters, builds query specifications, calls the repository to get total count and list, and maps them to a DTO list via
ObjectMapperto return.
Section sources
Batch Operation Implementation Strategy
CloneAsync Batch Clone
The CloneAsync method supports batch cloning of multiple entities:
- Iterate through the input ID list, retrieving original entities one by one.
- Generate a new name for the clone (append "Copy" tag) and ensure name uniqueness.
- Call the entity's
Clonemethod to create a copy and insert into the database. - Collect all successfully cloned entities and return their DTO list.
This method executes database insertions within a loop and does not use bulk operations, which may affect performance.
DeleteManyAsync Batch Delete
DeleteManyAsync is implemented by iterating through the ID list and calling DeleteAsync individually. This implementation is simple but less efficient; implementing true batch deletion in the repository layer is recommended for better performance.
ImportAsync and ExportAsync
- ImportAsync: Supports importing data from Excel. First performs row-level validation (e.g., duplicate names), then executes create or update operations in batches, with good error feedback mechanisms.
- ExportAsync: Exports data based on query conditions, returning dictionary-formatted Sheet data and filename, facilitating frontend Excel generation.
Diagram sources
Error Handling and Validation Mechanism
The service layer implements multi-level error handling and validation:
- Parameter Validation: Uses
Check.NotNull,Check.NotNullOrWhiteSpace, etc., for pre-validation. - Business Rule Validation: Checks like name uniqueness via
NameExistAsyncmethod. - User-Friendly Exceptions: Uses
UserFriendlyExceptionto pass readable error information to the frontend. - Exception Wrapping: Captures underlying exceptions in
ImportAsyncand wraps them as user-friendly exceptions with row number information.
Section sources
Transaction Boundaries and Performance Considerations
- Transaction Boundaries: Current implementation relies on default transaction behavior of the repository layer or database context. Explicit use of
ICurrentUnitOfWorkto control transactions is recommended when necessary. - Performance Optimization:
GetListAsyncuses pagination and filtering to avoid full table scans.AdjustSortAsyncloads all entities at once for sorting adjustment, reducing database interaction counts.- Batch operations (like
DeleteManyAsync) have performance bottlenecks; optimizing to single database calls in the repository layer is suggested.
Section sources
Extensibility and Responsibility Boundaries
MyEntityNameAppService clearly delineates application layer responsibilities:
- Responsibilities: Coordinating domain objects, executing application-level business logic, handling DTO conversions, managing transaction boundaries.
- Non-Responsibilities: Does not contain complex domain rules (handled by entity methods), does not directly access the database (via repository).
- Extension Methods: Custom logic can be implemented via inheritance or adding new methods; DTO and repository interfaces support flexible extension.
Section sources