Data Transfer Objects¶
- 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.
- Do inherit from the extensible DTO classes for the aggregate roots (like
- Do define DTO members with public getter and setter.
- Do use data annotations for validation on the properties of DTOs those are inputs of the service.
- Do not add any logic into DTOs except implementing
IValidatableObject
when necessary. - Do mark all DTOs as [Serializable] since they are already serializable and developers may want to binary serialize them.
List Results¶
- Do use the
Input
postfix for the request DTO class name (ex:GetUsersInput
). - Do use ListResultDto
as response DTO which makes your List<...Dto>(ex: ListResultDto<UserDto>
) wrapped into another object as anItems
property.- Do map entities to DTOs with help of automapper
Request example;
[Serializable]
public class GetUsersInput : PagedAndSortedResultRequestDto
{
public string FilterText { get; set; }
public string Name { get; set; }
}
Response example;
We don't need to define a new class in the application contracts layer. We can use it directly in applications services.
UserRepository
service must implement your repository interface which includes GetListAsync
. If the best practices efcore integration in the document are followed, these methods should already be in place.
public virtual async Task<ListResultDto<OdmsUserDto>> GetUserLookupAsync()
{
# Get entities from the repository
var users = await UserRepository.GetListAsync();
return new ListResultDto<OdmsUserDto>(
ObjectMapper.Map<List<OdmsUser>, List<OdmsUserDto>>(users)
);
}
Paged & Sorted List Results¶
- Do use the
Input
postfix for the request DTO class name (ex:GetUsersInput
). - Do inherit from
PagedAndSortedResultRequestDto
base DTO class for your request DTO class. - Do use PagedResultDto
as response DTO which makes your PagedResultDto<...Dto>(ex: PagedResultDto<UserDto>
) wrapped into another object as anItems
and adds anotherTotal count
property.- Do map entities to DTOs with help of automapper
Request example;
[Serializable]
public class GetUsersInput : PagedAndSortedResultRequestDto
{
public string FilterText { get; set; }
public string Name { get; set; }
}
Response example;
We don't need to define a new class in the application contracts layer. We can use it directly in applications services
UserRepository
service must implement your repository interface which includes GetCountAsynce
and GetListAsync
. If the best practices efcore integration in the document are followed, these methods should already be in place.
public virtual async Task<PagedResultDto<OdmsUserDto>> GetListAsync(GetUsersInput input)
{
var totalCount = await UserRepository.GetCountAsync(
filterText: input.FilterText,
name: input.Name,
);
var users = await UserRepository.GetListAsync(
filterText: input.FilterText,
name: input.Name,
sorting: input.Sorting,
maxResultCount: input.MaxResultCount,
skipCount: input.SkipCount
);
List<OdmsUserDto> userDtos =
ObjectMapper.Map<List<OdmsUser>, List<OdmsUserDto>>(users);
return new PagedResultDto<OdmsUserDto>
{
TotalCount = totalCount,
Items = userDtos
};
}