Merge pull request #357 from meysamhadeli/docs/update-aspir-docs

docs/update aspir docs
This commit is contained in:
Meysam Hadeli 2025-07-23 16:28:40 +03:30 committed by GitHub
commit 44e408258f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
415 changed files with 456 additions and 506 deletions

120
README.md
View File

@ -1,23 +1,20 @@
# 🛩️ Booking Monolith
<div align="center" style="margin-bottom:20px"> <div align="center" style="margin-bottom:20px">
<img src="assets/logo.png" alt="booking-microservices" /> <div align="left">
<div align="center"> <a href="https://github.com/meysamhadeli/booking-monolith/actions/workflows/ci.yml"><img alt="build-status" src="https://github.com/meysamhadeli/booking-monolith/actions/workflows/ci.yml/badge.svg?branch=main&style=flat-square"/></a>
<a href="https://github.com/meysamhadeli/booking-microservices/actions/workflows/ci.yml"><img alt="ci-status" src="https://github.com/meysamhadeli/booking-microservices/actions/workflows/ci.yml/badge.svg?branch=main&style=flat-square"/></a> <a href="https://github.com/meysamhadeli/booking-monolith/blob/main/LICENSE"><img alt="build-status" src="https://img.shields.io/github/license/meysamhadeli/booking-monolith?color=%234275f5&style=flat-square"/></a>
<a href="https://github.com/meysamhadeli/booking-microservices/blob/main/LICENSE"><img alt="build-status" src="https://img.shields.io/github/license/meysamhadeli/booking-microservices?color=%234275f5&style=flat-square"/></a>
</div> </div>
</div> </div>
> 🚀 **A practical microservices with the latest technologies and architecture like Vertical Slice Architecture, Event Sourcing, CQRS, DDD, gRpc, MongoDB, RabbitMq and Masstransit in .Net 9.** > 🚀 **A practical Monolith architecture with the latest technologies and architectures like Vertical Slice Architecture, Event Driven Architecture, CQRS, DDD and Aspire in .Net 9.**
## You can find other version of this project here: ## You can find other version of this project here:
- [Booking with Microservices Architecture](https://github.com/meysamhadeli/booking-microservices)
- [Booking with Modular Monolith Architecture](https://github.com/meysamhadeli/booking-modular-monolith) - [Booking with Modular Monolith Architecture](https://github.com/meysamhadeli/booking-modular-monolith)
- [Booking with Monolith Architecture](https://github.com/meysamhadeli/booking-monolith)
<div> <a href="https://gitpod.io/#https://github.com/meysamhadeli/booking-monolith"><img alt="Open in Gitpod" src="https://gitpod.io/button/open-in-gitpod.svg"/></a>
<a href="https://gitpod.io/#https://github.com/meysamhadeli/booking-microservices"><img alt="Open in Gitpod" src="https://gitpod.io/button/open-in-gitpod.svg"/></a>
</div>
<div>
<a href='https://codespaces.new/meysamhadeli/booking-microservices?quickstart=1'><img alt='Open in GitHub Codespaces' src='https://github.com/codespaces/badge.svg'></a>
</div>
# Table of Contents # Table of Contents
@ -26,17 +23,15 @@
- [Key Features](#key-features) - [Key Features](#key-features)
- [When to Use](#when-to-use) - [When to Use](#when-to-use)
- [Challenges](#challenges) - [Challenges](#challenges)
- [The Domain and Bounded Context - Service Boundary](#the-domain-and-bounded-context---service-boundary) - [The Domain and Bounded Context](#the-domain-and-bounded-context)
- [Structure of Project](#structure-of-project) - [Structure of Project](#structure-of-project)
- [Development Setup](#development-setup) - [Development Setup](#development-setup)
- [Dotnet Tools Packages](#dotnet-tools-packages) - [Dotnet Tools Packages](#dotnet-tools-packages)
- [Husky](#husky) - [Husky](#husky)
- [Upgrade Nuget Packages](#upgrade-nuget-packages) - [Upgrade Nuget Packages](#upgrade-nuget-packages)
- [How to Run](#how-to-run) - [How to Run](#how-to-run)
- [Config Certificate](#config-certificate) - [Config Certificate](#config-certificate)
- [Aspire](#aspire)
- [Docker Compose](#docker-compose) - [Docker Compose](#docker-compose)
- [Kubernetes](#kubernetes)
- [Build](#build) - [Build](#build)
- [Run](#run) - [Run](#run)
- [Test](#test) - [Test](#test)
@ -49,12 +44,11 @@
- :sparkle: Using `Vertical Slice Architecture` for `architecture` level. - :sparkle: Using `Vertical Slice Architecture` for `architecture` level.
- :sparkle: Using `Domain Driven Design (DDD)` to implement all `business logic`. - :sparkle: Using `Domain Driven Design (DDD)` to implement all `business logic`.
- :sparkle: Using `Rabbitmq` on top of `Masstransit` for `Event Driven Architecture`.
- :sparkle: Using `gRPC` for `internal communication`.
- :sparkle: Using `CQRS` implementation with `MediatR` library. - :sparkle: Using `CQRS` implementation with `MediatR` library.
- :sparkle: Using `Postgres` for `write side` database. - :sparkle: Using `Postgres` for `write side` database.
- :sparkle: Using `InMemory Broker` on top of `Masstransit` for `Event Driven Architecture`.
- :sparkle: Using `MongoDB` for `read side` database. - :sparkle: Using `MongoDB` for `read side` database.
- :sparkle: Using `Event Store` for `write side` of Booking Microservice/Module to store all `historical change` of aggregate. - :sparkle: Using `Event Store` for `write side` of Booking to store all `historical change` of aggregate.
- :sparkle: Using `Inbox Pattern` for ensuring message idempotency for receiver and `Exactly once Delivery`. - :sparkle: Using `Inbox Pattern` for ensuring message idempotency for receiver and `Exactly once Delivery`.
- :sparkle: Using `Outbox Pattern` for ensuring no message is lost and there is at `At Least One Delivery`. - :sparkle: Using `Outbox Pattern` for ensuring no message is lost and there is at `At Least One Delivery`.
- :sparkle: Using `Unit Testing` for testing small units and mocking our dependencies with `Nsubstitute`. - :sparkle: Using `Unit Testing` for testing small units and mocking our dependencies with `Nsubstitute`.
@ -68,11 +62,7 @@
- :sparkle: Using `OpenTelemetry` for distributed tracing on top of `Jaeger`. - :sparkle: Using `OpenTelemetry` for distributed tracing on top of `Jaeger`.
- :sparkle: Using `OpenTelemetry` for monitoring on top of `Prometheus` and `Grafana`. - :sparkle: Using `OpenTelemetry` for monitoring on top of `Prometheus` and `Grafana`.
- :sparkle: Using `IdentityServer` for authentication and authorization base on `OpenID-Connect` and `OAuth2`. - :sparkle: Using `IdentityServer` for authentication and authorization base on `OpenID-Connect` and `OAuth2`.
- :sparkle: Using `Yarp` as a microservices `gateway`. - :sparkle: Using `Aspire` for `service discovery`, `observability`, and `local orchestration` of microservices.
- :sparkle: Using `Kubernetes` to achieve efficient `scaling` and ensure `high availability` for each of our microservices.
- :sparkle: Using `Nginx Ingress Controller` for `load balancing` between our microservices top of `Kubernetes`.
- :sparkle: Using `cert-manager` to Configure `TLS` in `kubernetes cluster`.
## Technologies - Libraries ## Technologies - Libraries
@ -95,48 +85,46 @@
- ✔️ **[`Hellang.Middleware.ProblemDetails`](https://github.com/khellang/Middleware/tree/master/src/ProblemDetails)** - A middleware for handling exception in .Net Core. - ✔️ **[`Hellang.Middleware.ProblemDetails`](https://github.com/khellang/Middleware/tree/master/src/ProblemDetails)** - A middleware for handling exception in .Net Core.
- ✔️ **[`NewId`](https://github.com/phatboyg/NewId)** - NewId can be used as an embedded unique ID generator that produces 128 bit (16 bytes) sequential IDs. - ✔️ **[`NewId`](https://github.com/phatboyg/NewId)** - NewId can be used as an embedded unique ID generator that produces 128 bit (16 bytes) sequential IDs.
- ✔️ **[`Yarp`](https://github.com/microsoft/reverse-proxy)** - Reverse proxy toolkit for building fast proxy servers in .NET. - ✔️ **[`Yarp`](https://github.com/microsoft/reverse-proxy)** - Reverse proxy toolkit for building fast proxy servers in .NET.
- ✔️ **[`Tye`](https://github.com/dotnet/tye)** - Developer tool that makes developing, testing, and deploying microservices and distributed applications easier.
- ✔️ **[`gRPC-dotnet`](https://github.com/grpc/grpc-dotnet)** - gRPC functionality for .NET.
- ✔️ **[`EventStore`](https://github.com/EventStore/EventStore)** - The open-source, functional database with Complex Event Processing. - ✔️ **[`EventStore`](https://github.com/EventStore/EventStore)** - The open-source, functional database with Complex Event Processing.
- ✔️ **[`MongoDB.Driver`](https://github.com/mongodb/mongo-csharp-driver)** - .NET Driver for MongoDB. - ✔️ **[`MongoDB.Driver`](https://github.com/mongodb/mongo-csharp-driver)** - .NET Driver for MongoDB.
- ✔️ **[`xUnit.net`](https://github.com/xunit/xunit)** - A free, open source, community-focused unit testing tool for the .NET Framework. - ✔️ **[`xUnit.net`](https://github.com/xunit/xunit)** - A free, open source, community-focused unit testing tool for the .NET Framework.
- ✔️ **[`Respawn`](https://github.com/jbogard/Respawn)** - Respawn is a small utility to help in resetting test databases to a clean state. - ✔️ **[`Respawn`](https://github.com/jbogard/Respawn)** - Respawn is a small utility to help in resetting test databases to a clean state.
- ✔️ **[`Testcontainers`](https://github.com/testcontainers/testcontainers-dotnet)** - Testcontainers for .NET is a library to support tests with throwaway instances of Docker containers. - ✔️ **[`Testcontainers`](https://github.com/testcontainers/testcontainers-dotnet)** - Testcontainers for .NET is a library to support tests with throwaway instances of Docker containers.
- ✔️ **[`K6`](https://github.com/grafana/k6)** - Modern load testing for developers and testers in the DevOps era. - ✔️ **[`K6`](https://github.com/grafana/k6)** - Modern load testing for developers and testers in the DevOps era.
- ✔️ **[`Aspire`](https://github.com/dotnet/aspire)** - .NET stack for building and orchestrating observable, distributed cloud-native applications.
## Key Features ## Key Features
1. **Independent Services**: Each service is a separate project with its own database and deployment pipeline, enabling independent development and deployment. 1. **Single Codebase**: All components (UI, business logic, data access) are part of one project.
2. **Decentralized Communication**: Services communicate via APIs (REST, gRPC) or message brokers (RabbitMQ, Kafka), ensuring loose coupling and resilience. 2. **Tight Coupling**: Components are highly dependent on each other, making changes riskier.
3. **Scalability**: Services can be scaled independently based on demand, allowing efficient resource utilization. 3. **Simple Deployment**: The entire application is deployed as a single unit.
4. **Fault Tolerance**: Failures are isolated, preventing cascading failures and ensuring high availability. 4. **Centralized Database**: Typically uses a single database for all data storage and access.
5. **Technology Agnostic**: Services can use different technologies, frameworks, or databases, providing flexibility.
## When to Use ## When to Use
1. **Large and Complex Projects**: Ideal for applications with complex business logic that can be broken into smaller, manageable services. 1. **Small to Medium Projects**: Ideal for applications with limited complexity and scope.
2. **High Scalability Needs**: Suitable for applications requiring independent scaling of components. 2. **Rapid Development**: Suitable for projects requiring quick development and deployment.
3. **Fault Tolerance and High Availability**: Perfect for systems where failure isolation and uptime are critical. 3. **Small Teams**: Works well for small teams with limited resources.
4. **Distributed Teams**: Enables teams to work independently on different services. 4. **Low Scalability Needs**: Best for applications with predictable and low traffic.
5. **Frequent Updates**: Supports continuous deployment and A/B testing for individual services.
6. **Technology Diversity**: Allows the use of different technologies for different services.
## Challenges ## Challenges
- Increased complexity in management, DevOps overhead, data consistency, latency, and higher costs. - Harder to maintain as the codebase grows.
- Limited scalability (scaling requires scaling the entire application).
- Difficult to adopt new technologies incrementally.
## The Domain And Bounded Context - Service Boundary ## The Domain And Bounded Context
- `Identity Service`: The Identity Service is a bounded context for the authentication and authorization of users using [Identity Server](https://github.com/DuendeSoftware/IdentityServer). This service is responsible for creating new users and their corresponding roles and permissions using [.Net Core Identity](https://docs.microsoft.com/en-us/aspnet/core/security/authentication/identity) and Jwt authentication and authorization. - `Identity`: The Identity is a bounded context for the authentication and authorization of users using [Identity Server](https://github.com/DuendeSoftware/IdentityServer). This service is responsible for creating new users and their corresponding roles and permissions using [.Net Core Identity](https://docs.microsoft.com/en-us/aspnet/core/security/authentication/identity) and Jwt authentication and authorization.
- `Flight Service`: The Flight Service is a bounded context `CRUD` service to handle flight related operations. - `Flight`: The Flight is a bounded context `CRUD` service to handle flight related operations.
- `Passenger Service`: The Passenger Service is a bounded context for managing passenger information, tracking activities and subscribing to get notification for out of stock products. - `Passenger`: The Passenger is a bounded context for managing passenger information, tracking activities and subscribing to get notification for out of stock products.
- `Booking Service`: The Booking Service is a bounded context for managing all operation related to booking ticket. - `Booking`: The Booking is a bounded context for managing all operation related to booking ticket.
![](./assets/booking-microservices.png) ![](./assets/booking-monolith.png)
## Structure of Project ## Structure of Project
@ -178,7 +166,7 @@ dotnet tool restore
``` ```
### Husky ### Husky
Here we use `husky` to handel some pre commit rules and we used `conventional commits` rules and `formatting` as pre commit rules, here in [package.json](.././package.json). of course, we can add more rules for pre commit in future. (find more about husky in the [documentation](https://typicode.github.io/husky/get-started.html)) Here we use `husky` to handel some pre commit rules and we used `conventional commits` rules and `formatting` as pre commit rules, here in [package.json](./package.json). of course, we can add more rules for pre commit in future. (find more about husky in the [documentation](https://typicode.github.io/husky/get-started.html))
We need to install `husky` package for `manage` `pre commits hooks` and also I add two packages `@commitlint/cli` and `@commitlint/config-conventional` for handling conventional commits rules in [package.json](.././package.json). We need to install `husky` package for `manage` `pre commits hooks` and also I add two packages `@commitlint/cli` and `@commitlint/config-conventional` for handling conventional commits rules in [package.json](.././package.json).
Run the command bellow in the root of project to install all npm dependencies related to husky: Run the command bellow in the root of project to install all npm dependencies related to husky:
@ -205,24 +193,13 @@ Run the following commands to [Config SSL](https://docs.microsoft.com/en-us/aspn
dotnet dev-certs https -ep %USERPROFILE%\.aspnet\https\aspnetapp.pfx -p password dotnet dev-certs https -ep %USERPROFILE%\.aspnet\https\aspnetapp.pfx -p password
dotnet dev-certs https --trust dotnet dev-certs https --trust
``` ```
> Note: for running this command in `powershell` use `$env:USERPROFILE` instead of `%USERPROFILE%`* ***Note:** for running this command in `powershell` use `$env:USERPROFILE` instead of `%USERPROFILE%`*
#### macOS or Linux #### macOS or Linux
```bash ```bash
dotnet dev-certs https -ep ${HOME}/.aspnet/https/aspnetapp.pfx -p $CREDENTIAL_PLACEHOLDER$ dotnet dev-certs https -ep ${HOME}/.aspnet/https/aspnetapp.pfx -p $CREDENTIAL_PLACEHOLDER$
dotnet dev-certs https --trust dotnet dev-certs https --trust
``` ```
### Aspire
To run the application using the `ASPIRE App Host`, execute the following command from the solution root:
```bash
dotnet run --project ./src/Aspire/src/AppHost
```
> Note:The `ASPIRE dashboard` will be available at `http://localhost:18888`
> ### Docker Compose > ### Docker Compose
@ -232,41 +209,28 @@ To run this app in `Docker`, use the [docker-compose.yaml](./deployments/docker-
docker-compose -f ./deployments/docker-compose/docker-compose.yaml up -d docker-compose -f ./deployments/docker-compose/docker-compose.yaml up -d
``` ```
> ### Kubernetes
To `configure TLS` in the `Kubernetes cluster`, we need to install `cert-manager` based on the [docs](https://cert-manager.io/docs/installation) and run the following commands to apply TLS in our application. Here, we use [Let's Encrypt](https://letsencrypt.org/) to encrypt our certificate.
```bash
kubectl apply -f ./deployments/kubernetes/booking-cert-manager.yml
```
To apply all necessary `deployments`, `pods`, `services`, `ingress`, and `config maps`, please run the following command:
```bash
kubectl apply -f ./deployments/kubernetes/booking-microservices.yml
```
> ### Build > ### Build
To `build` all microservices, run this command in the `root` of the project: To `build` monolith app, run this command in the `root` of the project:
```bash ```bash
dotnet build dotnet build
``` ```
> ### Run > ### Run
To `run` each microservice, run this command in the root of the `Api` folder of each microservice where the `csproj` file is located: To `run` monolith app, run this command in the root of the `Api` folder:
```bash ```bash
dotnet run dotnet run
``` ```
> ### Test > ### Test
To `test` all microservices, run this command in the `root` of the project: To `test` monolith app, run this command in the `root` of the project:
```bash ```bash
dotnet test dotnet test
``` ```
> ### Documentation Apis > ### Documentation Apis
Each microservice provides `API documentation` and navigate to `/swagger` for `Swagger OpenAPI` or `/scalar/v1` for `Scalar OpenAPI` to visit list of endpoints. For checking `API documentation`, navigate to `/swagger` for `Swagger OpenAPI` or `/scalar/v1` for `Scalar OpenAPI` to visit list of endpoints.
As part of API testing, I created the [booking.rest](./booking.rest) file which can be run with the [REST Client](https://github.com/Huachao/vscode-restclient) `VSCode plugin`. As part of API testing, I created the [booking.rest](./booking.rest) file which can be run with the [REST Client](https://github.com/Huachao/vscode-restclient) `VSCode plugin`.
@ -280,7 +244,7 @@ Thanks a bunch for supporting me!
## Contribution ## Contribution
Thanks to all [contributors](https://github.com/meysamhadeli/booking-microservices/graphs/contributors), you're awesome and this wouldn't be possible without you! The goal is to build a categorized, community-driven collection of very well-known resources. Thanks to all [contributors](https://github.com/meysamhadeli/booking-monolith/graphs/contributors), you're awesome and this wouldn't be possible without you! The goal is to build a categorized, community-driven collection of very well-known resources.
Please follow this [contribution guideline](./CONTRIBUTION.md) to submit a pull request or create the issue. Please follow this [contribution guideline](./CONTRIBUTION.md) to submit a pull request or create the issue.
@ -293,4 +257,4 @@ Please follow this [contribution guideline](./CONTRIBUTION.md) to submit a pull
- [https://github.com/pdevito3/MessageBusTestingInMemHarness](https://github.com/pdevito3/MessageBusTestingInMemHarness) - [https://github.com/pdevito3/MessageBusTestingInMemHarness](https://github.com/pdevito3/MessageBusTestingInMemHarness)
## License ## License
This project is made available under the MIT license. See [LICENSE](https://github.com/meysamhadeli/booking-microservices/blob/main/LICENSE) for details. This project is made available under the MIT license. See [LICENSE](https://github.com/meysamhadeli/booking-monolith/blob/main/LICENSE) for details.

View File

@ -29,4 +29,4 @@ app.UseEndpoints(endpoints =>
app.MapGet("/", x => x.Response.WriteAsync(appOptions.Name)); app.MapGet("/", x => x.Response.WriteAsync(appOptions.Name));
app.Run(); app.Run();

View File

@ -213,4 +213,4 @@ var gateway = builder.AddProject<Projects.ApiGateway>("api-gateway")
.WithHttpEndpoint(port: 5001, name: "gateway-http") .WithHttpEndpoint(port: 5001, name: "gateway-http")
.WithHttpsEndpoint(port: 5000, name: "gateway-https"); .WithHttpsEndpoint(port: 5000, name: "gateway-https");
builder.Build().Run(); builder.Build().Run();

View File

@ -47,4 +47,4 @@ public class CachingBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest,
return response; return response;
} }
} }

View File

@ -4,4 +4,4 @@ public interface ICacheRequest
{ {
string CacheKey { get; } string CacheKey { get; }
DateTime? AbsoluteExpirationRelativeToNow { get; } DateTime? AbsoluteExpirationRelativeToNow { get; }
} }

View File

@ -4,4 +4,4 @@ namespace BuildingBlocks.Caching
{ {
string CacheKey { get; } string CacheKey { get; }
} }
} }

View File

@ -36,4 +36,4 @@ namespace BuildingBlocks.Caching
return response; return response;
} }
} }
} }

View File

@ -7,4 +7,4 @@ public static class IdentityConstant
public const string Admin = "admin"; public const string Admin = "admin";
public const string User = "user"; public const string User = "user";
} }
} }

View File

@ -8,4 +8,4 @@ public record FlightDeleted(Guid Id) : IIntegrationEvent;
public record AircraftCreated(Guid Id) : IIntegrationEvent; public record AircraftCreated(Guid Id) : IIntegrationEvent;
public record AirportCreated(Guid Id) : IIntegrationEvent; public record AirportCreated(Guid Id) : IIntegrationEvent;
public record SeatCreated(Guid Id) : IIntegrationEvent; public record SeatCreated(Guid Id) : IIntegrationEvent;
public record SeatReserved(Guid Id) : IIntegrationEvent; public record SeatReserved(Guid Id) : IIntegrationEvent;

View File

@ -2,4 +2,4 @@ using BuildingBlocks.Core.Event;
namespace BuildingBlocks.Contracts.EventBus.Messages; namespace BuildingBlocks.Contracts.EventBus.Messages;
public record UserCreated(Guid Id, string Name, string PassportNumber) : IIntegrationEvent; public record UserCreated(Guid Id, string Name, string PassportNumber) : IIntegrationEvent;

View File

@ -3,4 +3,4 @@ using BuildingBlocks.Core.Event;
namespace BuildingBlocks.Contracts.EventBus.Messages; namespace BuildingBlocks.Contracts.EventBus.Messages;
public record PassengerRegistrationCompleted(Guid Id) : IIntegrationEvent; public record PassengerRegistrationCompleted(Guid Id) : IIntegrationEvent;
public record PassengerCreated(Guid Id) : IIntegrationEvent; public record PassengerCreated(Guid Id) : IIntegrationEvent;

View File

@ -2,4 +2,4 @@ using BuildingBlocks.Core.Event;
namespace BuildingBlocks.Contracts.EventBus.Messages; namespace BuildingBlocks.Contracts.EventBus.Messages;
public record BookingCreated(Guid Id) : IIntegrationEvent; public record BookingCreated(Guid Id) : IIntegrationEvent;

View File

@ -9,4 +9,4 @@ public interface ICommand : ICommand<Unit>
public interface ICommand<out T> : IRequest<T> public interface ICommand<out T> : IRequest<T>
where T : notnull where T : notnull
{ {
} }

View File

@ -11,4 +11,4 @@ public interface ICommandHandler<in TCommand, TResponse> : IRequestHandler<TComm
where TCommand : ICommand<TResponse> where TCommand : ICommand<TResponse>
where TResponse : notnull where TResponse : notnull
{ {
} }

View File

@ -5,4 +5,4 @@ namespace BuildingBlocks.Core.CQRS;
public interface IQuery<out T> : IRequest<T> public interface IQuery<out T> : IRequest<T>
where T : notnull where T : notnull
{ {
} }

View File

@ -6,4 +6,4 @@ public interface IQueryHandler<in TQuery, TResponse> : IRequestHandler<TQuery, T
where TQuery : IQuery<TResponse> where TQuery : IQuery<TResponse>
where TResponse : notnull where TResponse : notnull
{ {
} }

View File

@ -34,4 +34,4 @@ public class CompositeEventMapper : IEventMapper
return null; return null;
} }
} }

View File

@ -6,4 +6,4 @@ public enum EventType
DomainEvent = 1, DomainEvent = 1,
IntegrationEvent = 2, IntegrationEvent = 2,
InternalCommand = 4 InternalCommand = 4
} }

View File

@ -2,4 +2,4 @@ namespace BuildingBlocks.Core.Event;
public interface IDomainEvent : IEvent public interface IDomainEvent : IEvent
{ {
} }

View File

@ -9,4 +9,4 @@ public interface IEvent : INotification
Guid EventId => NewId.NextGuid(); Guid EventId => NewId.NextGuid();
public DateTime OccurredOn => DateTime.Now; public DateTime OccurredOn => DateTime.Now;
public string EventType => GetType().AssemblyQualifiedName; public string EventType => GetType().AssemblyQualifiedName;
} }

View File

@ -2,4 +2,4 @@ namespace BuildingBlocks.Core.Event;
public interface IHaveIntegrationEvent public interface IHaveIntegrationEvent
{ {
} }

View File

@ -5,4 +5,4 @@ namespace BuildingBlocks.Core.Event;
[ExcludeFromTopology] [ExcludeFromTopology]
public interface IIntegrationEvent : IEvent public interface IIntegrationEvent : IEvent
{ {
} }

View File

@ -2,4 +2,4 @@ namespace BuildingBlocks.Core.Event;
public interface IInternalCommand : IEvent public interface IInternalCommand : IEvent
{ {
} }

View File

@ -2,4 +2,4 @@ using BuildingBlocks.Core.CQRS;
namespace BuildingBlocks.Core.Event; namespace BuildingBlocks.Core.Event;
public record InternalCommand : IInternalCommand, ICommand; public record InternalCommand : IInternalCommand, ICommand;

View File

@ -23,4 +23,4 @@ public class MessageEnvelope<TMessage> : MessageEnvelope
} }
public new TMessage? Message { get; } public new TMessage? Message { get; }
} }

View File

@ -152,4 +152,4 @@ public sealed class EventDispatcher(
return headers; return headers;
} }
} }

View File

@ -8,4 +8,4 @@ public interface IEventDispatcher
where T : IEvent; where T : IEvent;
public Task SendAsync<T>(T @event, Type type = null, CancellationToken cancellationToken = default) public Task SendAsync<T>(T @event, Type type = null, CancellationToken cancellationToken = default)
where T : IEvent; where T : IEvent;
} }

View File

@ -6,4 +6,4 @@ public interface IEventMapper
{ {
IIntegrationEvent? MapToIntegrationEvent(IDomainEvent @event); IIntegrationEvent? MapToIntegrationEvent(IDomainEvent @event);
IInternalCommand? MapToInternalCommand(IDomainEvent @event); IInternalCommand? MapToInternalCommand(IDomainEvent @event);
} }

View File

@ -3,4 +3,4 @@ using BuildingBlocks.Core.Event;
namespace BuildingBlocks.Core; namespace BuildingBlocks.Core;
public record IntegrationEventWrapper<TDomainEventType>(TDomainEventType DomainEvent) : IIntegrationEvent public record IntegrationEventWrapper<TDomainEventType>(TDomainEventType DomainEvent) : IIntegrationEvent
where TDomainEventType : IDomainEvent; where TDomainEventType : IDomainEvent;

View File

@ -20,4 +20,4 @@ public abstract record Aggregate<TId> : Entity<TId>, IAggregate<TId>
return dequeuedEvents; return dequeuedEvents;
} }
} }

View File

@ -9,4 +9,4 @@ public abstract record Entity<T> : IEntity<T>
public long? LastModifiedBy { get; set; } public long? LastModifiedBy { get; set; }
public bool IsDeleted { get; set; } public bool IsDeleted { get; set; }
public long Version { get; set; } public long Version { get; set; }
} }

View File

@ -10,4 +10,4 @@ public interface IAggregate : IEntity
{ {
IReadOnlyList<IDomainEvent> DomainEvents { get; } IReadOnlyList<IDomainEvent> DomainEvents { get; }
IEvent[] ClearDomainEvents(); IEvent[] ClearDomainEvents();
} }

View File

@ -12,4 +12,4 @@ public interface IEntity : IVersion
public DateTime? LastModified { get; set; } public DateTime? LastModified { get; set; }
public long? LastModifiedBy { get; set; } public long? LastModifiedBy { get; set; }
public bool IsDeleted { get; set; } public bool IsDeleted { get; set; }
} }

View File

@ -4,4 +4,4 @@ namespace BuildingBlocks.Core.Model;
public interface IVersion public interface IVersion
{ {
long Version { get; set; } long Version { get; set; }
} }

View File

@ -33,4 +33,4 @@ public static class Extensions
return PageList<TEntity>.Create(items.AsReadOnly(), pageRequest.PageNumber, pageRequest.PageSize, total); return PageList<TEntity>.Create(items.AsReadOnly(), pageRequest.PageNumber, pageRequest.PageSize, total);
} }
} }

