Muonroi.Services 2.0.2

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

Muonroi.Services

Generic EF Core service base with virtual lifecycle hooks for schema-divergent multi-tenancy architectures.

NuGet License

Overview

Muonroi.Services provides a standardized application service layer implementation designed specifically for schema-divergent multi-tenancy. At its core is the MServiceBase<TEntity, TDto> abstract class, which handles standard Entity Framework Core CRUD operations while exposing a rich set of lifecycle hooks.

Unlike traditional repository patterns, this package couples intentionally to EF Core DbContext. It provides the "Core" domain logic but delegates specific validation, enrichment, and side-effects to tenant-specific or site-specific overrides. This makes it an ideal fit for SaaS applications where different tenants require slightly different validation rules or default values for the same underlying domain entity.

Features

  • Standardized CRUD: Built-in GetByIdAsync, GetByConditionAsync, CreateAsync, UpdateAsync, and DeleteAsync reducing boilerplate.
  • DTO Mapping Integration: Seamlessly relies on IEntityMapper<TEntity, TDto> to transform inputs and outputs automatically.
  • Extensive Lifecycle Hooks: Provides virtual methods for complete interception of the mutation pipeline:
    • ValidateAsync(TEntity)
    • ApplyDefaultValues(TEntity)
    • BeforeCreate(TEntity) / AfterCreate(TEntity)
    • BeforeUpdate(TEntity) / AfterUpdate(TEntity)
  • Multi-tenant Ready: By overriding these hooks in tenant-specific subclasses (Site Profiles), you can implement divergent business rules without polluting the core service class with conditional logic.

Installation

dotnet add package Muonroi.Services

Quick Start

1. Create a Base Service

Inherit from MServiceBase to implement your generic domain service.

using Muonroi.Services;
using Microsoft.EntityFrameworkCore;

public class ProductService : MServiceBase<Product, ProductDto>
{
    public ProductService(AppDbContext context, IEntityMapper<Product, ProductDto> mapper) 
        : base(context, mapper)
    {
    }

    // Core shared logic can be added here
}

2. Override for Specific Tenant/Site Logic

When running in a multi-tenant environment, you might have a specific tenant that needs special validation.

public class EnterpriseTenantProductService : ProductService
{
    public EnterpriseTenantProductService(AppDbContext context, IEntityMapper<Product, ProductDto> mapper) 
        : base(context, mapper)
    {
    }

    protected override Task ValidateAsync(Product entity, CancellationToken ct)
    {
        if (entity.Price < 100)
        {
            throw new ValidationException("Enterprise products must have a minimum price of 100.");
        }
        return Task.CompletedTask;
    }

    protected override void ApplyDefaultValues(Product entity)
    {
        // Enforce specific defaults for this tenant
        entity.IsPremium = true;
    }

    protected override async Task AfterCreate(Product entity, CancellationToken ct)
    {
        // E.g., Publish a domain event specifically needed by this tenant
        await _eventBus.PublishAsync(new EnterpriseProductCreatedEvent(entity.Id), ct);
    }
}

API Reference

MServiceBase<TEntity, TDto>

Properties:

  • Context: The underlying DbContext
  • Mapper: The IEntityMapper<TEntity, TDto> provided via DI.

Core Methods:

  • GetByIdAsync<TKey>(TKey id, ct): Fetches and maps a single entity.
  • GetByConditionAsync(Expression<Func<TEntity, bool>> predicate, ct): Fetches multiple entities matching a predicate.
  • CreateAsync(TDto dto, ct): Maps to entity, triggers create hooks, saves, and returns the DTO.
  • UpdateAsync(TEntity entity, TDto dto, ct): Applies DTO to entity, triggers update hooks, saves, and returns the DTO.
  • DeleteAsync(TEntity entity, ct): Removes the entity from the context and saves.

Hooks (Protected Virtual):

  • ValidateAsync: Intercept before creation or update. Throw to abort.
  • ApplyDefaultValues: Sync method to inject default properties before BeforeCreate.
  • BeforeCreate / AfterCreate: Pre and post insert hooks.
  • BeforeUpdate / AfterUpdate: Pre and post update hooks.

Ecosystem Combinations

Works great standalone. Becomes significantly more powerful when combined.

+ Data.EntityFrameworkCore → MServiceBase<T> wraps MDbContext with CRUD lifecycle hooks

Provides an integrated generic repository and service layer pattern directly over EF Core.

+ Tenancy.SiteProfile → MSiteRepository resolves the correct DbContext per site automatically

Dynamically resolves which database schema or connection string to use based on the current site/tenant profile.

+ Mediator → Service methods become IRequestHandler implementations: clean CQRS separation

Wrap MServiceBase method calls inside MediatR handlers to separate command/query execution logic.

+ Observability → Each service method call traced as OTel span

Trace CRUD operations deeply to measure database performance and execution times.

+ RuleEngine → Services can run rule orchestration before/after data mutations

Execute IMRuleOrchestrator inside the BeforeCreate or BeforeUpdate hooks to enforce complex business rules automatically.

Full Stack

csharp // combined registration builder.Services.AddSiteProfileDbContext<AppDbContext>(); builder.Services.AddMediatR(cfg => cfg.RegisterServicesFromAssembly(typeof(Program).Assembly)); builder.Services.AddMuonroiObservability(); builder.Services.AddRuleEngine();

Samples

  • samples/MultiTenantSaaS/
  • samples/CQRSArchitecture/

License

Apache 2.0 — see LICENSE-APACHE.

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

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
2.0.2 92 8/26/2026
2.0.1 81 8/26/2026
2.0.0 114 8/14/2026
1.0.0-alpha.18 51 8/14/2026
1.0.0-alpha.16 73 6/22/2026
1.0.0-alpha.15 74 5/31/2026