SmartDto.NET 1.0.0

There is a newer version of this package available.
See the version list below for details.
dotnet add package SmartDto.NET --version 1.0.0
                    
NuGet\Install-Package SmartDto.NET -Version 1.0.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="SmartDto.NET" Version="1.0.0">
  <PrivateAssets>all</PrivateAssets>
  <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="SmartDto.NET" Version="1.0.0" />
                    
Directory.Packages.props
<PackageReference Include="SmartDto.NET">
  <PrivateAssets>all</PrivateAssets>
  <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add SmartDto.NET --version 1.0.0
                    
#r "nuget: SmartDto.NET, 1.0.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package SmartDto.NET@1.0.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=SmartDto.NET&version=1.0.0
                    
Install as a Cake Addin
#tool nuget:?package=SmartDto.NET&version=1.0.0
                    
Install as a Cake Tool

SmartDto.NET

A C# source generator that produces strongly-typed Create and Update request DTOs from your domain models. No reflection, no runtime overhead.

Install

dotnet add package SmartDto.NET

Quick start

Mark your model with [Dto]:

using SmartDto.NET;

[Dto]
public class Player
{
    [DtoIgnore]
    public int Id { get; set; }

    public required string Name { get; set; }
    public int Level { get; set; }
    public string? Email { get; set; }
}

Register the JSON converter:

builder.Services.AddControllers()
    .AddJsonOptions(o => o.JsonSerializerOptions.Converters.Add(
        new PatchFieldJsonConverterFactory()));

Use the generated records in your controller:

[HttpPost]
public IActionResult Create([FromBody] CreatePlayerRequest request)
{
    var errors = request.Validate();
    if (errors.Count > 0)
        return BadRequest(new { errors });

    Player player = request.ToEntity();
    return Ok(player);
}

[HttpPatch("{id}")]
public IActionResult Update(int id, [FromBody] UpdatePlayerRequest request)
{
    var errors = request.Validate();
    if (errors.Count > 0)
        return BadRequest(new { errors });

    request.ApplyTo(existingPlayer);
    return Ok(existingPlayer);
}

What gets generated

For each [Dto] class the generator produces two immutable records:

public record CreatePlayerRequest
{
    public PatchField<string> Name { get; init; }   // required in Validate()
    public PatchField<int> Level { get; init; }      // optional
    public PatchField<string?> Email { get; init; }  // optional, nullable

    public List<string> Validate() { ... }
    public Player ToEntity() { ... }
}

public record UpdatePlayerRequest
{
    public PatchField<string> Name { get; init; }    // optional, but non-null if sent
    public PatchField<int> Level { get; init; }
    public PatchField<string?> Email { get; init; }

    public List<string> Validate() { ... }
    public void ApplyTo(Player target) { ... }
}

PatchField<T> distinguishes three states: not sent (HasValue = false), sent with value, and sent as null.

Attributes

Attribute Target Description
[Dto] Class Enables generation for this model
[DtoIgnore] Property Excludes from generated DTOs
[DtoName("json_name")] Property Overrides the JSON property name
[CreateOnly] Property Only appears in the Create request
[UpdateOnly] Property Only appears in the Update request

required keyword

Properties marked required are validated as mandatory in CreateRequest.Validate(). In UpdateRequest, all properties are optional.

Custom names

[Dto(CreateName = "NewPlayerDto", UpdateName = "EditPlayerDto")]
public class Player { ... }

Create/Update-only properties

[Dto]
public class Player
{
    public required string Name { get; set; }

    [CreateOnly]
    public required string Password { get; set; }    // only in CreatePlayerRequest

    [UpdateOnly]
    public string? DeactivationReason { get; set; }  // only in UpdatePlayerRequest
}

JSON serializer support

The generator detects which serializers are available and produces the corresponding converters:

Serializer Generated converter Registration
System.Text.Json PatchFieldJsonConverterFactory options.Converters.Add(new PatchFieldJsonConverterFactory())
Newtonsoft.Json PatchFieldNewtonsoftConverter settings.Converters.Add(new PatchFieldNewtonsoftConverter())

Both are generated if both packages are referenced. No converter is auto-registered -- you choose which one to use.

Custom validation

Simple validator

Implement IDtoValidator<T> and point to it from the attribute:

public class MyCreateValidator : IDtoValidator<CreatePlayerRequest>
{
    public List<string> Validate(CreatePlayerRequest instance)
    {
        var errors = new List<string>();
        if (instance.Name.HasValue && instance.Name.Value.Length < 3)
            errors.Add("Name must be at least 3 characters.");
        return errors;
    }
}

[Dto(CreateValidator = typeof(MyCreateValidator))]
public class Player { ... }

When a validator is set, Validate() delegates entirely to it -- the default generated rules are replaced.

FluentValidation

When FluentValidation is installed, the generator produces:

  • FluentDtoValidator<T> -- base class bridging FluentValidation with IDtoValidator<T>
  • CreatePlayerRequestBaseValidator -- contains the generated required/null rules
  • UpdatePlayerRequestBaseValidator -- contains the generated null rules

Inherit to extend:

public class MyCreateValidator : CreatePlayerRequestBaseValidator
{
    public MyCreateValidator()
    {
        RuleFor(x => x.Name)
            .Must(f => !f.HasValue || f.Value.Length >= 3)
            .WithMessage("Name must be at least 3 characters.");
    }
}

[Dto(CreateValidator = typeof(MyCreateValidator))]
public class Player { ... }

Or start from scratch:

public class MyCreateValidator : FluentDtoValidator<CreatePlayerRequest>
{
    public MyCreateValidator()
    {
        // your rules only
    }
}

Requirements

  • .NET 6+ (or .NET Framework with SDK-style projects and System.Text.Json NuGet)
  • required keyword needs C# 11 / .NET 7+ (optional -- without it all properties are optional in Create)

License

MIT

There are no supported framework assets in this package.

Learn more about Target Frameworks and .NET Standard.

This package has no dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.2.7 124 4/4/2026 1.2.7 is deprecated because it is no longer maintained.
1.2.6 95 4/4/2026
1.2.5 112 4/3/2026
1.2.1 103 4/3/2026
1.2.0 107 4/3/2026
1.1.2 105 4/3/2026
1.1.1 112 4/2/2026
1.1.0 100 4/2/2026
1.0.4 99 4/2/2026
1.0.3 102 4/2/2026
1.0.2 102 4/2/2026
1.0.1 97 4/2/2026
1.0.0 99 4/1/2026