View File

@ -13,4 +13,4 @@ public interface IPageList<T>
int TotalCount { get; init; } int TotalCount { get; init; }
int PageNumber { get; init; } int PageNumber { get; init; }
int PageSize { get; init; } int PageSize { get; init; }
} }

View File

@ -4,4 +4,4 @@ using MediatR;
public interface IPageQuery<out TResponse> : IPageRequest, IRequest<TResponse> public interface IPageQuery<out TResponse> : IPageRequest, IRequest<TResponse>
where TResponse : class where TResponse : class
{ } { }

View File

@ -6,4 +6,4 @@ public interface IPageRequest
int PageSize { get; init; } int PageSize { get; init; }
string? Filters { get; init; } string? Filters { get; init; }
string? SortOrder { get; init; } string? SortOrder { get; init; }
} }

View File

@ -16,4 +16,4 @@ public record PageList<T>(IReadOnlyList<T> Items, int PageNumber, int PageSize,
{ {
return new PageList<T>(items, pageNumber, pageSize, totalItems); return new PageList<T>(items, pageNumber, pageSize, totalItems);
} }
} }

View File

@ -178,4 +178,4 @@ public abstract class AppDbContextBase : DbContext, IDbContext
throw new System.Exception("try for find IAggregate", ex); throw new System.Exception("try for find IAggregate", ex);
} }
} }
} }

