Jinget.SourceGenerator 8.0.50

Prefix Reserved
dotnet add package Jinget.SourceGenerator --version 8.0.50
                    
NuGet\Install-Package Jinget.SourceGenerator -Version 8.0.50
                    
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="Jinget.SourceGenerator" Version="8.0.50" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Jinget.SourceGenerator" Version="8.0.50" />
                    
Directory.Packages.props
<PackageReference Include="Jinget.SourceGenerator" />
                    
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 Jinget.SourceGenerator --version 8.0.50
                    
#r "nuget: Jinget.SourceGenerator, 8.0.50"
                    
#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 Jinget.SourceGenerator@8.0.50
                    
#: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=Jinget.SourceGenerator&version=8.0.50
                    
Install as a Cake Addin
#tool nuget:?package=Jinget.SourceGenerator&version=8.0.50
                    
Install as a Cake Tool

Jinget

We are currently in the way to make Jinget an open source project, during this journey we will publish different parts of Jinget

Jinget.SourceGenerator

The purpose of this package is to facilitate communication and use of various types of web services and Web APIs including Rest APIs and SOAP web services.

How to Use:

  1. Download the package from NuGet using Package Manager: Install-Package Jinget.SourceGenerator You can also use other methods supported by NuGet. Check Here for more information.
ReadOnly model generation:

While working with CQRS you might need to sperate the Models and ReadOnly Models, where Models are needed for command operations and ReadOnly Models are needed for query operations. Consider we have Model as below:

public class StudentModel : BaseEntity<int>, IAggregateRoot
{
    public string Name { get; private set; }
    public DateTime EnrollDate { get; set; }
    public Address HomeAddress { get; set; }
    public ICollection<CourseModel> Courses { get; set; }
    public ICollection<StudentScoreModel> Scores { get; set; }
}

to generate ReadOnly Model we can add following attributes:

namespace Models;
[GenerateReadModel(PreserveBaseTypes = true)]
[AppendPropertyToReadModel("bool", "IsSuspended")]
public class StudentModel : BaseEntity<int>, IAggregateRoot
{
    [PreserveOriginalGetterSetter]
    public string Name { get; private set; }

    [IgnoreReadModelConversion]
    public DateTime EnrollDate { get; set; }

    [PreserveOriginalType]
    [IgnoreMapping]
    public Address HomeAddress { get; set; }

    [Count("CoursesCount")]
    public ICollection<CourseModel> Courses { get; set; }

    [Sum("SumOfScores")]
    [Average("AverageScores")]
    public ICollection<StudentScoreModel> Scores { get; set; }
}

GenerateReadModel: This is the main attribute should be added to model, which cause the readonly model generation. Important note here is that, models should have Model suffix. The PreserveBaseTypes argument states that if the base type should be ignored for transformation or not. The PreserveBaseInterface argument states that if the base interfaces should be ignored for transformation or not.

AppendPropertyToReadModel: This is an optional attribute which is used to add new custom property to readonly model. First argument is property type and second argument is it's name. For these aggregation attributes, there is an argument called ignoreMappping that has same effect as IgnoreMapping attribute. Default value for this argument is true.

PreserveOriginalGetterSetter: This is an optional attribute which is used to preserve property's getter/setter access modifier. Properties without this attribute will be transformed as public get/set properties.

IgnoreReadModelConversion: This is an optional attribute which is used to ignore a property from transformation.

PreserveOriginalType: This is an optional attribute which is used to preserve property's original type while transformation. By default all reference types are included in transformation.

IgnoreMapping: This is an optional attribute which is used to ignore a property in efcore mapping configuration.

Count: Just same as AppendPropertyToReadModel this attribute is used to add new custom property to readonly model. Other aggregation such as Sum, Average, Max and Min are also supported. For these aggregation attributes, there is an argument called ignoreMappping that has same effect as IgnoreMapping attribute. Default value for this argument is true.

Finally above mentioned code will produced the following readonly model:

namespace Models;

public class ReadOnlyStudentModel : BaseEntity<int>, Jinget.Core.Contracts.IAggregateRoot
{
    public string Name { get; private set; }
	public Address HomeAddress { get; set; }
	public ICollection<ReadOnlyCourseModel> Courses { get; set; }
    public int CoursesCount { get; set; }
	public ICollection<ReadOnlyStudentScoreModel> Scores { get; set; }
    public decimal SumOfScores { get; set; }
    public decimal AverageScores { get; set; }
    public bool IsSuspended { get; set; }
}
ReadOnly model mapping configuration generation(for EF Core):

