Skip to content

vmetreveli/Meadow_Framework

Repository files navigation

Meadow Framework

A small, opinionated .NET library that wires MediatR-style dispatching, MassTransit (RabbitMQ) integration and a set of DDD primitives (AggregateRoot, Repository, UnitOfWork, ValueObject) to accelerate building maintainable, distributed applications.

Lightweight building blocks for domain-driven applications, messaging and application-level dispatching.

Table of Contents

  • Overview
  • Key features
  • Prerequisites
  • Quick start
  • Configuration
  • Usage examples
    • Command + Handler
    • Publishing integration events
    • Repository + Unit of Work
  • Security & Analyzers
  • Registered services
  • Architecture (sequence)
  • Contributing
  • Development
  • License

Overview

This repository provides a reusable set of abstractions, DI wiring and integrations commonly used in microservice-style .NET projects:

  • Application-level dispatchers and handler discovery (command / query / event handlers)
  • MassTransit integration with RabbitMQ for integration events
  • DDD primitives (AggregateRoot, EntityBase, ValueObject, Repository, UnitOfWork)
  • Outbox support and basic exception / API problem handling middleware

The goal is to reduce boilerplate and let teams focus on domain logic and message flows.

Key features

  • Automatic DI registration (scan assembly and register command/query/event handlers)
  • MediatR-style dispatching via IDispatcher / IQueryDispatcher / ICommandDispatcher
  • Integration events publishing with MassTransit (RabbitMQ)
  • DDD primitives and repository/unit-of-work abstractions
  • Exception middleware and API problem details helpers
  • Roslyn Analyzer for security (sensitive data detection)

Prerequisites

  • .NET 6+ SDK (examples use the minimal host style)
  • (Optional) RabbitMQ instance for MassTransit

Quick start

Register the framework when building your host (example for .NET 6+ minimal hosting):

using Framework.Infrastructure; // adjust namespace if different

var builder = WebApplication.CreateBuilder(args);

// register the framework and scan the current assembly (or pass any assembly that contains handlers)
builder.Services.AddFramework(builder.Configuration, typeof(Program).Assembly);

var app = builder.Build();
app.UseMiddleware<Framework.Infrastructure.ErrorHandlerMiddleware>(); // optional, if present
app.MapControllers();
app.Run();

Notes:

  • The example assumes an extension method AddFramework(IConfiguration, Assembly) is exposed by the library. If your project uses a different type or assembly for discovery, pass that assembly instead.

Configuration

A minimal appsettings.json example with RabbitMQ settings consumed by MassTransit integration:

{
  "MassTransit": {
    "Host": "rabbitmq://localhost",
    "Username": "guest",
    "Password": "guest",
    "VirtualHost": "/"
  },
  "ConnectionStrings": {
    "DefaultConnection": "Server=.;Database=MyDb;Trusted_Connection=True;"
  }
}

Usage examples

Command + handler (example)

// command (record or class)
public record CreateOrderCommand(Guid OrderId, decimal Total);

// handler (implements the framework's abstraction)
public class CreateOrderHandler : ICommandHandler<CreateOrderCommand, Result>
{
    private readonly IRepository<Order> _orders;
    public CreateOrderHandler(IRepository<Order> orders) => _orders = orders;

    public async Task<Result> Handle(CreateOrderCommand request, CancellationToken ct)
    {
        var order = Order.Create(request.OrderId, request.Total);
        await _orders.AddAsync(order, ct);
        await _orders.UnitOfWork.SaveChangesAsync(ct);
        return Result.Success();
    }
}

Publishing integration events (MassTransit)

public class OrderCreatedEvent
{
    public Guid OrderId { get; init; }
    public decimal Total { get; init; }
}

public class SomeService
{
    private readonly IPublishEndpoint _publisher;
    public SomeService(IPublishEndpoint publisher) => _publisher = publisher;

    public Task PublishOrderCreated(Guid orderId, decimal total) =>
        _publisher.Publish(new OrderCreatedEvent { OrderId = orderId, Total = total });
}

Repository + Unit of Work (conceptual)

// obtain via DI
IRepository<Order> orders = ...;
var order = await orders.GetAsync(orderId);
order.ApplyDomainEvent(new SomethingHappened(...));
await orders.UnitOfWork.SaveChangesAsync();

Security & Analyzers

The framework includes a Roslyn Analyzer to help identify potential sensitive data in your domain models.

Sensitive Data Detection (SD001)

The analyzer scans for properties with names suggesting sensitive information (e.g., Password, Email, Phone) and warns if they are not annotated with [SensitiveData].

Configuration (.editorconfig)

You can customize the list of sensitive property names in your .editorconfig:

[*.cs]
dotnet_diagnostic.SD001.severity = warning
dotnet_diagnostic.SD001.sensitive_names = SSN, CreditCard, SecretAnswer

Usage

public class User : EntityBase
{
    [SensitiveData] // Suppresses the warning and marks for masking/encryption
    public string Password { get; private set; }
}

Registered services

When you call AddFramework(...), the library will register (examples — adjust to actual project API):

  • Dispatchers / helpers
    • IDispatcher
    • ICommandDispatcher
    • IQueryDispatcher
    • IEventDispatcher
  • Handler registrations (open or concrete)
    • ICommandHandler<TCommand, TResult>
    • IQueryHandler<TQuery, TResult>
    • IEventHandler
    • INotificationHandler (if MediatR is used)
  • Repository / Persistence abstractions
    • IRepository
    • IUnitOfWork
    • IOutboxRepository (if outbox is implemented)
  • Middleware
    • ErrorHandlerMiddleware / ExceptionMiddleware (API problem mapping)

Core components

  • EntityBase, AggregateRoot, ValueObject
  • Specification and SpecificationEvaluator
  • OutboxMessage and Outbox message state
  • Mapping abstractions and common DTO helpers

Architecture (sequence)

sequenceDiagram
    participant Client
    participant API
    participant Dispatcher
    participant Handler
    participant Repository
    participant Bus

    Client->>API: HTTP Request / Command
    API->>Dispatcher: Send command
    Dispatcher->>Handler: Invoke handler
    Handler->>Repository: Persist changes
    Handler->>Bus: Publish integration event
    Bus->>OtherService: Deliver event
Loading

Contributing

  • Open issues or PRs with a clear description and small, focused changes.
  • Add unit tests for new behavior where applicable.
  • Follow existing code style and run local builds before submitting.

Development

  • Build: dotnet build
  • Run tests (if present): dotnet test
  • Linting / static analysis: follow repository CI configuration (if any)

If you add new handlers or domain types, ensure the assembly that contains them is included when calling AddFramework(...) so the DI scanner can discover and register handlers.

License

Specify a license for the repository (e.g., MIT). Add a LICENSE file at the repository root and update this section accordingly.

Contact For questions or contributions, open an issue in this repository or contact the maintainers listed in the project metadata.

About

Framework For DDD

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages