DKNet.EfCore.DtoGenerator 10.0.35

dotnet add package DKNet.EfCore.DtoGenerator --version 10.0.35
                    
NuGet\Install-Package DKNet.EfCore.DtoGenerator -Version 10.0.35
                    
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="DKNet.EfCore.DtoGenerator" Version="10.0.35">
  <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="DKNet.EfCore.DtoGenerator" Version="10.0.35" />
                    
Directory.Packages.props
<PackageReference Include="DKNet.EfCore.DtoGenerator">
  <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 DKNet.EfCore.DtoGenerator --version 10.0.35
                    
#r "nuget: DKNet.EfCore.DtoGenerator, 10.0.35"
                    
#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 DKNet.EfCore.DtoGenerator@10.0.35
                    
#: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=DKNet.EfCore.DtoGenerator&version=10.0.35
                    
Install as a Cake Addin
#tool nuget:?package=DKNet.EfCore.DtoGenerator&version=10.0.35
                    
Install as a Cake Tool

DKNet.EfCore.DtoGenerator

What is DtoGenerator

DKNet.EfCore.DtoGenerator is a lightweight Roslyn Incremental Source Generator that automatically creates immutable DTO (Data Transfer Object) types from your EF Core entities or any POCO classes at compile time. It eliminates the need to manually write repetitive DTO classes while maintaining type safety and reducing boilerplate code.

The generator synthesizes matching public init properties for every public instance readable property on the entity ( excluding indexers & statics). It also automatically copies validation attributes from entity properties to DTO properties, ensuring that validation rules are consistently applied across your application layers.

When Mapster is available, it uses TypeAdapter.Adapt for efficient mapping; otherwise, it falls back to property-by-property initialization.

NuGet Package

Add the NuGet package to your project:

<ItemGroup>
  <PackageReference Include="DKNet.EfCore.DtoGenerator" Version="1.0.0" PrivateAssets="all" OutputItemType="Analyzer" />
</ItemGroup>

Optional but recommended: Add Mapster for rich mapping capabilities and configuration:

<ItemGroup>
  <PackageReference Include="Mapster" Version="7.4.0" />
</ItemGroup>

Project Configuration

To enable and configure the source generator, add the following properties to your project file (.csproj):

<PropertyGroup>
  <EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
  <CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)Generated</CompilerGeneratedFilesOutputPath>
  
  <EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>
</PropertyGroup>

These settings enable the generator to emit generated files in the obj/Generated directory and ensure the analyzer runs correctly on every build.

DTO Declaration

To generate a DTO from an entity, create an empty partial record (recommended) or class/struct and apply the [GenerateDto] attribute:

Example Entity:

public class MerchantBalance
{
    public Guid Id { get; set; }
    public string MerchantId { get; set; } = string.Empty;
    public decimal Balance { get; set; }
    public DateTime LastUpdated { get; set; }
}

DTO Declaration:

using DKNet.EfCore.DtoGenerator;

[GenerateDto(typeof(MerchantBalance))]
public partial record BalanceDto;

The generator will automatically create a BalanceDto.g.cs file with all properties from MerchantBalance and mapping helper methods.

Validation Attributes

NEW: The generator automatically copies all validation attributes from entity properties to DTO properties. This ensures consistent validation rules across your application layers without manual duplication.

Supported Validation Attributes:

  • [MaxLength]
  • [StringLength] (including MinimumLength parameter)
  • [Required]
  • [Range]
  • [EmailAddress]
  • [Url]
  • [Phone]
  • All other System.ComponentModel.DataAnnotations attributes

Example Entity with Validation:

public class Product
{
    public Guid Id { get; set; }
    
    [Required]
    [StringLength(100, MinimumLength = 3)]
    public string Name { get; set; } = string.Empty;
    
    [MaxLength(50)]
    public string Sku { get; set; } = string.Empty;
    
    [Range(0.01, 999999.99)]
    public decimal Price { get; set; }
    
    [EmailAddress]
    public string Email { get; set; } = string.Empty;
}

Generated DTO with Copied Attributes:

public partial record ProductDto
{
    public Guid Id { get; init; }
    
    [Required]
    [StringLength(100, MinimumLength = 3)]
    public required string Name { get; init; }
    
    [MaxLength(50)]
    public required string Sku { get; init; }
    
    [Range(0.01, 999999.99)]
    public decimal Price { get; init; }
    
    [EmailAddress]
    public required string Email { get; init; }
}

The copied validation attributes work seamlessly with ASP.NET Core model validation, allowing you to validate DTOs using ModelState.IsValid or Validator.TryValidateObject().

Excluding Properties

You can exclude specific properties from the generated DTO using the Exclude parameter:

[GenerateDto(typeof(MerchantBalance), Exclude = new[] { "LastUpdated", "Id" })]
public partial record BalanceSummaryDto;

Including Only Specific Properties