When we have readonly model, we might need to separate their DbContexts too. For example we might need to map models to main DbContext and map readonly models to readonly DbContext. In order to generate the readonly mapping configuration, consider we have the following mapping configuration:

namespace MappingConfigurations;
[GenerateReadModelMappingConfiguration]
public class StudentMappingConfiguration : IEntityTypeConfiguration<StudentModel>
{
    public void Configure(EntityTypeBuilder<StudentModel> builder)
    {
        builder.ToTable("tblStudent", "demo");

        builder
            .HasMany(x => x.Scores)
            .WithOne(x => x.Student)
            .HasForeignKey(x => x.StudentId);

        //ReadModelMapping:IgnoreThisLine
        builder.Property(x => x.Name)
            .HasColumnType("nvarchar(50)")
            .IsRequired();

        builder
            .HasMany(x => x.Courses)
            .WithMany(x => x.Students)
            .UsingEntity("tblStudentCourses",
            l => l.HasOne(typeof(StudentModel)).WithMany().HasForeignKey("StudentId"),
            r => r.HasOne(typeof(CourseModel)).WithMany().HasForeignKey("CourseId"))
            .ToTable("tblStudentCourses", "demo");
    }
}

GenerateReadModelMappingConfiguration: This is the main attribute should be added to class, which cause the readonly model mapping configuration generation.

//ReadModelMapping:IgnoreThisLine: Any statement which has this comment above it, will be ignored in transformation.

Finally above mentioned code will produced the following readonly model mapping configuration:

using Jinget.Core.Contracts;
using Jinget.Core.Utilities.Expressions;
using Jinget.SourceGenerator.Common.Attributes;
using Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
namespace MappingConfigurations;
public class ReadOnlyStudentMappingConfiguration: IEntityTypeConfiguration<Models.ReadOnlyStudentModel>
{
    public override void Configure(EntityTypeBuilder<Models.ReadOnlyStudentModel> builder)
    {
        builder.ToTable("tblStudent", "demo");
        builder.HasMany(x => x.Scores).WithOne(x => x.Student).HasForeignKey(x => x.StudentId);
        builder.HasMany(x => x.Courses).WithMany(x => x.Students).UsingEntity("tblStudentCourses", l => l.HasOne(typeof(Models.ReadOnlyStudentModel)).WithMany().HasForeignKey("StudentId"), r => r.HasOne(typeof(Models.ReadOnlyCourseModel)).WithMany().HasForeignKey("CourseId")).ToTable("tblStudentCourses", "demo");
        builder.Ignore("IsSuspended");
        builder.Ignore("HomeAddress");
        builder.Ignore("CoursesCount");
        builder.Ignore("SumOfScores");
        builder.Ignore("AverageScores");
    }
}
Web API generator:

Using this capability you can generate common web apis based the given models and readonly models. web apis generated by this generator is highly coupled to CQRS concepts. In order to generate the web apis, consider we have the following mapping configuration:

[GenerateWebAPI]
[GenerateReadModel(PreserveBaseTypes = true)]
[AppendPropertyToReadModel("bool", "IsSuspended")]
public class StudentModel : BaseEntity<int>, IAggregateRoot
{
    [PreserveOriginalGetterSetter]
    public string Name { get; private set; }

    [IgnoreReadModelConversion]
    public DateTime EnrollDate { get; set; }

    [PreserveOriginalType]
    public Address HomeAddress { get; set; }

    [Count("CoursesCount")]
    public ICollection<CourseModel> Courses { get; set; }

    [Sum("SumOfScores")]
    [Average("AverageScores")]
    public ICollection<StudentScoreModel> Scores { get; set; }
}

GenerateWebAPI: This is the main attribute should be added to class, which cause the web apis generation. In the above sample we have also included the readonly model generation too. This attribute has different arguments such as:

HasClaim: Indicates that the web apis has authorization claim.

ClaimPrefix: The prefix to use for the claim.

ClaimTitle: Instead of setting claim dynamically, this value will be used. final result will be ClaimPrefix-ClaimTitle-create/modify etc.

ClaimType: The claim type to use. You can introduce your own claim attribute(which inherits from Authohrize attribute)

TenantAware: Indicates that the model should be tenant aware, so that all queries should have tenant filter.

CommandHandler: The command handler interface to use. if interface is generic then write it like this: InterfaceNameNumberOfGenericArguments. for example for ITest[T1,T2] write ITest2. Default value is IBaseCommandHandler`2

QueryHandler: The query handler interface to use. if interface is generic then write it like this: InterfaceNameNumberOfGenericArguments for example for ITest[T1,T2] write ITest2. Default value is IBaseReadOnlyQueryHandler`2.