View File

@ -57,4 +57,4 @@ namespace BuildingBlocks.EFCore
return CreateNewInstance(options); return CreateNewInstance(options);
} }
} }
} }

View File

@ -78,4 +78,4 @@ where TResponse : notnull
return response; return response;
} }
} }
} }

View File

@ -138,4 +138,4 @@ public static class Extensions
await seedersManager.ExecuteSeedAsync(); await seedersManager.ExecuteSeedAsync();
} }
} }

View File

@ -9,4 +9,4 @@ namespace BuildingBlocks.EFCore
{ {
Task SeedAllAsync(); Task SeedAllAsync();
} }
} }

View File

@ -15,4 +15,4 @@ public interface IDbContext
Task RollbackTransactionAsync(CancellationToken cancellationToken = default); Task RollbackTransactionAsync(CancellationToken cancellationToken = default);
IExecutionStrategy CreateExecutionStrategy(); IExecutionStrategy CreateExecutionStrategy();
Task ExecuteTransactionalAsync(CancellationToken cancellationToken = default); Task ExecuteTransactionalAsync(CancellationToken cancellationToken = default);
} }

View File

@ -4,4 +4,4 @@ public interface ISeedManager
{ {
Task ExecuteSeedAsync(); Task ExecuteSeedAsync();
Task ExecuteTestSeedAsync(); Task ExecuteTestSeedAsync();
} }

View File

@ -3,4 +3,4 @@ namespace BuildingBlocks.EFCore;
public class PostgresOptions public class PostgresOptions
{ {
public string ConnectionString { get; set; } public string ConnectionString { get; set; }
} }

View File

@ -39,4 +39,4 @@ public class SeedManager(
logger.LogInformation("Seed {SeederName} is completed.", testSeeder.GetType().Name); logger.LogInformation("Seed {SeederName} is completed.", testSeeder.GetType().Name);
} }
} }
} }

View File

@ -25,4 +25,4 @@ public class BackgroundWorker : BackgroundService
await perform(stoppingToken); await perform(stoppingToken);
logger.LogInformation("Background worker stopped"); logger.LogInformation("Background worker stopped");
}, stoppingToken); }, stoppingToken);
} }

View File

@ -90,4 +90,4 @@ public static class EventStoreDBConfigExtensions
.AsImplementedInterfaces() .AsImplementedInterfaces()
.WithTransientLifetime()); .WithTransientLifetime());
} }
} }

View File

@ -24,5 +24,4 @@ namespace BuildingBlocks.EventStoreDB.Events
public virtual void When(object @event) { } public virtual void When(object @event) { }
} }
} }

View File

@ -36,4 +36,4 @@ public static class AggregateStreamExtensions
return aggregate; return aggregate;
} }
} }