Alternatively, you can specify only the properties you want to include using the Include parameter. When Include is provided, only those properties will be generated:

[GenerateDto(typeof(MerchantBalance), Include = new[] { "MerchantId", "Balance" })]
public partial record BalanceOnlyDto;

Note: Include and Exclude are mutually exclusive. If you specify Include, the Exclude parameter will be ignored, and a warning will be generated if both are provided.

Ignoring Complex Types (Entity Navigation Properties)

Use the IgnoreComplexType parameter to automatically exclude navigation properties that link to other entities. This is useful for creating simple DTOs that only contain primitive and value type properties:

// Assuming Customer has Orders (List<Order>) and PrimaryAddress (Address) navigation properties
[GenerateDto(typeof(Customer), IgnoreComplexType = true)]
public partial record CustomerSimpleDto;

When IgnoreComplexType is set to true, the generator automatically excludes:

  • Single entity properties (e.g., public Address? PrimaryAddress { get; set; })
  • Collection properties of entities (e.g., public List<Order> Orders { get; set; })

Note: Properties marked with the [Owned] attribute (EF Core owned types) are NOT excluded since they're considered part of the entity, not navigation properties.

You can combine IgnoreComplexType with Exclude to exclude additional properties:

[GenerateDto(typeof(Customer), IgnoreComplexType = true, Exclude = new[] { "Email" })]
public partial record CustomerBasicDto;
// Generated DTO will exclude Orders, PrimaryAddress (complex types) AND Email

However, when you use Include, it overrides IgnoreComplexType, allowing you to explicitly include navigation properties if needed:

// Orders navigation property will be included even though IgnoreComplexType = true
// because Include parameter takes precedence
[GenerateDto(typeof(Customer), IgnoreComplexType = true, Include = new[] { "CustomerId", "Name", "Orders" })]
public partial record CustomerWithOrdersDto;

Customizing DTOs

You can add custom properties or override generated ones by declaring them in your partial DTO:

[GenerateDto(typeof(MerchantBalance))]
public partial record BalanceDto
{
    // Add custom computed property
    public string DisplayBalance => $"${Balance:N2}";
    
    // Override generated property with custom logic
    public new string MerchantId { get; init; } = string.Empty;
}

Copy Generated DTOs to Project Folder

For verification and debugging purposes, you can copy generated DTOs to your project folder using a custom MSBuild target. Add the following to your project file (.csproj):


<Target Name="CopyGeneratedDtosToOutputFolder" AfterTargets="CoreCompile" Condition="Exists('$(CompilerGeneratedFilesOutputPath)')">
    <ItemGroup>
        <GeneratedDtoFiles Include="$(CompilerGeneratedFilesOutputPath)\**\*Dto.g.cs"/>
    </ItemGroup>
    <MakeDir Directories="$(ProjectDir)GeneratedDtos" Condition="'@(GeneratedDtoFiles)' != ''"/>
    <Copy SourceFiles="@(GeneratedDtoFiles)"
          DestinationFiles="$(ProjectDir)GeneratedDtos\%(Filename)%(Extension)"
          SkipUnchangedFiles="false"
          OverwriteReadOnlyFiles="true"
          Condition="'@(GeneratedDtoFiles)' != ''"/>
    <Message Text="Copied %(Filename)%(Extension) to $(ProjectDir)GeneratedDtos" Importance="high" Condition="'@(GeneratedDtoFiles)' != ''"/>
</Target>


<ItemGroup>
    <Compile Remove="GeneratedDtos\**\*.cs"/>
    <None Include="GeneratedDtos\**\*.cs"/>
</ItemGroup>

This MSBuild target will:

  • Copy all generated *Dto.g.cs files to a GeneratedDtos folder in your project
  • Exclude these files from compilation to avoid duplicates
  • Keep them visible in Solution Explorer for inspection
  • Show a message during build indicating which files were copied

Generated Code Examples

With Mapster Present

public partial record BalanceDto
{
    public System.Guid Id { get; init; }
    
    [MaxLength(100)]
    public string MerchantId { get; init; } = default!;
    
    public decimal Balance { get; init; }
    public System.DateTime LastUpdated { get; init; }

    public static BalanceDto FromEntity(MerchantBalance entity) 
        => Mapster.TypeAdapter.Adapt<BalanceDto>(entity);
    
    public MerchantBalance ToEntity() 
        => Mapster.TypeAdapter.Adapt<MerchantBalance>(this);
    
    public static IEnumerable<BalanceDto> FromEntities(IEnumerable<MerchantBalance> entities) 
        => Mapster.TypeAdapter.Adapt<IEnumerable<BalanceDto>>(entities);
}

Without Mapster (Fallback)

public partial record BalanceDto
{
    public System.Guid Id { get; init; }
    
    [MaxLength(100)]
    public string MerchantId { get; init; } = default!;
    
    public decimal Balance { get; init; }
    public System.DateTime LastUpdated { get; init; }

