| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Name | Name | Last commit date | ||
|---|---|---|---|---|
A multi-channel notification service built with .NET, Clean Architecture, and Domain-Driven Design as a self-study project to practice backend patterns and distributed systems concepts.
NotifyHub accepts notification requests and routes them to the appropriate provider — SMS, Email, or Telegram Bot — based on the notification type. It uses a customized Outbox Pattern to persist notifications before dispatching them, ensuring reliability even under failure conditions.
The solution follows Clean Architecture with four numbered layers that enforce a strict dependency rule (outer layers depend on inner layers, never the reverse):
src/
├── 1.Core/
│ ├── NotifyHub.Core.Domain # Entities, value objects, domain logic
│ ├── NotifyHub.Core.Contracts # Interfaces and abstractions
│ ├── NotifyHub.Core.ApplicationService # CQRS handlers, application logic
│ └── NotifyHub.Core.BuildingBlocks # Shared base types, Result pattern, base classes
│
├── 2.Infrastructure/
│ ├── NotifyHub.Infrastructure.Services # SMS, Email, Telegram providers; RabbitMQ service
│ └── Data/
│ └── NotifyHub.Infrastructure.Data.SqlServer # Outbox persistence, repositories
│
├── 3.Endpoint/
│ └── NotifyHub.Endpoint.WebAPI # ASP.NET Core Web API entry point
│
└── 4.Shared/
└── NotifyHub.Shared.Utility # Cross-cutting helpers and utilities
A factory is used to resolve the correct notification provider at runtime based on the notification type, keeping the dispatch logic decoupled from provider implementations.
Incoming notifications are saved to the database before being dispatched. A background process reads the outbox and publishes messages, providing a basic at-least-once delivery guarantee and decoupling the API from external provider availability.
SMS and Email services return a Result<T> type instead of throwing exceptions for expected failures. This makes success and error paths explicit in the application layer.
Commands and queries are separated using MediatR. Write operations (sending a notification) and read operations are handled by distinct handlers, keeping responsibilities clear.
A custom IMessageBusService wraps RabbitMQ.Client v7's async API. A reusable consumer base class (MessageBusConsumer<TMessage>) is used for implementing background consumers, making it straightforward to add new message types.
The SMS service uses Polly retry policies to handle transient failures when calling external SMS providers.
| Concern | Technology |
|---|---|
| Language / Runtime | C# / .NET |
| Web API | ASP.NET Core |
| CQRS / Mediator | MediatR |
| Message Broker | RabbitMQ (RabbitMQ.Client v7) |
| Database | SQL Server (Outbox), MongoDB |
| Resilience | Polly |
| Logging | Serilog |
| Architecture | Clean Architecture + DDD |
This project was built as a hands-on learning exercise to apply and understand:
It is not a production-ready system, but a personal study project exploring how these patterns fit together.
| Back | FazBrowse Home | New Git URL |