View File

@ -40,4 +40,4 @@ public class EventTypeMapper
return type; return type;
}); });
} }

View File

@ -12,4 +12,4 @@ namespace BuildingBlocks.EventStoreDB.Events
public interface IAggregateEventSourcing<T> : IAggregateEventSourcing, IEntity<T> public interface IAggregateEventSourcing<T> : IAggregateEventSourcing, IEntity<T>
{ {
} }
} }

View File

@ -6,4 +6,4 @@ namespace BuildingBlocks.EventStoreDB.Events;
public interface IEventHandler<in TEvent> : INotificationHandler<TEvent> public interface IEventHandler<in TEvent> : INotificationHandler<TEvent>
where TEvent : IEvent where TEvent : IEvent
{ {
} }

View File

@ -4,4 +4,4 @@ namespace BuildingBlocks.EventStoreDB.Events;
public interface IExternalEvent : IEvent public interface IExternalEvent : IEvent
{ {
} }

View File

@ -3,4 +3,4 @@ namespace BuildingBlocks.EventStoreDB.Events;
public interface IProjection public interface IProjection
{ {
void When(object @event); void When(object @event);
} }

View File

@ -26,5 +26,4 @@ public class StreamEvent<T> : StreamEvent where T : notnull
public StreamEvent(T data, EventMetadata metadata) : base(data, metadata) public StreamEvent(T data, EventMetadata metadata) : base(data, metadata)
{ {
} }
} }

