Tooark.Dtos
4.7.0
See the version list below for details.
dotnet add package Tooark.Dtos --version 4.7.0
NuGet\Install-Package Tooark.Dtos -Version 4.7.0
<PackageReference Include="Tooark.Dtos" Version="4.7.0" />
<PackageVersion Include="Tooark.Dtos" Version="4.7.0" />
<PackageReference Include="Tooark.Dtos" />
paket add Tooark.Dtos --version 4.7.0
#r "nuget: Tooark.Dtos, 4.7.0"
#:package Tooark.Dtos@4.7.0
#addin nuget:?package=Tooark.Dtos&version=4.7.0
#tool nuget:?package=Tooark.Dtos&version=4.7.0
Tooark.Dtos
Library for managing and maintaining base DTOs in .NET projects.
π Languages: πΊπΈ English (this file) Β· π§π· PortuguΓͺs
π Contents
- Overview
- Installation
- Configuration
- Components
- Usage Examples
- Dependencies
- Contributing
- Help & Security
- Support
- License
π Overview
The Tooark.Dtos package provides:
- search and pagination DTOs for listing endpoints;
- a standard response with data, errors, pagination and metadata;
- automatic translation of the error keys produced by the Tooark validations;
- a page size limit, so that a request cannot ask for every record.
Runtime requirement:
SearchDto,PaginationDtoandResponseDtouse MVC,HttpandWebUtilitiestypes, so the package requires the ASP.NET Core runtime to be installed. That is expected for API DTOs.
π§ Installation
dotnet add package Tooark.Dtos
βοΈ Configuration
Message translation requires no configuration: ResponseDto resolves the language from the request's
execution flow and reads the translations from the files shipped with
Tooark.Extensions.
The registration below exists so the application can inject IStringLocalizer into its own types:
using Tooark.Dtos.Injections;
builder.Services.AddTooarkDtos();
To add or override translations, place a Resources/{language}.json in the application output.
π¦ Components
Dto
Base class of the DTOs that produce translated messages. It has no public members: it exists so that
ResponseDto and SearchDto share the localizer.
SearchDto
Search parameters with pagination.
| Member | Type | Description |
|---|---|---|
Search |
string? |
Information to look for. Default: null |
SearchNormalized |
string? |
Normalized Search, computed once per value. Neither bound nor serialized |
PageIndex |
long |
Page index, starting at 1. A smaller value assumes 1. Default: 1 |
PageIndexLogical |
long |
PageIndex minus one, for direct use in Skip. Neither bound nor serialized |
PageSize |
long |
Page size. Negative assumes 0, which means ignoring the size. Default: 10 |
PageSizeMax |
long |
protected virtual. Ceiling of PageSize. Default: DefaultPageSizeMax |
DefaultPageSizeMax |
const long |
Default ceiling: 100 |
SearchOrderDto
Inherits from SearchDto and adds ordering.
| Member | Type | Description |
|---|---|---|
OrderBy |
string? |
Name of the column to order by |
OrderAsc |
bool |
Ascending when true. Default: true |
PaginationDto
Record total and navigation between pages. Every property is read-only.
| Member | Type | Description |
|---|---|---|
Total |
long |
Total records |
PageSize / PageIndex |
long |
Page size and index |
Previous / Next |
long? |
Indexes of the neighboring pages, null when absent |
CurrentLink / PreviousLink / NextLink |
string? |
Corresponding URLs |
ResponseDto<T>
Standard API response.
| Member | Type | Description |
|---|---|---|
Data |
T? |
Response data |
Errors |
IReadOnlyList<string> |
Error messages, already translated |
Pagination |
PaginationDto? |
Pagination data |
Metadata |
IReadOnlyList<MetadataDto> |
Metadata |
SetPagination / SetMetadata / AddMetadata |
Set pagination and metadata after construction |
Errors and Metadata are read-only collections: casting them to IList compiles, but changing them throws
NotSupportedException. Use SetMetadata or AddMetadata.
MetadataDto
Key/value pair. Key and value are independent β passing one as null results in an empty string, without discarding the other.
Page size limit
Without a ceiling, a single request could ask for every record. PageSize is limited to
DefaultPageSizeMax, which is 100. An endpoint that needs larger pages overrides the limit in its own DTO:
public sealed class ReportSearchDto : SearchDto
{
protected override long PageSizeMax => 5000;
}
Use the expression-bodied form. An auto-property with an initializer does not work: the limit is read by the base class constructor, which runs before the derived class initializers.
Pagination links
The links reuse the request's query string, replacing only PageIndex, so that the endpoint's filters keep
applying while navigating.
Two consequences worth knowing:
- Every request parameter shows up in the response body. Do not send credentials in the query string β they would come back in the links and from there into logs, caches and browser history.
- The links are not an access control. Whoever can call one page can call the others by editing the URL,
and
Totalalready says how many exist. Against mass harvesting, what counts is thePageSizeceiling, rate limiting and authorization β not hiding the links.
π Usage Examples
Search with pagination
using Microsoft.AspNetCore.Mvc;
using Tooark.Dtos;
[HttpGet]
public async Task<IActionResult> List([FromQuery] SearchDto filter)
{
var query = _context.People.AsQueryable();
if (!string.IsNullOrEmpty(filter.SearchNormalized))
{
query = query.Where(p => p.NormalizedName.Contains(filter.SearchNormalized));
}
var total = await query.LongCountAsync();
var people = await query
.Skip((int)(filter.PageIndexLogical * filter.PageSize))
.Take((int)filter.PageSize)
.ToListAsync();
var response = new ResponseDto<List<Person>>(people);
response.SetPagination(new PaginationDto(total, filter, Request));
return Ok(response);
}
The response:
{
"data": [ ... ],
"errors": [],
"pagination": {
"total": 95,
"pageSize": 10,
"pageIndex": 9,
"previous": 8,
"next": 10,
"currentLink": "https://api.example.com/people?PageIndex=9&PageSize=10",
"previousLink": "https://api.example.com/people?PageIndex=8&PageSize=10",
"nextLink": "https://api.example.com/people?PageIndex=10&PageSize=10"
},
"metadata": []
}
Do not name the parameter
search.SearchDtohas aSearchproperty, and ASP.NET Core emits theMVC1004warning when the parameter name matches a property of the bound type, because prefix resolution becomes ambiguous. Any other name works.
Search with ordering
using Tooark.Dtos;
[HttpGet]
public IActionResult List([FromQuery] SearchOrderDto filter)
{
var query = _context.People.OrderByProperty(filter.OrderBy ?? nameof(Person.Name));
// ...
}
Response with validation errors
using Tooark.Dtos;
var person = new Person(name, email);
// The invalid notification becomes the error list, already translated
if (!person.IsValid)
{
// ["The Name field is required"]
return BadRequest(new ResponseDto<Person>(person));
}
With the error code in front of the message:
// ["T.VLD.STR5: The Name field is required"]
return BadRequest(new ResponseDto<Person>(person.Notification, withCode: true));
The ModelState failures of [ApiController] controllers can answer with this same body: that is what
AddTooarkModelStateEnvelope does, in
Tooark.AspNetCore.
Endpoint with a larger page
using Tooark.Dtos;
public sealed class ExportSearchDto : SearchDto
{
protected override long PageSizeMax => 5000;
}
[HttpGet("export")]
public IActionResult Export([FromQuery] ExportSearchDto filter)
{
// filter.PageSize accepts up to 5000 in this endpoint
}
Metadata
using Tooark.Dtos;
var response = new ResponseDto<List<Person>>(people);
response.AddMetadata(new MetadataDto("version", "2024-01"));
response.SetMetadata([new MetadataDto("source", "cache")]);
π Dependencies
| Package | Version | Description |
|---|---|---|
Tooark.Extensions |
4.x | Message localization and search normalization |
Tooark.Notifications |
4.x | Notifications that become the response errors |
Microsoft.AspNetCore.App (shared framework) |
8.x/10.x | HttpRequest, QueryHelpers and BindNever |
π€ Contributing
Contributions are welcome! Start with CONTRIBUTING.md β it covers the development workflow, the coding and commit conventions and the pull request checklist. Bugs and feature requests go through the issue templates of the Tooark repository.
By participating you agree to the Code of Conduct.
π Help & Security
- β Questions, bugs, feature ideas β see SUPPORT.md for the right channel
- π Security vulnerabilities β do not open a public issue; follow SECURITY.md
π Support
If Tooark helps your projects, consider supporting its development:
- π GitHub Sponsors
- β Ko-fi
Every contribution helps keep the project maintained and improving. Thank you! π
π License
This project is licensed under the BSD 3-Clause License.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Tooark.Extensions (>= 4.7.0)
- Tooark.Notifications (>= 4.7.0)
-
net8.0
- Tooark.Extensions (>= 4.7.0)
- Tooark.Notifications (>= 4.7.0)
NuGet packages (2)
Showing the top 2 NuGet packages that depend on Tooark.Dtos:
| Package | Downloads |
|---|---|
|
Tooark
Package with all Tooark resources for .NET applications. |
|
|
Tooark.AspNetCore
Package with the ASP.NET Core specific pieces of Tooark for .NET applications. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 4.7.1 | 0 | 10/17/2026 |
| 4.7.0 | 139 | 9/30/2026 |
| 4.6.0 | 156 | 9/29/2026 |
| 4.5.0 | 110 | 9/29/2026 |
| 4.4.0 | 104 | 9/28/2026 |
| 4.3.0 | 115 | 9/26/2026 |
| 4.2.1 | 112 | 9/25/2026 |
| 4.2.0 | 126 | 9/20/2026 |
| 4.1.0 | 116 | 9/18/2026 |
| 4.0.1 | 203 | 8/25/2026 |
| 4.0.0 | 128 | 8/25/2026 |
| 3.3.6 | 106 | 9/18/2026 |
| 3.3.5 | 119 | 8/25/2026 |
| 3.3.4 | 138 | 8/12/2026 |
| 3.3.3 | 138 | 7/27/2026 |
| 3.3.2 | 291 | 6/11/2026 |
| 3.3.1 | 155 | 6/6/2026 |
| 2.3.5 | 99 | 9/18/2026 |
| 2.3.4 | 117 | 8/25/2026 |
| 2.3.3 | 129 | 7/27/2026 |