SkillAgentSearch skills...

Modern

.NET modern tools for fast and efficient development

Install / Use

/learn @anton-martyniuk/Modern

README

Modern

What is Modern?

Modern is a set of modern .NET tools :hammer: :wrench: for fast and efficient development of common backend tasks. It allows to create a production ready applications with just set of models and configuration which can be further extended. Modern tool are flexible, easily changeable and extendable.
It includes the following components:

  • generic repositories for SQL and NoSQL databases
  • generic services with and without caching support
  • generic in memory services with in-memory filtering capabilities
  • in-memory and redis generic caches
  • generic set of CQRS queries and commands over repository (if you prefer CQRS over services)
  • generic controllers for all types of services
  • OData controllers for all types of services

For more information - see full documentation here.

Examples for all types of components - see here.


Table of contents :bookmark_tabs:

How to get started?

Lets create a Web Api with CRUD operations over Airplane entities. We need a repository, service and controller.

  1. Install the following Nuget packages:
  1. Create classes for the following models: AirplaneDto and AirplaneDbo.

  2. Create an EF Core DbContext for accessing the AirplaneDbo.

  3. Register the Modern builder in DI and add the following components:

builder.Services
    .AddModern()
    .AddRepositoriesEfCore(options =>
    {
        options.AddRepository<FlyingDbContext, AirplaneDbo, long>();
    })
    .AddServices(options =>
    {
        options.AddService<AirplaneDto, AirplaneDbo, long, IModernRepository<AirplaneDbo, long>>();
    })
    .AddControllers(options =>
    {
        options.AddController<CreateRequest, UpdateRequest, AirplaneDto, AirplaneDbo, long>();
    });

As a result a production ready API will be created:

GET :large_blue_circle:
/Airplanes/get/{id}

GET :large_blue_circle: :large_blue_circle:
/Airplanes/get

POST :white_check_mark:
/Airplanes/create

POST :white_check_mark: :white_check_mark:
/Airplanes/create-many

PUT :part_alternation_mark:
/Airplanes/update/{id}

PUT :part_alternation_mark: :part_alternation_mark:
/Airplanes/update-many

PATCH :heavy_dollar_sign:
/Airplanes/patch/{id}

DELETE :x:
/Airplanes/delete/{id}

DELETE :x: :x:
/Airplanes/delete-many

Roadmap :arrow_right: :date:

The following features will be implemented in the next releases:

  • Assembly scan in DI packages
  • Unit and integration tests
  • MinimalsApis
  • Reflection improvements

Repositories

Modern generic repository is divided into 2 interfaces: IModernQueryRepository<TEntity, TId> and IModernCrudRepository<TEntity, TId>. IModernQueryRepository has the following methods:

Task<TEntity> GetByIdAsync(TId id, EntityIncludeQuery<TEntity>? includeQuery = null, CancellationToken cancellationToken = default);

Task<TEntity?> TryGetByIdAsync(TId id, EntityIncludeQuery<TEntity>? includeQuery = null, CancellationToken cancellationToken = default);

Task<IEnumerable<TEntity>> GetAllAsync(EntityIncludeQuery<TEntity>? includeQuery = null, CancellationToken cancellationToken = default);

Task<long> CountAsync(CancellationToken cancellationToken = default);

Task<long> CountAsync(Expression<Func<TEntity, bool>> predicate, EntityIncludeQuery<TEntity>? includeQuery = null,
    CancellationToken cancellationToken = default);

Task<bool> ExistsAsync(Expression<Func<TEntity, bool>> predicate, EntityIncludeQuery<TEntity>? includeQuery = null, CancellationToken cancellationToken = default);

Task<TEntity?> FirstOrDefaultAsync(Expression<Func<TEntity, bool>> predicate, EntityIncludeQuery<TEntity>? includeQuery = null, CancellationToken cancellationToken = default);

Task<TEntity?> SingleOrDefaultAsync(Expression<Func<TEntity, bool>> predicate, EntityIncludeQuery<TEntity>? includeQuery = null, CancellationToken cancellationToken = default);

Task<IEnumerable<TEntity>> WhereAsync(Expression<Func<TEntity, bool>> predicate, EntityIncludeQuery<TEntity>? includeQuery = null, CancellationToken cancellationToken = default);

Task<PagedResult<TEntity>> WhereAsync(Expression<Func<TEntity, bool>> predicate, int pageNumber, int pageSize, EntityIncludeQuery<TEntity>? includeQuery = null, CancellationToken cancellationToken = default);