View File

@ -16,4 +16,4 @@ public static class StreamEventExtensions
var type = typeof(StreamEvent<>).MakeGenericType(eventData.GetType()); var type = typeof(StreamEvent<>).MakeGenericType(eventData.GetType());
return (StreamEvent)Activator.CreateInstance(type, eventData, metaData)!; return (StreamEvent)Activator.CreateInstance(type, eventData, metaData)!;
} }
} }

View File

@ -25,4 +25,4 @@ public class StreamNameMapper
return $"{tenantPrefix}{streamType.Name}-{aggregateId}"; return $"{tenantPrefix}{streamType.Name}-{aggregateId}";
} }
} }

View File

@ -23,4 +23,4 @@ public static class Extensions
.AddEventStoreDB(configuration) .AddEventStoreDB(configuration)
.AddProjections(assembliesToScan); .AddProjections(assembliesToScan);
} }
} }

View File

@ -7,4 +7,4 @@ public interface IProjectionProcessor
{ {
Task ProcessEventAsync<T>(StreamEvent<T> streamEvent, CancellationToken cancellationToken = default) Task ProcessEventAsync<T>(StreamEvent<T> streamEvent, CancellationToken cancellationToken = default)
where T : INotification; where T : INotification;
} }

View File

@ -9,4 +9,4 @@ public interface IProjectionPublisher
where T : INotification; where T : INotification;
Task PublishAsync(StreamEvent streamEvent, CancellationToken cancellationToken = default); Task PublishAsync(StreamEvent streamEvent, CancellationToken cancellationToken = default);
} }

