Marventa.Framework 3.3.2

There is a newer version of this package available.
See the version list below for details.
dotnet add package Marventa.Framework --version 3.3.2
                    
NuGet\Install-Package Marventa.Framework -Version 3.3.2
                    
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="Marventa.Framework" Version="3.3.2" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Marventa.Framework" Version="3.3.2" />
                    
Directory.Packages.props
<PackageReference Include="Marventa.Framework" />
                    
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 Marventa.Framework --version 3.3.2
                    
#r "nuget: Marventa.Framework, 3.3.2"
                    
#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 Marventa.Framework@3.3.2
                    
#: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=Marventa.Framework&version=3.3.2
                    
Install as a Cake Addin
#tool nuget:?package=Marventa.Framework&version=3.3.2
                    
Install as a Cake Tool

πŸš€ Marventa Framework

.NET License NuGet

Enterprise-grade .NET framework with Clean Architecture, CQRS, and 47+ modular features


πŸ“‹ Table of Contents


⚑ Quick Start

1. Installation

dotnet add package Marventa.Framework

2. Configure Services

using Marventa.Framework.Web.Extensions;

var builder = WebApplication.CreateBuilder(args);

// Add Marventa Framework with CQRS
builder.Services.AddMarventaFramework(builder.Configuration, options =>
{
    // Core Infrastructure
    options.EnableLogging = true;
    options.EnableCaching = true;
    options.EnableRepository = true;
    options.EnableHealthChecks = true;

    // CQRS + MediatR
    options.EnableCQRS = true;
    options.CqrsOptions.Assemblies.Add(typeof(Program).Assembly);
    options.CqrsOptions.EnableValidationBehavior = true;
    options.CqrsOptions.EnableLoggingBehavior = true;
    options.CqrsOptions.EnableTransactionBehavior = true;
});

var app = builder.Build();
app.UseMarventaFramework(builder.Configuration);
app.Run();

3. Create Your First Entity

using Marventa.Framework.Core.Entities;

public class Product : BaseEntity
{
    public string Name { get; set; } = string.Empty;
    public decimal Price { get; set; }
    public int StockQuantity { get; set; }

    // BaseEntity provides:
    // - Guid Id (auto-generated)
    // - DateTime CreatedDate, UpdatedDate
    // - bool IsDeleted (soft delete)
    // - Audit tracking (CreatedBy, UpdatedBy)
}

4. Done! πŸŽ‰

You now have:

  • βœ… Repository pattern with Unit of Work
  • βœ… CQRS with automatic validation
  • βœ… Soft delete and audit tracking
  • βœ… Logging and health checks
  • βœ… Clean Architecture structure

🎯 Core Features

1. Base Entity Classes

Class Purpose When to Use
BaseEntity Basic entity with audit tracking Default for all entities
AuditableEntity Adds versioning & concurrency Entities needing version control
TenantBaseEntity Multi-tenant isolation Multi-tenant applications

2. CQRS + MediatR Pipeline

// Command with automatic validation & transaction
public class CreateProductCommand : ICommand<Guid>
{
    public string Name { get; set; }
    public decimal Price { get; set; }
}

// Validator (automatically executed)
public class CreateProductCommandValidator : AbstractValidator<CreateProductCommand>
{
    public CreateProductCommandValidator()
    {
        RuleFor(x => x.Name).NotEmpty().MaximumLength(200);
        RuleFor(x => x.Price).GreaterThan(0);
    }
}

// Handler (transaction managed automatically)
public class CreateProductCommandHandler : IRequestHandler<CreateProductCommand, Guid>
{
    private readonly IUnitOfWork _unitOfWork;

    public CreateProductCommandHandler(IUnitOfWork unitOfWork)
    {
        _unitOfWork = unitOfWork;
    }

    public async Task<Guid> Handle(CreateProductCommand request, CancellationToken ct)
    {
        var product = new Product { Name = request.Name, Price = request.Price };
        await _unitOfWork.Repository<Product>().AddAsync(product, ct);
        // SaveChanges called automatically by TransactionBehavior
        return product.Id;
    }
}

3. Repository Pattern

public class ProductService
{
    private readonly IRepository<Product> _repository;

    public ProductService(IRepository<Product> repository)
    {
        _repository = repository;
    }

    // Simple queries
    public async Task<Product?> GetByIdAsync(Guid id)
        => await _repository.GetByIdAsync(id);

    // Advanced queries with specifications
    public async Task<IEnumerable<Product>> GetExpensiveProductsAsync()
        => await _repository.FindAsync(p => p.Price > 1000);