IQueryable<TEntity> AsQueryable();

IModernCrudRepository has the following methods:

Task<TEntity> CreateAsync(TEntity entity, CancellationToken cancellationToken = default);

Task<List<TEntity>> CreateAsync(List<TEntity> entities, CancellationToken cancellationToken = default);

Task<TEntity> UpdateAsync(TId id, TEntity entity, CancellationToken cancellationToken = default);

Task<List<TEntity>> UpdateAsync(List<TEntity> entities, CancellationToken cancellationToken = default);

Task<TEntity> UpdateAsync(TId id, Action<TEntity> update, CancellationToken cancellationToken = default);

Task<bool> DeleteAsync(TId id, CancellationToken cancellationToken = default);

Task<bool> DeleteAsync(List<TId> ids, CancellationToken cancellationToken = default);

Task<TEntity> DeleteAndReturnAsync(TId id, CancellationToken cancellationToken = default);

Repositories for SQL databases :pencil:

Modern generic repositories for SQL databases are built on top of 2 the following ORM frameworks:

  • EF Core
  • Dapper

To use EF Core repository install the Modern.Repositories.EFCore Nuget package and register it within Modern builder in DI:

builder.Services
    .AddModern()
    .AddRepositoriesEfCore(options =>
    {
        options.AddRepository<FlyingDbContext, AirplaneDbo, long>(useDbFactory: false);
    });

Specify the type of EF Core DbContext, Dbo entity model and primary key. useDbFactory parameter indicates whether repository with DbContextFactory should be used. The default value is false.

:information_source: Use this parameter if you plan to inherit from this generic repository and extend or change its functionality.
When using DbContextFactory every repository creates and closes a database connection in each method.
When NOT using DbContextFactory repository shares the same database connection during its lifetime.

:warning: It is not recommended to use useDbFactory = false when repository is registered as SingleInstance, otherwise a single database connection will persist during the whole application lifetime

To use Dapper repository install the Modern.Repositories.Dapper Nuget package and register it within Modern builder in DI:

builder.Services
    .AddModern()
    .AddRepositoriesDapper(options =>
    {
        options.ProvideDatabaseConnection(() => new NpgsqlConnection(connectionString));
        options.AddRepository<AirplaneDapperMapping, AirplaneDbo, long>();
    });

Specify the type of Dapper mapping class, Dbo entity model and primary key.
A dapper needs to know how to create a database connection. Since there are multiple database connection classes - provide the needed one using ProvideDatabaseConnection method. Dapper repository requires to have a small mapping class that way generic repository can match the entity property name with database table column.

:information_source: Mapping class for Dapper is a part of Modern tools and not a part of Dapper library

For example consider the following mapping class:

public class AirplaneDapperMapping : DapperEntityMapping<AirplaneDbo>
{
    protected override void CreateMapping()
    {
        Table("db_schema_name.airplanes")
            .Id(nameof(AirplaneDbo.Id), "id")
            .Column(nameof(AirplaneDbo.YearOfManufacture), "year_of_manufacture")
            .Column(nameof(AirplaneDbo.ModelId), "model_id")
            //...
            ;
    }
}

Repositories for No SQL databases :pencil:

Modern generic repositories for No SQL databases are built on of the following NoSQL databases:

  • MongoDB
  • LiteDb (embedded single-file NoSQL database)

To use MongoDB repository install the Modern.Repositories.MongoDB Nuget package and register it within Modern builder in DI:

builder.Services
    .AddModern()
    .AddRepositoriesMongoDb(options =>
    {
        options.ConfigureMongoDbClient(mongoDbConnectionString);
        options.AddRepository<AirplaneDbo, string>("database_name", "collection_name");
    });

Specify the type of Dbo entity model and "_id" key.
Provide the connection string in ConfigureMongoDbClient method. You can also use the second parameter updateSettings and configure the custom parameters in a MongoClientSettings class of MongoDB Driver.

To use LiteDB repository install the Modern.Repositories.LiteDB Nuget package and register it within Modern builder in DI:

builder.Services
    .AddModern()
    .AddRepositoriesLiteDb(options =>
    {
        options.AddRepository<AirplaneDbo, string>("connection_string", "collection_name");
    });

Specify the type of Dbo entity model and "_id" key.

:information_

View on GitHub
GitHub Stars103
CategoryDevelopment
Updated2d ago
Forks19

Languages

C#

Security Score

100/100

Audited on Apr 1, 2026

No findings