View File

@ -36,4 +36,4 @@ public class ProjectionPublisher : IProjectionPublisher
return (Task)method return (Task)method
.Invoke(this, new object[] { streamEvent, cancellationToken })!; .Invoke(this, new object[] { streamEvent, cancellationToken })!;
} }
} }

View File

@ -71,4 +71,4 @@ public class EventStoreDBRepository<T> : IEventStoreDBRepository<T> where T : cl
return events return events
.Select(EventStoreDBSerializer.ToJsonEventData); .Select(EventStoreDBSerializer.ToJsonEventData);
} }
} }

View File

@ -30,4 +30,4 @@ public static class RepositoryExtensions
return await repository.Update(entity, expectedVersion, cancellationToken); return await repository.Update(entity, expectedVersion, cancellationToken);
} }
} }

View File

@ -36,4 +36,4 @@ public static class EventStoreDBSerializer
Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(@event)), Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(@event)),
Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(new { })) Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(new { }))
); );
} }

View File

@ -78,4 +78,4 @@ public static class JsonObjectContractProvider
.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) .GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
.OrderByDescending(e => e.GetParameters().Length) .OrderByDescending(e => e.GetParameters().Length)
.FirstOrDefault(); .FirstOrDefault();
} }

View File

@ -12,4 +12,4 @@ public class NonDefaultConstructorContractResolver : DefaultContractResolver
base.CreateConstructorParameters base.CreateConstructorParameters
); );
} }
} }

View File

@ -65,4 +65,4 @@ public static class SerializationExtensions
{ {
return new StringContent(obj.ToJson(), Encoding.UTF8, "application/json"); return new StringContent(obj.ToJson(), Encoding.UTF8, "application/json");
} }
} }

View File

@ -73,4 +73,4 @@ public class EventStoreDBSubscriptionCheckpointRepository : ISubscriptionCheckpo
} }
private static string GetCheckpointStreamName(string subscriptionId) => $"checkpoint_{subscriptionId}"; private static string GetCheckpointStreamName(string subscriptionId) => $"checkpoint_{subscriptionId}";
} }

View File

@ -188,4 +188,4 @@ public class EventStoreDBSubscriptionToAll
logger.LogInformation("Checkpoint event - ignoring"); logger.LogInformation("Checkpoint event - ignoring");
return true; return true;
} }
} }

View File

@ -5,4 +5,4 @@ public interface ISubscriptionCheckpointRepository
ValueTask<ulong?> Load(string subscriptionId, CancellationToken ct); ValueTask<ulong?> Load(string subscriptionId, CancellationToken ct);
ValueTask Store(string subscriptionId, ulong position, CancellationToken ct); ValueTask Store(string subscriptionId, ulong position, CancellationToken ct);
} }

View File

@ -17,4 +17,4 @@ public class InMemorySubscriptionCheckpointRepository : ISubscriptionCheckpointR
return ValueTask.CompletedTask; return ValueTask.CompletedTask;
} }
} }

View File