    // Pagination
    public async Task<IEnumerable<Product>> GetPagedAsync(int page, int size)
        => await _repository.GetPagedAsync(page, size);
}

4. Built-in Pipeline Behaviors

Behavior Purpose Automatic Actions
ValidationBehavior Input validation Validates using FluentValidation
LoggingBehavior Performance monitoring Logs execution time, warns if >500ms
TransactionBehavior Transaction management Auto SaveChanges, rollback on error
IdempotencyBehavior Duplicate prevention Prevents duplicate command execution

πŸ“¦ Installation & Setup

Step 1: Install Package

dotnet add package Marventa.Framework

Step 2: Configure appsettings.json

{
  "Marventa": {
    "ApiKey": "your-secret-key",
    "RateLimit": {
      "MaxRequests": 100,
      "WindowMinutes": 15
    },
    "Caching": {
      "Provider": "Memory"
    }
  },
  "ConnectionStrings": {
    "DefaultConnection": "your-database-connection"
  }
}

Step 3: Setup DbContext

using Marventa.Framework.Infrastructure.Data;

public class ApplicationDbContext : BaseDbContext
{
    public ApplicationDbContext(
        DbContextOptions<ApplicationDbContext> options,
        ITenantContext tenantContext)
        : base(options, tenantContext)
    {
    }

    public DbSet<Product> Products { get; set; }
    public DbSet<Order> Orders { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder); // IMPORTANT: Apply base configurations
        modelBuilder.ApplyConfigurationsFromAssembly(typeof(ApplicationDbContext).Assembly);
    }
}

BaseDbContext provides:

  • βœ… Automatic audit tracking (CreatedDate, UpdatedDate)
  • βœ… Soft delete with global query filters
  • βœ… Multi-tenancy support with automatic isolation
  • βœ… Domain event dispatching
  • βœ… Optimistic concurrency with RowVersion

πŸ—οΈ Entity Base Classes

BaseEntity - Standard Entities

using Marventa.Framework.Core.Entities;

public class Product : BaseEntity
{
    public string Name { get; set; } = string.Empty;
    public decimal Price { get; set; }
}

// Provides automatically:
// - Guid Id
// - DateTime CreatedDate, UpdatedDate
// - string? CreatedBy, UpdatedBy
// - bool IsDeleted (soft delete)
// - DateTime? DeletedDate, string? DeletedBy

AuditableEntity - With Versioning

public class Order : AuditableEntity
{
    public string OrderNumber { get; set; } = string.Empty;
    public decimal TotalAmount { get; set; }
}

// Includes BaseEntity + versioning:
// - string Version (semantic versioning)
// - byte[] RowVersion (optimistic concurrency)

TenantBaseEntity - Multi-Tenant

public class Customer : TenantBaseEntity
{
    public string CompanyName { get; set; } = string.Empty;
    public string Email { get; set; } = string.Empty;
}

// Includes BaseEntity + tenant isolation:
// - Guid TenantId
// - Automatic filtering by tenant in all queries

⚑ CQRS Pattern

Commands (Write Operations)

using Marventa.Framework.Application.Commands;

// 1. Define Command
public class UpdateProductPriceCommand : ICommand<bool>
{
    public Guid ProductId { get; set; }
    public decimal NewPrice { get; set; }
}

// 2. Validator (optional but recommended)
public class UpdateProductPriceCommandValidator : AbstractValidator<UpdateProductPriceCommand>
{
    public UpdateProductPriceCommandValidator()
    {
        RuleFor(x => x.ProductId).NotEmpty();
        RuleFor(x => x.NewPrice).GreaterThan(0).LessThan(1000000);
    }
}

// 3. Handler
public class UpdateProductPriceCommandHandler : IRequestHandler<UpdateProductPriceCommand, bool>
{
    private readonly IUnitOfWork _unitOfWork;

    public async Task<bool> Handle(UpdateProductPriceCommand request, CancellationToken ct)
    {
        var product = await _unitOfWork.Repository<Product>().GetByIdAsync(request.ProductId);
        if (product == null) return false;

        product.Price = request.NewPrice;
        await _unitOfWork.Repository<Product>().UpdateAsync(product);
        return true;
    }
}

Queries (Read Operations)

using Marventa.Framework.Application.Queries;

// 1. Define Query
public class GetProductByIdQuery : IQuery<ProductDto>
{
    public Guid Id { get; set; }
}

// 2. Handler
public class GetProductByIdQueryHandler : IRequestHandler<GetProductByIdQuery, ProductDto>
{
    private readonly IRepository<Product> _repository;