    public static BalanceDto FromEntity(MerchantBalance entity) => new BalanceDto
    {
        Id = entity.Id,
        MerchantId = entity.MerchantId,
        Balance = entity.Balance,
        LastUpdated = entity.LastUpdated
    };

    public MerchantBalance ToEntity() => new MerchantBalance
    {
        Id = this.Id,
        MerchantId = this.MerchantId,
        Balance = this.Balance,
        LastUpdated = this.LastUpdated
    };

    public static IEnumerable<BalanceDto> FromEntities(IEnumerable<MerchantBalance> entities)
    {
        foreach (var e in entities) yield return FromEntity(e);
    }
}

Note: All validation attributes from entity properties are automatically copied to DTO properties in the generated code.

Mapster Configuration

When using Mapster, you can customize mapping behavior with global or type-specific configurations:

TypeAdapterConfig<MerchantBalance, BalanceDto>
    .NewConfig()
    .Map(dest => dest.DisplayBalance, src => $"${src.Balance:N2}")
    .Ignore(dest => dest.Id);

For EF Core query projections, use Mapster's .ProjectToType<T>() extension instead of FromEntity to enable database-side translation:

var balances = await dbContext.MerchantBalances
    .ProjectToType<BalanceDto>()
    .ToListAsync();

Additional Notes

  • Navigation Properties:
    • By default, navigation and collection properties are included as shallow copies in DTOs.
    • Use IgnoreComplexType = true to automatically exclude all entity navigation properties (both single and collection).
    • Properties marked with [Owned] attribute are NOT excluded by IgnoreComplexType as they're considered owned types, not navigations.
    • Customize via Mapster configuration or override in partial DTO for more control.
  • Nullable Reference Types: Non-nullable reference type properties receive a = default!; initializer to satisfy compiler null-state analysis.
  • Generic Entities: Limited support for generic entities (non-generic DTO shells only).
  • Diagnostics: DKDTOGEN001 warning is reported if generation fails for a target type; build continues.
  • Validation Attributes: All System.ComponentModel.DataAnnotations attributes are automatically copied from entity properties to DTO properties, ensuring consistent validation across layers.

Local Development

Build and pack the source generator:

# Build
dotnet build -c Release

# Pack
dotnet pack -c Release

For local consumption in another project:

<ItemGroup>
  <ProjectReference Include="..\EfCore\DKNet.EfCore.DtoGenerator\DKNet.EfCore.DtoGenerator.csproj"
                    OutputItemType="Analyzer" />
</ItemGroup>

Cross-Compiler Compatibility (CS9057)

This is a dev-only netstandard2.0 source generator, so its .csproj disables the SDK code-style / NetAnalyzers from running on the generator's own build:

<PropertyGroup>
  <RunAnalyzers>false</RunAnalyzers>
  <EnforceCodeStyleInBuild>false</EnforceCodeStyleInBuild>
</PropertyGroup>

Without these, the project fails to build under a csc older than the SDK's analyzers, e.g.:

CSC : error CS9057: Analyzer assembly '.../codestyle/cs/Microsoft.CodeAnalysis.CodeStyle.dll'
cannot be used because it references version '5.6.0.0' of the compiler, which is newer than
the currently running version '5.3.0.0'.

CS9057 means an analyzer was built against a newer Roslyn than the compiler running the build (a mixed-SDK environment: e.g. MSBuild from the 10.0.3xx band feeding 5.6 analyzers into a 5.3 csc). These analyzers add no value to a generator project, so turning them off here decouples the build from any specific SDK band. Pin the SDK in global.json if you want the band itself to be deterministic.

Planned Enhancements

  • [DtoIgnore] attribute to skip specific entity properties
  • [DtoName("...")] attribute for renaming properties
  • Partial method hooks for custom mapping logic
  • Optional deep copy of collections and navigation properties
  • Multi-targeting for broader analyzer compatibility

Happy generating! For more information and complete documentation, visit the DKNet Framework Documentation.

There are no supported framework assets in this package.

Learn more about Target Frameworks and .NET Standard.

  • .NETStandard 2.0

    • 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
10.0.35 81 8/5/2026
10.0.34 78 8/5/2026
10.0.33 81 8/4/2026
10.0.32 126 8/3/2026
10.0.31 103 7/21/2026
10.0.30 99 7/21/2026
10.0.29 393 6/22/2026
10.0.27 161 5/22/2026
10.0.26 116 5/19/2026
10.0.25 368 3/27/2026
10.0.24 126 3/27/2026
10.0.23 123 3/27/2026
10.0.22 264 3/26/2026
10.0.21 175 3/17/2026
10.0.20 151 2/2/2026
10.0.19 263 1/21/2026
10.0.18 126 1/21/2026
10.0.17 155 1/19/2026
10.0.16 129 1/18/2026
10.0.15 135 1/18/2026
Loading failed