@ -10,4 +10,4 @@ public class AggregateNotFoundException : System.Exception
{ {
return new AggregateNotFoundException(typeof(T).Name, id); return new AggregateNotFoundException(typeof(T).Name, id);
} }
} }

View File

@ -11,4 +11,4 @@ public class AppException : CustomException
public AppException(string message, System.Exception innerException, HttpStatusCode statusCode = HttpStatusCode.BadRequest, int? code = null) : base(message, innerException, statusCode, code) public AppException(string message, System.Exception innerException, HttpStatusCode statusCode = HttpStatusCode.BadRequest, int? code = null) : base(message, innerException, statusCode, code)
{ {
} }
} }

View File

@ -10,4 +10,4 @@ namespace BuildingBlocks.Exception
} }
} }
} }

View File

@ -8,4 +8,4 @@ namespace BuildingBlocks.Exception
{ {
} }
} }
} }

View File

@ -34,4 +34,4 @@ public class CustomException : System.Exception
public HttpStatusCode StatusCode { get; } public HttpStatusCode StatusCode { get; }
public int? Code { get; } public int? Code { get; }
} }

View File

@ -13,4 +13,4 @@ namespace SmartCharging.Infrastructure.Exceptions
{ {
} }
} }
} }

View File

@ -20,4 +20,4 @@ public class GrpcExceptionInterceptor : Interceptor
throw new RpcException(new Status(StatusCode.Internal, exception.Message)); throw new RpcException(new Status(StatusCode.Internal, exception.Message));
} }
} }
} }

View File

@ -14,4 +14,4 @@ namespace BuildingBlocks.Exception
{ {
} }
} }
} }

View File

@ -8,4 +8,4 @@ namespace BuildingBlocks.Exception
{ {
} }
} }
} }

View File

@ -9,4 +9,4 @@ public class ProblemDetailsWithCode : ProblemDetails
{ {
[JsonPropertyName("code")] [JsonPropertyName("code")]
public int? Code { get; set; } public int? Code { get; set; }
} }

View File

@ -8,4 +8,4 @@ namespace BuildingBlocks.Exception
{ {
} }
} }
} }

View File

@ -87,4 +87,4 @@ public static class Extensions
return app; return app;
} }
} }

View File

@ -3,4 +3,4 @@ namespace BuildingBlocks.HealthCheck;
public class HealthOptions public class HealthOptions
{ {
public bool Enabled { get; set; } = true; public bool Enabled { get; set; } = true;
} }

View File

@ -21,4 +21,4 @@ public class AuthHeaderHandler : DelegatingHandler
return base.SendAsync(request, cancellationToken); return base.SendAsync(request, cancellationToken);
} }
} }

View File

@ -74,4 +74,4 @@ namespace BuildingBlocks.Jwt
return services; return services;
} }
} }
} }

View File

@ -37,4 +37,4 @@ public class LoggingBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest,
_logger.LogInformation("[{Prefix}] Handled {X-RequestData}", prefix, typeof(TRequest).Name); _logger.LogInformation("[{Prefix}] Handled {X-RequestData}", prefix, typeof(TRequest).Name);
return response; return response;
} }
} }

View File

@ -16,4 +16,4 @@ public static class Extensions
return services; return services;
} }
} }

View File

@ -35,4 +35,4 @@ public class ConsumeFilter<T> : IFilter<ConsumeContext<T>>
public void Probe(ProbeContext context) public void Probe(ProbeContext context)
{ {
} }
} }

View File

@ -117,4 +117,4 @@ public static class Extensions
.Ignore< .Ignore<
ValidationException>(); // don't retry if we have invalid data and message goes to _error queue masstransit ValidationException>(); // don't retry if we have invalid data and message goes to _error queue masstransit
} }
} }

View File

@ -7,4 +7,4 @@ public class RabbitMqOptions
public string UserName { get; set; } public string UserName { get; set; }
public string Password { get; set; } public string Password { get; set; }
public ushort? Port { get; set; } public ushort? Port { get; set; }
} }

View File

@ -4,4 +4,4 @@ public enum TransportType
{ {
RabbitMq, RabbitMq,
InMemory InMemory
} }

View File

@ -49,4 +49,4 @@ namespace BuildingBlocks.Mongo
return services; return services;
} }
} }
} }

View File

@ -10,4 +10,4 @@ public interface IMongoDbContext : IDisposable
Task CommitTransactionAsync(CancellationToken cancellationToken = default); Task CommitTransactionAsync(CancellationToken cancellationToken = default);
Task RollbackTransaction(CancellationToken cancellationToken = default); Task RollbackTransaction(CancellationToken cancellationToken = default);
void AddCommand(Func<Task> func); void AddCommand(Func<Task> func);
} }

View File

@ -5,4 +5,4 @@ namespace BuildingBlocks.Mongo;
public interface IMongoRepository<TEntity, in TId> : IRepository<TEntity, TId> public interface IMongoRepository<TEntity, in TId> : IRepository<TEntity, TId>
where TEntity : class, IAggregate<TId> where TEntity : class, IAggregate<TId>
{ {
} }

View File

@ -2,4 +2,4 @@ namespace BuildingBlocks.Mongo;
public interface IMongoUnitOfWork<out TContext> : IUnitOfWork<TContext> where TContext : class, IMongoDbContext public interface IMongoUnitOfWork<out TContext> : IUnitOfWork<TContext> where TContext : class, IMongoDbContext
{ {
} }

View File

@ -46,4 +46,4 @@ public interface IRepository<TEntity, in TId> :
public interface IRepository<TEntity> : IRepository<TEntity, long> public interface IRepository<TEntity> : IRepository<TEntity, long>
where TEntity : class, IAggregate<long> where TEntity : class, IAggregate<long>
{ {
} }

Some files were not shown because too many files have changed in this diff Show More