    public async Task<ProductDto> Handle(GetProductByIdQuery request, CancellationToken ct)
    {
        var product = await _repository.GetByIdAsync(request.Id);
        return new ProductDto
        {
            Id = product.Id,
            Name = product.Name,
            Price = product.Price
        };
    }
}

Using in Controllers

[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
    private readonly IMediator _mediator;

    public ProductsController(IMediator mediator) => _mediator = mediator;

    [HttpGet("{id}")]
    public async Task<ActionResult<ProductDto>> Get(Guid id)
    {
        var query = new GetProductByIdQuery { Id = id };
        var result = await _mediator.Send(query);
        return Ok(result);
    }

    [HttpPost]
    public async Task<ActionResult<Guid>> Create(CreateProductCommand command)
    {
        var id = await _mediator.Send(command);
        return CreatedAtAction(nameof(Get), new { id }, id);
    }
}

πŸ’Ύ Repository Pattern

Basic Usage

public class ProductService
{
    private readonly IRepository<Product> _repository;

    // CRUD Operations
    public async Task<Product> CreateAsync(Product product)
        => await _repository.AddAsync(product);

    public async Task<Product?> GetAsync(Guid id)
        => await _repository.GetByIdAsync(id);

    public async Task<IEnumerable<Product>> GetAllAsync()
        => await _repository.GetAllAsync();

    public async Task UpdateAsync(Product product)
        => await _repository.UpdateAsync(product);

    public async Task DeleteAsync(Product product)
        => await _repository.DeleteAsync(product); // Soft delete
}

Advanced Queries

// Find with predicate
var products = await _repository.FindAsync(p => p.Price > 100);

// Pagination
var pagedProducts = await _repository.GetPagedAsync(pageNumber: 1, pageSize: 20);

// Count
var count = await _repository.CountAsync(p => p.IsDeleted == false);

// Any
var hasExpensive = await _repository.AnyAsync(p => p.Price > 1000);

Unit of Work Pattern

public class OrderService
{
    private readonly IUnitOfWork _unitOfWork;

    public async Task<Order> CreateOrderAsync(OrderDto dto)
    {
        await _unitOfWork.BeginTransactionAsync();
        try
        {
            // Create order
            var order = new Order { OrderNumber = dto.OrderNumber };
            await _unitOfWork.Repository<Order>().AddAsync(order);

            // Update inventory
            var product = await _unitOfWork.Repository<Product>().GetByIdAsync(dto.ProductId);
            product.StockQuantity -= dto.Quantity;

            await _unitOfWork.SaveChangesAsync();
            await _unitOfWork.CommitTransactionAsync();
            return order;
        }
        catch
        {
            await _unitOfWork.RollbackTransactionAsync();
            throw;
        }
    }
}

βš™οΈ Configuration Options

Feature Flags (47 Total)

builder.Services.AddMarventaFramework(builder.Configuration, options =>
{
    // πŸ—οΈ Core Infrastructure
    options.EnableLogging = true;
    options.EnableCaching = true;
    options.EnableRepository = true;
    options.EnableHealthChecks = true;
    options.EnableValidation = true;
    options.EnableExceptionHandling = true;

    // πŸ›‘οΈ Security
    options.EnableSecurity = true;
    options.EnableJWT = true;
    options.EnableApiKeys = true;
    options.EnableEncryption = true;

    // ⚑ CQRS + MediatR
    options.EnableCQRS = true;
    options.CqrsOptions.EnableValidationBehavior = true;
    options.CqrsOptions.EnableLoggingBehavior = true;
    options.CqrsOptions.EnableTransactionBehavior = true;

    // 🌐 API Management
    options.EnableVersioning = true;
    options.EnableRateLimiting = true;
    options.EnableCompression = true;
    options.EnableIdempotency = true;

    // πŸ“Š Monitoring
    options.EnableAnalytics = true;
    options.EnableObservability = true;

    // πŸ”„ Event-Driven
    options.EnableEventDriven = true;
    options.EnableMessaging = true;
    options.EnableSagas = true;

    // 🏒 Multi-Tenancy
    options.EnableMultiTenancy = true;
});

🌟 Real-World Example

Complete working example of a Product Management API:

// 1. Entity
public class Product : BaseEntity
{
    public string Name { get; set; } = string.Empty;
    public string Description { get; set; } = string.Empty;
    public decimal Price { get; set; }
    public int StockQuantity { get; set; }
    public string Category { get; set; } = string.Empty;
}

// 2. Command
public class CreateProductCommand : ICommand<Guid>
{
    public string Name { get; set; } = string.Empty;
    public string Description { get; set; } = string.Empty;
    public decimal Price { get; set; }
    public int StockQuantity { get; set; }
    public string Category { get; set; } = string.Empty;
}

