madslundt/NetCoreMicroservicesSample
53.7
Weak · 21 September 2026
3k
lines of production code
C#
primary language
4
measurements over time
What this system is
This system is a .NET Core 3.1-based microservices architecture for managing movies, users, and reviews. It employs an event-driven design using CQRS and MediatR, with each service exposing RESTful APIs through an Ocelot API Gateway. The infrastructure supports pluggable backends for event sourcing, message brokering (RabbitMQ, Kafka, or Dapr), and persistence (SQL Server, MongoDB), ensuring loose coupling and scalability.
How it got here
2019 — Users Service and Infrastructure Foundation
6 changes.
This period focused on establishing the foundational infrastructure for the Users Service, including the implementation of the service itself and shared components like the Events project. Significant effort was also directed towards standardizing the application's architecture through centralized logging, service discovery with Consul, and an outbox pattern for reliable messaging.
2020 — Event-driven architecture and service scaffolding
18 changes.
This period focused on establishing a robust event-driven infrastructure, implementing CQRS and event sourcing patterns using MediatR and a pluggable event store. Concurrently, the team built out the initial versions of the Movies and Reviews microservices, integrating them with various message brokers and persistence backends.
Features
Add MongoDB as an outbox store implementation
A new MongoDB-based implementation of the outbox store has been introduced, allowing the application to persist outbox messages in a MongoDB collection. This includes the registration of the store as a scoped service and the configuration of connection details via appsettings, enabling users to switch to or configure a MongoDB backend for their outbox needs.
Infrastructure/Outbox/Stores/MongoDb · high confidence
Add RabbitMQ message broker infrastructure
The application now supports RabbitMQ as a message broker, introducing the core infrastructure components for event publishing and listening. This includes the RabbitMQOptions configuration class to map settings from appsettings, a RabbitMQExtensions class to register the RawRabbit client and related services, and a RabbitMQListener implementation that handles subscribing to and publishing events via RabbitMQ exchanges and queues.
Infrastructure/MessageBrokers/RabbitMQ · high confidence
Added Consul service registration and configuration
The Infrastructure/Consul directory now includes ConsulExtensions.cs and ConsulOptions.cs, which provide a new extension method to register a Consul client via dependency injection and a middleware to automatically register, health-check, and deregister the service with a Consul agent on startup and shutdown. This enables the application to discover and be discovered by other services via Consul.
Infrastructure/Consul · high confidence
Added Dapr message broker integration scaffolding
The application now includes initial support for Dapr as a message broker, introducing a new \MessageController\ that exposes a \POST /dapr/messages\ endpoint to receive and publish local events. This is accompanied by supporting infrastructure: \DaprExtensions\ for service and middleware registration, \DaprOptions\ for configuration, and a \Message\ model. The implementation is currently a placeholder, as the extension methods throw \NotImplementedException\ to indicate the feature is not yet fully ready.
Infrastructure/MessageBrokers/Dapr · medium confidence
Added Entity Framework Core and MongoDB event store implementations
The system now supports pluggable event store backends via a new \IStore\ interface. Two implementations are provided: an Entity Framework Core store (\EfCoreEventStore\) for relational databases and a MongoDB store (\MongoDbEventStore\) for document storage. Both are registered in the DI container as scoped services, allowing the application to choose the persistence layer at startup.
Infrastructure/EventStores/Stores · high confidence
Added Entity Framework Core outbox store implementation
The outbox persistence layer now supports Entity Framework Core. A new \EfCoreOutboxStore\ and its associated context and extension methods have been added to the \Infrastructure/Outbox/Stores/EfCore\ directory, enabling the application to store outbox messages in a SQL database via EF Core.
Infrastructure/Outbox/Stores/EfCore · high confidence
Added Kafka message broker integration
Users can now use Kafka as a message broker for event-driven communication. The system registers a Kafka listener that consumes events from configured topics and publishes events to Kafka, enabling asynchronous event handling across services.
Infrastructure/MessageBrokers/Kafka · high confidence
Added core domain and infrastructure interfaces for event sourcing
Introduced the foundational building blocks for the event sourcing infrastructure. The \IAggregate\ interface and \Aggregate\ base class define the contract for domain entities that track uncommitted events and versioning. Additionally, the \ISnapshot\ interface was added to support snapshotting aggregates, enabling more efficient state restoration. These changes establish the core abstractions required for the event store to function.
Infrastructure/EventStores/Aggregate, Infrastructure/EventStores/Snapshot · high confidence
Added domain event classes for user and movie lifecycle
New event classes have been introduced to track user and movie lifecycle changes. Specifically, UserCreatedEvent and UserDeletedEvent now capture user creation and deletion details, while MovieCreatedEvent and MovieDeletedEvent track corresponding movie actions. Each event includes relevant data fields and validation rules to ensure data integrity.
Src/Events/Users · high confidence
Added projection infrastructure for event handling
Introduced the core interfaces and abstract base class for the projection system. The new IProjection interface and Projection base class provide a mechanism for registering event handlers and dispatching incoming events to the appropriate processing logic.
Infrastructure/EventStores/Projection · high confidence
Added review lifecycle event definitions
Introduced new domain events for the Reviews module, specifically ReviewCreatedEvent and ReviewDeletedEvent. These events carry structured data about review creation and deletion, including identifiers for the review, movie, and user, as well as rating and text content. Each event includes a validator to ensure required fields are present and ratings fall within the 1-5 range.
Src/Events/Reviews · medium confidence
Initial Ocelot-based API Gateway with Consul service discovery and Swagger UI
Introduced a new Ocelot-based API Gateway that routes requests to the Users, Movies, and Reviews services. The gateway is configured to discover services via Consul and exposes a Swagger UI for all three downstream APIs, enabling developers to view and test the aggregated API documentation.
ApiGateway · high confidence
Initial release of the Reviews Service
The Reviews Service is introduced, providing APIs to create, retrieve, and delete reviews. Users can submit a review for a movie, fetch reviews by movie or user, and remove reviews. The service persists review data in a SQL database and manages state via an event store, with configuration for message brokers and logging.
Src/ReviewsService · high confidence
Initial release of the Users Service
The Users Service is introduced, providing endpoints to create, retrieve, and delete users. The service implements a command/query pattern with FluentValidation, manages a SQL database via Entity Framework Core (including initial migration and model snapshot), and integrates with RabbitMQ for messaging and MongoDB for an outbox pattern. The API exposes a REST interface for user management, supports Docker containerization, and includes configuration for Consul service discovery and Serilog logging.
Src/UsersService · high confidence
Introduce MoviesService with full CRUD operations and event-driven architecture
The MoviesService is introduced, providing a complete set of endpoints for managing movies. Users can create, read, delete, and list movies via the MovieController and UserController. The service implements a command/query pattern using MediatR, with handlers for CreateMovie, DeleteMovie, and DeleteMoviesByUserId. It also includes query handlers for GetMovie and GetMoviesByUserId. The service is configured with SQL Server for the database context, MongoDB for event and outbox storage, RabbitMQ for messaging, and Elasticsearch for logging. The service also integrates with Consul for service discovery and Swagger for API documentation.
Src/MoviesService · high confidence
Introduce Outbox pattern with pluggable storage backends and Swagger support
The Infrastructure/Outbox module now provides a complete outbox implementation, including the core OutboxListener, OutboxProcessor (hosted service), and OutboxMessage model. The system supports pluggable storage backends—currently Entity Framework Core, MongoDB, and a placeholder for Dapr—selected via configuration. Additionally, Swagger support is added to the infrastructure layer, allowing API documentation to be enabled and configured via app settings.
Infrastructure/Outbox · high confidence
Introduce shared Events project with automatic event subscription
A new 'Events' project has been added to the solution, providing a shared location for event definitions and infrastructure. This includes an extension method, UseSubscribeAllEvents, which automatically discovers and subscribes to all types implementing the IEvent interface, simplifying the setup of event handling across services.
Src/Events · medium confidence
Introduces core command and event bus abstractions
The application now includes foundational infrastructure for handling commands and events. This adds a \CommandBus\ for dispatching commands via MediatR, along with corresponding interfaces and base classes for events (\EventBus\, \IEventBus\, \Event\, \IEvent\). These components provide the underlying mechanisms for command processing and event publishing, enabling the rest of the system to interact with these patterns.
Infrastructure/Core/Events · high confidence
Introduces core infrastructure for CQRS, validation, and exception handling
The application now includes a new core infrastructure layer that establishes a CQRS (Command/Query) pattern using MediatR, with dedicated bus interfaces and implementations for commands and queries. A global exception filter is added to standardize error responses and logging, while a validation behavior automatically enforces FluentValidation rules on all MediatR requests. These changes provide a consistent foundation for handling requests, validating input, and managing errors across the application.
Infrastructure/Core · high confidence
New EventStore infrastructure with pluggable backends
The application now includes a new EventStore implementation that supports multiple persistence backends. The system can be configured via appsettings to use either an Entity Framework Core (EfCore) or a MongoDB store, with the specific backend selected by the 'EventStoreType' configuration option. This change introduces the core EventStore, IEventStore interface, and related helper classes for managing aggregate streams, projections, and snapshots.
Infrastructure/EventStores · high confidence
New repository interface and implementation for event-sourced aggregates
Added a new generic repository pattern for event-sourced aggregates, featuring an IRepository interface and a concrete Repository class. The implementation persists aggregates to the event store and publishes events via the event bus, supporting find, add, update, and delete operations for both single and collection-based workflows.
Infrastructure/EventStores/Repository · high confidence
Behavioural changes
Centralized logging infrastructure with correlation ID and Swagger filtering
The application now uses a centralized logging setup via the new \LoggingExtensions\ class. This configuration integrates Serilog for structured logging, enriches logs with exception details and correlation IDs from headers, and automatically excludes Swagger requests from being logged. Additionally, it integrates Elastic APM for application performance monitoring.
Infrastructure/Logging · medium confidence
Introduce configurable message broker abstraction
The application now supports pluggable message brokers (Dapr, RabbitMQ, or Kafka) selected via the 'MessageBrokerType' configuration setting. A new 'IEventListener' interface and associated extension methods allow the application to subscribe to and publish events through the chosen broker, with a runtime error thrown if an unsupported broker type is configured.
Infrastructure/MessageBrokers · high confidence
Dependencies
Upgrade to .NET Core 3.1 and update dependencies
The solution has been upgraded to .NET Core 3.1, with all project files now targeting netcoreapp3.1. This change includes updating various NuGet packages to their compatible versions, such as Microsoft.EntityFrameworkCore to 3.1.8, MediatR to 8.1.0, and Swashbuckle.AspNetCore to 5.5.1, ensuring the services are built on the supported .NET Core 3.1 runtime.
(dependencies) · high confidence
Written by watchdog.canine.dev from the codebase's own history, inside the signed delivery this page is composed from.
How this codebase got here
Score
- CAI 50 → 54 (+3.4)
- Rubric changed (rubric-2026.08.18 → rubric-2026.09.15) — scores are not directly comparable.
Lenses
- Code Health 61 → 65 (+4.4)
- Architecture 81 → 82 (+0.3)
- Maturity 47 → 60 (+13.0)
- Readiness 39 → 41 (+2.3)
- Security 64 → 63 (-0.7)
- Domain Modelling 100 → 63 (-37.3)
- Event-Driven 100 → 100 (+0.0)
- Event Sourcing 100 → 100 (+0.0)
Resolved (18)
- Change coupling: CreateUserCommand.cs ↔ Startup.cs (Src/UsersService/Commands/CreateUserCommand.cs)
- High CVE: System.Net.Security 4.3.0
- High CVE: System.Net.Security 4.3.0
- Medium CVE: Microsoft.Data.SqlClient 1.1.3
- Medium CVE: MongoDB.Driver 2.11.2
- Medium CVE: SharpCompress 0.23.0
- Medium CVE: SharpCompress 0.23.0
- Medium CVE: System.Net.Security 4.3.0
- Medium CVE: System.Net.Security 4.3.0
- Monorepo: only 1 of 4 solutions was scored
- No exposed public API
- complexity unreadable for .cs — churn × complexity hotspots could not be measured
- dormant codebase — no living knowledge left to concentrate
- redundant comment (Infrastructure/Consul/ConsulExtensions.cs)
- redundant comment (Infrastructure/Consul/ConsulExtensions.cs)
- redundant comment (Infrastructure/Consul/ConsulExtensions.cs)
- redundant comment (Infrastructure/Consul/ConsulExtensions.cs)
- redundant comment (Infrastructure/Core/ExceptionFilter.cs)
New (32)
- Documentation: no architecture or design documentation (README.md)
- End-of-life runtime: .NET netcoreapp3.1
- High CVE: System.Net.Security 4.3.0
- High IaC: WD-COMPOSE-0002 (Compose/docker-compose.yml)
- High IaC: WD-COMPOSE-0002 (Compose/docker-compose.yml)
- High IaC: WD-DOCKER-0013 (ApiGateway/Ocelot/Dockerfile)
- High IaC: WD-DOCKER-0013 (ApiGateway/Ocelot/Dockerfile)
- High IaC: WD-DOCKER-0013 (Src/MoviesService/Dockerfile)
- High IaC: WD-DOCKER-0013 (Src/MoviesService/Dockerfile)
- High IaC: WD-DOCKER-0013 (Src/ReviewsService/Dockerfile)
- High IaC: WD-DOCKER-0013 (Src/ReviewsService/Dockerfile)
- High IaC: WD-DOCKER-0013 (Src/UsersService/Dockerfile)
- High IaC: WD-DOCKER-0013 (Src/UsersService/Dockerfile)
- Medium CVE: SharpCompress 0.23.0
- Medium IaC: WD-COMPOSE-0002 (Compose/docker-compose.yml)
- Medium IaC: WD-COMPOSE-0002 (Compose/docker-compose.yml)
- Medium IaC: WD-COMPOSE-0002 (Compose/docker-compose.yml)
- Medium IaC: WD-COMPOSE-0002 (Compose/docker-compose.yml)
- Medium IaC: WD-COMPOSE-0002 (Compose/docker-compose.yml)
- Medium IaC: WD-DOCKER-0003 (ApiGateway/Ocelot/Dockerfile)
- …and 12 more
API surface
- Unchanged — 10 HTTP endpoints
Written by watchdog.canine.dev from the codebase's own history, inside the signed delivery this page is composed from.
Survey your own repository
madslundt/NetCoreMicroservicesSample was measured the same way every project in this corpus was: the same rubric, at a pinned commit, with the result published in full. Point a surveyor at a repository you know and see whether you agree with it.
About this page
- The score is its most recent published measurement, taken on 21 September 2026 at a pinned commit. It is not a live figure and does not change until the project is measured again.
- Measured at commit 1a8e7618343da0a3381abfc6319ccd9ff8adfef2 — the exact code this score is about.
- Scored under rubric-2026.09.15 — the same rubric and the same method as every other entry in this index.
- Measured by watchdog.canine.dev using codehealth-analyzer preprod-28e75b8e3254.