# Application Services Best Practices & Conventions
> This document offers best practices for implementing Application Services classes in your modules and applications based on Domain-Driven-Design principles.
>
> **Ensure you've read the [*Application Services*](../domain-driven-design/application-services.md) document first.**
## General
* **Do** create an application service for each **aggregate root**.
### Application Service Interface
## Application Service Interface
* **Do** define an `interface` for each application service in the **application contracts** package.
* **Do** inherit from the `IApplicationService` interface.
@ -11,11 +17,11 @@
* **Do not** get/return entities for the service methods.
* **Do** define DTOs based on the [DTO best practices](data-transfer-objects.md).
#### Outputs
### Outputs
* **Avoid** to define too many output DTOs for same or related entities. Instead, define a **basic** and a **detailed** DTO for an entity.
##### Basic DTO
#### Basic DTO
**Do** define a **basic** DTO for an aggregate root.
@ -44,7 +50,7 @@ public class IssueLabelDto
}
```
##### Detailed DTO
#### Detailed DTO
**Do** define a **detailed** DTO for an entity if it has reference(s) to other aggregate roots.
@ -81,20 +87,20 @@ public class LabelDto : ExtensibleEntityDto<Guid>
}
````
#### Inputs
### Inputs
* **Do not** define any property in an input DTO that is not used in the service class.
* **Do not** share input DTOs between application service methods.
* **Do not** inherit an input DTO class from another one.
* **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.
#### Methods
### Methods
* **Do** define service methods as asynchronous with **Async** postfix.
* **Do not** repeat the entity name in the method names.
* Example: Define `GetAsync(...)` instead of `GetProductAsync(...)` in the `IProductAppService`.
##### Getting A Single Entity
#### Getting A Single Entity
* **Do** use the `GetAsync`**method name**.
* **Do** get Id with a **primitive** method parameter.
@ -104,7 +110,7 @@ public class LabelDto : ExtensibleEntityDto<Guid>
Task<QuestionWithDetailsDto> GetAsync(Guid id);
````
##### Getting A List Of Entities
#### Getting A List Of Entities
* **Do** use the `GetListAsync`**method name**.
* **Do** get a single DTO argument for **filtering**, **sorting** and **paging** if necessary.
This method votes a question and returns the current score of the question.
### Application Service Implementation
## Application Service Implementation
* **Do** develop the application layer **completely independent from the web layer**.
* **Do** implement application service interfaces in the **application layer**.
@ -195,30 +201,30 @@ This method votes a question and returns the current score of the question.
* **Do** make all public methods **virtual**, so developers may inherit and override them.
* **Do not** make **private** methods. Instead make them **protected virtual**, so developers may inherit and override them.
#### Using Repositories
### Using Repositories
* **Do** use the specifically designed repositories (like `IProductRepository`).
* **Do not** use generic repositories (like `IRepository<Product>`).
#### Querying Data
### 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.
#### Extra Properties
### Extra Properties
* **Do** use either `MapExtraPropertiesTo` extension method ([see](../../fundamentals/object-extensions.md)) or configure the object mapper (`MapExtraProperties`) to allow application developers to be able to extend the objects and services.
#### Manipulating / Deleting Entities
### Manipulating / Deleting Entities
* **Do** always get all the related entities from repositories to perform the operations on them.
* **Do** call repository's Update/UpdateAsync method after updating an entity. Because, not all database APIs support change tracking & auto update.
#### Handle files
### Handle files
* **Do not** use any web components like `IFormFile` or `Stream` in the application services. If you want to serve a file you can use `byte[]`.
* **Do** use a `Controller` to handle file uploading then pass the `byte[]` of the file to the application service method.
#### Using Other Application Services
### Using Other Application Services
* **Do not** use other application services of the same module/application. Instead;
# Data Transfer Objects Best Practices & Conventions
> This document offers best practices for implementing Data Transfer Object classes in your modules and applications based on Domain-Driven-Design principles.
>
> **Ensure you've read the [*Data Transfer Objects*](../domain-driven-design/data-transfer-objects.md) document first.**
## General
* **Do** define DTOs in the **application contracts** package.
* **Do** inherit from the pre-built **base DTO classes** where possible and necessary (like `EntityDto<TKey>`, `CreationAuditedEntityDto<TKey>`, `AuditedEntityDto<TKey>`, `FullAuditedEntityDto<TKey>` and so on).
* **Do** inherit from the **extensible DTO** classes for the **aggregate roots** (like `ExtensibleAuditedEntityDto<TKey>`), because aggregate roots are extensible objects and extra properties are mapped to DTOs in this way.
> This document offers best practices for implementing Domain Service classes in your modules and applications based on Domain-Driven-Design principles.
>
> **Ensure you've read the [*Domain Services*](../domain-driven-design/domain-services.md) document first.**
## Domain Services
- **Do** define domain services in the **domain layer**.
- **Do not** create interfaces for the domain services **unless** you have a good reason to (like mock and test different implementations).
@ -14,7 +18,7 @@ public class IssueManager : DomainService
}
```
### Domain Service Methods
## Domain Service Methods
- **Do not** define `GET` methods. `GET` methods do not change the state of an entity. Hence, use the repository directly in the Application Service instead of Domain Service method.
- **Do not** return `DTO`. Return only domain objects when you need.
- **Do not** involve authenticated user logic. Instead, define extra parameter and send the related data of ` CurrentUser` from the Application Service layer.
> This document offers best practices for implementing Aggregate Root and Entity classes in your modules and applications based on Domain-Driven-Design principles.
>
> **Ensure you've read the [*Entities*](../domain-driven-design/entities.md) document first.**
## Entities
Every aggregate root is also an entity. So, these rules are valid for aggregate roots too unless aggregate root rules override them.
- **Do** define entities in the **domain layer**.
#### Primary Constructor
### Primary Constructor
* **Do** define a **primary constructor** that ensures the validity of the entity on creation. Primary constructors are used to create a new instance of the entity by the application code.
@ -14,15 +18,15 @@ Every aggregate root is also an entity. So, these rules are valid for aggregate
- **Do** always initialize sub collections in the primary constructor.
- **Do not** generate `Guid` keys inside the constructor. Get it as a parameter, so the calling code will use `IGuidGenerator` to generate a new `Guid` value.
#### Parameterless Constructor
### Parameterless Constructor
- **Do** always define a `protected` parameterless constructor to be compatible with ORMs.
#### References
### References
- **Do** always **reference** to other aggregate roots **by Id**. Never add navigation properties to other aggregate roots.
#### Other Class Members
### Other Class Members
- **Do** always define properties and methods as `virtual` (except `private` methods, obviously). Because some ORMs and dynamic proxy tools require it.
- **Do** keep the entity as always **valid** and **consistent** within its own boundary.
@ -30,27 +34,27 @@ Every aggregate root is also an entity. So, these rules are valid for aggregate
- **Do** define `public `, `internal` or `protected internal` (virtual) **methods** to change the properties (with non-public setters) if necessary.
- **Do** return the entity object (`this`) from the setter methods.
### Aggregate Roots
## Aggregate Roots
#### Primary Keys
### Primary Keys
* **Do** always use a **Id** property for the aggregate root key.
* **Do not** use **composite keys** for aggregate roots.
* **Do** use **Guid** as the **primary key** of all aggregate roots.
#### Base Class
### Base Class
* **Do** inherit from the `AggregateRoot<TKey>` or one of the audited classes (`CreationAuditedAggregateRoot<TKey>`, `AuditedAggregateRoot<TKey>` or `FullAuditedAggregateRoot<TKey>`) based on requirements.
#### Aggregate Boundary
### Aggregate Boundary
* **Do** keep aggregates **as small as possible**. Most of the aggregates will only have primitive properties and will not have sub collections. Consider these as design decisions:
* **Performance** &**memory** cost of loading & saving aggregates (keep in mind that an aggregate is normally loaded & saved as a single unit). Larger aggregates will consume more CPU & memory.
* **Consistency** &**validity** boundary.
### Example
## Example
#### Aggregate Root
### Aggregate Root
````C#
public class Issue : FullAuditedAggregateRoot<Guid> //Using Guid as the key/identifier
@ -130,7 +134,7 @@ public class Issue : FullAuditedAggregateRoot<Guid> //Using Guid as the key/iden
}
````
#### The Entity
### Entity
````C#
public class IssueLabel : Entity
@ -151,11 +155,12 @@ public class IssueLabel : Entity
- **Do** always use a short `TablePrefix` value for a module to create **unique table names** in a shared database. `Abp` table prefix is reserved for ABP core modules.
- **Do** set `Schema` to `null` as default.
### Model Mapping
## Model Mapping
- **Do** explicitly **configure all entities** by overriding the `OnModelCreating` method of the `DbContext`. Example:
@ -100,7 +104,7 @@ public static class IdentityDbContextModelBuilderExtensions
* **Do** call `b.ConfigureByConvention();` for each entity mapping (as shown above).
### Repository Implementation
## Repository Implementation
- **Do****inherit** the repository from the `EfCoreRepository<TDbContext, TEntity, TKey>` class and implement the corresponding repository interface. Example:
@ -168,7 +172,7 @@ public override async Task<IQueryable<IdentityUser>> WithDetailsAsync()
}
````
### Module Class
## Module Class
- **Do** define a module class for the Entity Framework Core integration package.
- **Do** add `DbContext` to the `IServiceCollection` using the `AddAbpDbContext<TDbContext>` method.
> This document offers best practices for implementing MongoDB integration in your modules and applications.
>
> **Ensure you've read the [*MongoDB Integration*](../../data/entity-framework-core/index.md) document first.**
## General
* Do define a separated `MongoDbContext` interface and class for each module.
### MongoDbContext Interface
## MongoDbContext Interface
- **Do** define an **interface** for the `MongoDbContext` that inherits from `IAbpMongoDbContext`.
- **Do** add a `ConnectionStringName`**attribute** to the `MongoDbContext` interface.
@ -17,7 +23,7 @@ public interface IAbpIdentityMongoDbContext : IAbpMongoDbContext
}
````
### MongoDbContext class
## MongoDbContext class
- **Do** inherit the `MongoDbContext` from the `AbpMongoDbContext` class.
- **Do** add a `ConnectionStringName` attribute to the `MongoDbContext` class.
@ -34,7 +40,7 @@ public class AbpIdentityMongoDbContext : AbpMongoDbContext, IAbpIdentityMongoDbC
}
```
### Collection Prefix
## Collection Prefix
- **Do** add static `CollectionPrefix`**property** to the `DbContext` class. Set default value from a constant. Example:
@ -46,7 +52,7 @@ Used the same constant defined for the EF Core integration table prefix in this
- **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.
### Collection Mapping
## Collection Mapping
- **Do** explicitly **configure all aggregate roots** by overriding the `CreateModel` method of the `MongoDbContext`. Example:
@ -83,7 +89,7 @@ public static class AbpIdentityMongoDbContextExtensions
}
```
### Repository Implementation
## Repository Implementation
- **Do****inherit** the repository from the `MongoDbRepository<TMongoDbContext, TEntity, TKey>` class and implement the corresponding repository interface. Example:
@ -124,7 +130,7 @@ public async Task<IdentityUser> FindByNormalizedUserNameAsync(
* Using `IQueryable<TEntity>` 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.
### Module Class
## Module Class
- **Do** define a module class for the MongoDB integration package.
- **Do** add `MongoDbContext` to the `IServiceCollection` using the `AddMongoDbContext<TMongoDbContext>` method.
> This document offers best practices for implementing Repository classes in your modules and applications based on Domain-Driven-Design principles.
>
> **Ensure you've read the [*Repositories*](../domain-driven-design/repositories.md) document first.**
## 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**.
@ -30,7 +34,7 @@ public interface IIdentityUserRepository : IBasicRepository<IdentityUser, Guid>
* **Do** inherit the repository interface from `IBasicRepository<TEntity, TKey>` (as normally) or a lower-featured interface, like `IReadOnlyRepository<TEntity, TKey>` (if it's needed).
* **Do not** define repositories for entities those are **not aggregate roots**.
### Repository Methods
## Repository Methods
* **Do** define all repository methods as **asynchronous**.
* **Do** add an **optional**`cancellationToken` parameter to every method of the repository. Example:
* **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.
**Data Transfer Objects** (DTO) are used to transfer data between the **Application Layer** and the **Presentation Layer** or other type of clients.
Typically, an [application service](./application-services.md) is called from the presentation layer (optionally) with a **DTO** as the parameter. It uses domain objects to **perform some specific business logic** and (optionally) returns a DTO back to the presentation layer. Thus, the presentation layer is completely **isolated** from domain layer.
In a [Domain Driven Design](../domain-driven-design) (DDD) solution, the core business logic is generally implemented in aggregates ([entities](./entities.md)) and the Domain Services. Creating a Domain Service is especially needed when;
* You implement a core domain logic that depends on some services (like repositories or other external services).