// 3. Validator
public class CreateProductCommandValidator : AbstractValidator<CreateProductCommand>
{
    public CreateProductCommandValidator()
    {
        RuleFor(x => x.Name).NotEmpty().MaximumLength(200);
        RuleFor(x => x.Price).GreaterThan(0);
        RuleFor(x => x.StockQuantity).GreaterThanOrEqualTo(0);
        RuleFor(x => x.Category).NotEmpty();
    }
}

// 4. Handler
public class CreateProductCommandHandler : IRequestHandler<CreateProductCommand, Guid>
{
    private readonly IUnitOfWork _unitOfWork;

    public CreateProductCommandHandler(IUnitOfWork unitOfWork)
    {
        _unitOfWork = unitOfWork;
    }

    public async Task<Guid> Handle(CreateProductCommand request, CancellationToken ct)
    {
        var product = new Product
        {
            Name = request.Name,
            Description = request.Description,
            Price = request.Price,
            StockQuantity = request.StockQuantity,
            Category = request.Category
        };

        await _unitOfWork.Repository<Product>().AddAsync(product, ct);
        // TransactionBehavior automatically calls SaveChangesAsync
        return product.Id;
    }
}

// 5. Query
public class GetAllProductsQuery : IQuery<IEnumerable<ProductDto>>
{
    public string? Category { get; set; }
    public decimal? MinPrice { get; set; }
    public decimal? MaxPrice { get; set; }
}

// 6. Query Handler
public class GetAllProductsQueryHandler : IRequestHandler<GetAllProductsQuery, IEnumerable<ProductDto>>
{
    private readonly IRepository<Product> _repository;

    public async Task<IEnumerable<ProductDto>> Handle(GetAllProductsQuery request, CancellationToken ct)
    {
        var query = _repository.Query();

        if (!string.IsNullOrEmpty(request.Category))
            query = query.Where(p => p.Category == request.Category);

        if (request.MinPrice.HasValue)
            query = query.Where(p => p.Price >= request.MinPrice.Value);

        if (request.MaxPrice.HasValue)
            query = query.Where(p => p.Price <= request.MaxPrice.Value);

        var products = await query.ToListAsync(ct);

        return products.Select(p => new ProductDto
        {
            Id = p.Id,
            Name = p.Name,
            Price = p.Price,
            StockQuantity = p.StockQuantity,
            Category = p.Category
        });
    }
}

// 7. Controller
[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
    private readonly IMediator _mediator;

    public ProductsController(IMediator mediator) => _mediator = mediator;

    [HttpGet]
    public async Task<ActionResult<IEnumerable<ProductDto>>> GetAll([FromQuery] GetAllProductsQuery query)
    {
        var products = await _mediator.Send(query);
        return Ok(products);
    }

    [HttpPost]
    public async Task<ActionResult<Guid>> Create([FromBody] CreateProductCommand command)
    {
        var id = await _mediator.Send(command);
        return CreatedAtAction(nameof(GetById), new { id }, id);
    }

    [HttpGet("{id}")]
    public async Task<ActionResult<ProductDto>> GetById(Guid id)
    {
        var query = new GetProductByIdQuery { Id = id };
        var product = await _mediator.Send(query);
        return product != null ? Ok(product) : NotFound();
    }
}

πŸ“š Documentation

Complete Resources

Key Topics

  • Clean Architecture Implementation
  • CQRS Pattern with MediatR
  • Repository & Unit of Work
  • Multi-Tenancy Setup
  • Event-Driven Architecture
  • Saga Pattern for Distributed Transactions
  • CDN Integration (Azure, AWS, CloudFlare)
  • Performance Optimization

πŸ†˜ Support

Get Help


πŸ“„ License

MIT License - Free for personal and commercial use.

See LICENSE for details.


<div align="center">

Built with ❀️ by Adem Kınataş

⭐ Star us on GitHub if you find this useful!

</div>

Product 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 is compatible.  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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net8.0

    • No dependencies.
  • net9.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