TraceDataType: The type to use for the trace data. if interface is generic then write it like this: InterfaceNameNumberOfGenericArguments for example for MyTraceData[T1,T2] write MyTraceData2

UserContextType: The type to use for the user context. if interface is generic then write it like this: InterfaceNameNumberOfGenericArguments for example for MyTraceData[T1,T2] write MyTraceData2

Model: The type to use for the model. if not specified, then model will be constructed using model in handlers.

ReadOnlyModel: The type to use for the readonly model. if not specified, then readonly model will be constructed using model in handlers.

Finally above mentioned code will produced the following readonly model:

using Microsoft.AspNetCore.Routing;
using Mapster;
using System.Linq;
using System.Threading;
using Jinget.Core.Types;
using Jinget.Core.Utilities.Expressions;
namespace WebApis;

public static class StudentApiExtensions 
{
    public static RouteGroupBuilder MapStudentApis(this RouteGroupBuilder group)
    {
        group.MapPost("/",  async (Handlers.IBaseCommandHandler<Models.StudentModel, int> command, Models.ReadOnlyStudentModel vm, CancellationToken cancellationToken) 
            => await command.SaveAsync(vm.Adapt<Models.StudentModel>(), cancellationToken: cancellationToken));

        group.MapPut("/",  async (Handlers.IBaseCommandHandler<Models.StudentModel, int> command, Models.ReadOnlyStudentModel vm, CancellationToken cancellationToken) 
            => await command.SaveAsync(vm.Adapt<Models.StudentModel>(), cancellationToken: cancellationToken));

        group.MapDelete("/{id}",  async (Handlers.IBaseCommandHandler<Models.StudentModel, int> command, int id, CancellationToken cancellationToken) 
            => await command.RemoveAsync(id, cancellationToken: cancellationToken));

        group.MapGet("/{id}",  async (Handlers.IBaseReadOnlyQueryHandler<Models.ReadOnlyStudentModel, int> query, int id, CancellationToken cancellationToken) 
            => await query.FetchAsync<Models.ReadOnlyStudentModel>(id, cancellationToken: cancellationToken));

        group.MapGet("/",  async (Handlers.IBaseReadOnlyQueryHandler<Models.ReadOnlyStudentModel, int> query, CancellationToken cancellationToken, int page=1, int pageSize=10, string sortColumn="id", string sortDirection="asc", string searchCriteria="") 
            => await query.FetchAllAsync<Models.ReadOnlyStudentModel>(
                new QueryOption<Models.ReadOnlyStudentModel>
                {
                    Filter = ExpressionUtility.CreateSearchAllColumnsExpression<Models.ReadOnlyStudentModel>(searchCriteria),
                    PaginationOption = new QueryOption<Models.ReadOnlyStudentModel>.PaginationOptionModel
                    {
                        PageIndex = page,
                        PageSize = pageSize
                    },
                    SortOption = new QueryOption<Models.ReadOnlyStudentModel>.SortOptionModel
                    {
                        SortColumn = sortColumn,
                        SortDirection = sortDirection
                    }
                }, cancellationToken: cancellationToken));

        group.MapPost("/delete/list",  async (Handlers.IBaseCommandHandler<Models.StudentModel, int> command, List<int> ids, CancellationToken cancellationToken) 
            => new ResponseResult<List<int>>(ids, (await command.RemoveRangeImmediateAsync(x => ids.Contains(x.Id), cancellationToken: cancellationToken)).EffectedRowsCount));

        return group;
    }
}

How to install

In order to install Jinget please refer to nuget.org

Further Information

Sample codes are available via Unit Test projects which are provided beside the main source codes.

Contact Me

👨‍💻 Twitter: https://twitter.com/_jinget

📧 Email: farahmandian2011@gmail.com

📣 Instagram: https://www.instagram.com/vahidfarahmandian

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  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 was computed.  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. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in 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
8.0.50 135 9/11/2025
8.0.49 133 9/8/2025
8.0.48 128 9/8/2025
8.0.47 138 9/7/2025
8.0.46 85 8/22/2025
8.0.45 115 7/31/2025
8.0.44 104 7/31/2025
8.0.43 105 7/30/2025
8.0.42 97 7/30/2025
8.0.41 100 7/30/2025
8.0.40 97 7/30/2025
8.0.39 99 7/29/2025
8.0.38 102 7/28/2025
8.0.36-preview005 107 7/27/2025