5.2.0 268 10/13/2025 5.2.0 is deprecated because it is no longer maintained.
5.1.0 293 10/5/2025 5.1.0 is deprecated because it is no longer maintained.
5.0.0 206 10/4/2025 5.0.0 is deprecated because it is no longer maintained.
4.6.0 213 10/3/2025 4.6.0 is deprecated because it is no longer maintained.
4.5.5 236 10/2/2025 4.5.5 is deprecated because it is no longer maintained.
4.5.4 232 10/2/2025 4.5.4 is deprecated because it is no longer maintained.
4.5.3 225 10/2/2025 4.5.3 is deprecated because it is no longer maintained.
4.5.2 226 10/2/2025 4.5.2 is deprecated because it is no longer maintained.
4.5.1 230 10/2/2025 4.5.1 is deprecated because it is no longer maintained.
4.5.0 230 10/2/2025 4.5.0 is deprecated because it is no longer maintained.
4.4.0 237 10/1/2025 4.4.0 is deprecated because it is no longer maintained.
4.3.0 235 10/1/2025 4.3.0 is deprecated because it is no longer maintained.
4.2.0 234 10/1/2025 4.2.0 is deprecated because it is no longer maintained.
4.1.0 224 10/1/2025 4.1.0 is deprecated because it is no longer maintained.
4.0.2 236 10/1/2025 4.0.2 is deprecated because it is no longer maintained.
4.0.1 227 10/1/2025 4.0.1 is deprecated because it is no longer maintained.
4.0.0 302 9/30/2025 4.0.0 is deprecated because it is no longer maintained.
3.5.2 234 9/30/2025 3.5.2 is deprecated because it is no longer maintained.
3.5.1 268 9/30/2025 3.5.1 is deprecated because it is no longer maintained.
3.4.1 273 9/30/2025 3.4.1 is deprecated because it is no longer maintained.
3.4.0 266 9/30/2025 3.4.0 is deprecated because it is no longer maintained.
3.3.2 275 9/30/2025 3.3.2 is deprecated because it is no longer maintained.
3.2.0 271 9/30/2025 3.2.0 is deprecated because it is no longer maintained.
3.1.0 266 9/29/2025 3.1.0 is deprecated because it is no longer maintained.
3.0.1 271 9/29/2025 3.0.1 is deprecated because it is no longer maintained.
3.0.1-preview-20250929165802 257 9/29/2025 3.0.1-preview-20250929165802 is deprecated because it is no longer maintained.
3.0.0 265 9/29/2025 3.0.0 is deprecated because it is no longer maintained.
3.0.0-preview-20250929164242 265 9/29/2025 3.0.0-preview-20250929164242 is deprecated because it is no longer maintained.
3.0.0-preview-20250929162455 261 9/29/2025 3.0.0-preview-20250929162455 is deprecated because it is no longer maintained.
2.12.0-preview-20250929161039 254 9/29/2025 2.12.0-preview-20250929161039 is deprecated because it is no longer maintained.
2.11.0 273 9/29/2025 2.11.0 is deprecated because it is no longer maintained.
2.10.0 268 9/29/2025 2.10.0 is deprecated because it is no longer maintained.
2.9.0 261 9/29/2025 2.9.0 is deprecated because it is no longer maintained.
2.8.0 262 9/29/2025 2.8.0 is deprecated because it is no longer maintained.
2.7.0 276 9/29/2025 2.7.0 is deprecated because it is no longer maintained.
2.6.0 268 9/28/2025 2.6.0 is deprecated because it is no longer maintained.
2.5.0 277 9/28/2025 2.5.0 is deprecated because it is no longer maintained.
2.4.0 267 9/28/2025 2.4.0 is deprecated because it is no longer maintained.
2.3.0 267 9/28/2025 2.3.0 is deprecated because it is no longer maintained.
2.2.0 281 9/28/2025 2.2.0 is deprecated because it is no longer maintained.
2.1.0 269 9/26/2025 2.1.0 is deprecated because it is no longer maintained.
2.0.9 273 9/26/2025 2.0.9 is deprecated because it is no longer maintained.
2.0.5 268 9/25/2025 2.0.5 is deprecated because it is no longer maintained.
2.0.4 271 9/25/2025 2.0.4 is deprecated because it is no longer maintained.
2.0.3 276 9/25/2025 2.0.3 is deprecated because it is no longer maintained.
2.0.1 277 9/25/2025 2.0.1 is deprecated because it is no longer maintained.
2.0.0 273 9/25/2025 2.0.0 is deprecated because it is no longer maintained.
1.1.2 353 9/24/2025 1.1.2 is deprecated because it is no longer maintained.
1.1.1 354 9/24/2025 1.1.1 is deprecated because it is no longer maintained.
1.1.0 271 9/24/2025 1.1.0 is deprecated because it is no longer maintained.
1.0.0 273 9/24/2025 1.0.0 is deprecated because it is no longer maintained.

v3.3.2: Clean Build - Fixed all build warnings. Added XML documentation to Analytics classes. Updated analyzers to 9.0.0. CI/CD workflows optimized. Zero warnings in production builds. No breaking changes - fully backward compatible.