├── Docs
├── cb.JPG
├── cq.JPG
├── ec.JPG
├── ed.JPG
├── cap.JPG
└── highlevel.JPG
├── Src
├── InventoryMicroservice
│ ├── InventoryCore
│ │ ├── Class1.cs
│ │ └── InventoryCore.csproj
│ ├── InventoryDomainService
│ │ ├── Class1.cs
│ │ └── InventoryDomainService.csproj
│ ├── InventoryQueryHandler
│ │ ├── Class1.cs
│ │ └── InventoryQueryHandler.csproj
│ ├── InventoryInfrastructure
│ │ ├── Class1.cs
│ │ └── InventoryInfrastructure.csproj
│ ├── Inventory.Event
│ │ └── Inventory.Event
│ │ │ ├── PurchaseEvent.cs
│ │ │ └── Inventory.Event.csproj
│ ├── InventoryQuery
│ │ ├── StoreQuery.cs
│ │ └── Inventory.Query.csproj
│ ├── InventoryDto
│ │ ├── Inventory.DTO.csproj
│ │ ├── StoreQueryResultDTO.cs
│ │ └── StoreDTO.cs
│ ├── InventoryWebApi
│ │ ├── appsettings.Development.json
│ │ ├── appsettings.json
│ │ ├── Constants.cs
│ │ ├── Properties
│ │ │ └── launchSettings.json
│ │ ├── Program.cs
│ │ ├── Controllers
│ │ │ ├── StoreQueryController.cs
│ │ │ └── StoreCommandController.cs
│ │ ├── Inventory.Api.csproj
│ │ └── Startup.cs
│ ├── Inventory.Api.Grpc
│ │ ├── appsettings.Development.json
│ │ ├── appsettings.json
│ │ ├── Protos
│ │ │ └── InventoryService.proto
│ │ ├── Properties
│ │ │ └── launchSettings.json
│ │ ├── Services
│ │ │ └── GreeterService.cs
│ │ ├── Inventory.Api.Grpc.csproj
│ │ ├── Dockerfile
│ │ ├── Program.cs
│ │ └── Startup.cs
│ ├── Inventory.Api.Tests
│ │ ├── Properties
│ │ │ └── launchSettings.json
│ │ ├── Inventory.Api.Tests.csproj
│ │ ├── TestClientProvider.cs
│ │ ├── StoredCommandControllerTest.cs
│ │ └── StoreQueryControllerTest.cs
│ ├── InventoryCommand
│ │ ├── CreateStoreCommand.cs
│ │ └── Inventory.Command.csproj
│ ├── InventoryDomain
│ │ ├── Store.cs
│ │ ├── Inventory.Domain.csproj
│ │ └── StoreItem.cs
│ ├── Inventory.Api.Grpc.Tests
│ │ ├── Protos
│ │ │ └── InventoryService.proto
│ │ ├── InventoryServiceTest.cs
│ │ └── Inventory.Api.Grpc.Tests.csproj
│ ├── InventoryRepository
│ │ ├── IStoreRepository.cs
│ │ ├── IStoreItemRepository.cs
│ │ ├── Inventory.Repository.csproj
│ │ ├── StoreRepository.cs
│ │ └── StoreItemRepository.cs
│ ├── Inventory.EventHandler
│ │ └── Inventory.EventHandler
│ │ │ ├── Inventory.EventHandler.csproj
│ │ │ ├── ProductSoldEventHandler.cs
│ │ │ └── ProductPurchasedEventHandler.cs
│ ├── InventoryCommandHandler
│ │ ├── Inventory.CommandHandler.csproj
│ │ └── CreateStoreCommandHandler.cs
│ └── Inventory.QueryHandler
│ │ ├── Inventory.QueryHandler.csproj
│ │ └── StoreQueryHandler.cs
├── SalesMicroservice
│ ├── SalesDomainService
│ │ ├── Class1.cs
│ │ └── SalesDomainService.csproj
│ ├── SalesInfrastructure
│ │ ├── Class1.cs
│ │ └── SalesInfrastructure.csproj
│ ├── SalesDto
│ │ ├── Sales.DTO.csproj
│ │ ├── ProductSalesDTO.cs
│ │ └── SalesDTO.cs
│ ├── SalesCore
│ │ ├── Sales.Core.csproj
│ │ └── Constants.cs
│ ├── SalesWebApi
│ │ ├── appsettings.Development.json
│ │ ├── appsettings.json
│ │ ├── Program.cs
│ │ ├── Dockerfile
│ │ ├── Properties
│ │ │ └── launchSettings.json
│ │ ├── Controllers
│ │ │ ├── SalesQueryController.cs
│ │ │ └── SalesCommandController.cs
│ │ ├── Sales.Api.csproj
│ │ └── Startup.cs
│ ├── SalesQuery
│ │ ├── Sales.Query.csproj
│ │ └── SalesQuery.cs
│ ├── SalesCommand
│ │ ├── Sales.Command.csproj
│ │ └── SalesCommand.cs
│ ├── SalesDomain
│ │ ├── Sales.Domain.csproj
│ │ ├── Sales.cs
│ │ └── SalesLineItem.cs
│ ├── SalesRepository
│ │ ├── ISalesRepository.cs
│ │ ├── Sales.Repository.csproj
│ │ └── SalesRepository.cs
│ ├── SalesQueryHandler
│ │ ├── Sales.QueryHandler.csproj
│ │ └── SalesQueryHandler.cs
│ ├── SalesCommandHandler
│ │ ├── Sales.CommandHandler.csproj
│ │ └── SalesCommandHandler.cs
│ └── Sales.Repository.Tests
│ │ ├── Sales.Repository.Tests.csproj
│ │ └── SalesRepositoryTest.cs
├── PurchaseMicroservice
│ ├── PurchaseDto
│ │ ├── Purchase.DTO.csproj
│ │ ├── PurchaseItemDTO.cs
│ │ ├── ProductPurchasedDTO.cs
│ │ ├── PurchaseQueryDTO.cs
│ │ └── PurchaseDTO.cs
│ ├── PurchaseDomain
│ │ ├── Models
│ │ │ ├── User.cs
│ │ │ ├── Product.cs
│ │ │ ├── Purchase.cs
│ │ │ └── ProductLineItem.cs
│ │ └── Purchase.Domain.csproj
│ ├── PurchaseWebApi
│ │ ├── appsettings.Development.json
│ │ ├── appsettings.json
│ │ ├── Properties
│ │ │ └── launchSettings.json
│ │ ├── Program.cs
│ │ ├── Purchase.Api.csproj
│ │ ├── Controllers
│ │ │ ├── PurchaseQueryController.cs
│ │ │ └── PurchaseCommandController.cs
│ │ └── Startup.cs
│ ├── PurchaseInfrastructure
│ │ ├── IServiceBus.cs
│ │ ├── Purchase.Infrastructure.csproj
│ │ └── RabbitMqBus.cs
│ ├── PurchaseCore
│ │ ├── Purchase.Core.csproj
│ │ ├── BusinessException.cs
│ │ └── Constants.cs
│ ├── PurchaseQuery
│ │ ├── Purchase.Query.csproj
│ │ └── ProductPurchasedQuery.cs
│ ├── PurchaseCommandHandler
│ │ ├── Protos
│ │ │ └── InventoryService.proto
│ │ ├── Purchase.CommandHandler.csproj
│ │ └── PurchaseCommandHandler.cs
│ ├── PurchaseCommand
│ │ ├── LineItemCommand.cs
│ │ ├── Purchase.Command.csproj
│ │ └── PurchaseCommand.cs
│ ├── PurchaseRepository
│ │ ├── IPurchaseRepostiory.cs
│ │ ├── Purchase.Repository.csproj
│ │ └── PurchaseRepository.cs
│ └── Purchase.QueryHandler
│ │ ├── Purchase.QueryHandler.csproj
│ │ └── ProductPurchaseQueryHandler.cs
├── CommonAll
│ ├── Common.Core
│ │ ├── IEvent.cs
│ │ ├── IQuery.cs
│ │ ├── ICommand.cs
│ │ ├── IAggregate.cs
│ │ ├── Aggregate.cs
│ │ ├── IEmailService.cs
│ │ ├── IQueryHandler.cs
│ │ ├── IEventHandler.cs
│ │ ├── ICommandBus.cs
│ │ ├── ICommandHandler.cs
│ │ ├── IRepository.cs
│ │ ├── ISerializer.cs
│ │ ├── Common.Core.csproj
│ │ ├── QueryResult.cs
│ │ ├── IEventBus.cs
│ │ ├── IQueryBus.cs
│ │ ├── CommandResult.cs
│ │ ├── EmailSettings.cs
│ │ ├── EmailParams.cs
│ │ ├── Entity.cs
│ │ ├── JsonSerializer.cs
│ │ ├── IMongoService.cs
│ │ └── Events
│ │ │ ├── ProductPurchasedEvent.cs
│ │ │ └── ProductSoldEvent.cs
│ ├── Common.Core.Tests
│ │ ├── UnitTest1.cs
│ │ └── Common.Core.Tests.csproj
│ ├── Common.Infrastructure
│ │ ├── MessageBrokerSettings.cs
│ │ ├── Common.Infrastructure.csproj
│ │ ├── QueryBus.cs
│ │ ├── CommandBus.cs
│ │ ├── EmailService.cs
│ │ ├── MongoService.cs
│ │ └── EventBus.cs
│ └── Common.Infrastructure.Tests
│ │ ├── Common.Infrastructure.Tests.csproj
│ │ └── RabbitMqServiceBusTest.cs
├── .dockerignore
└── TheMicroservices.sln
├── LICENSE
├── .gitignore
└── README.md
/Docs/cb.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/habibsql/TheMicroServices/HEAD/Docs/cb.JPG
--------------------------------------------------------------------------------
/Docs/cq.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/habibsql/TheMicroServices/HEAD/Docs/cq.JPG
--------------------------------------------------------------------------------
/Docs/ec.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/habibsql/TheMicroServices/HEAD/Docs/ec.JPG
--------------------------------------------------------------------------------
/Docs/ed.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/habibsql/TheMicroServices/HEAD/Docs/ed.JPG
--------------------------------------------------------------------------------
/Docs/cap.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/habibsql/TheMicroServices/HEAD/Docs/cap.JPG
--------------------------------------------------------------------------------
/Docs/highlevel.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/habibsql/TheMicroServices/HEAD/Docs/highlevel.JPG
--------------------------------------------------------------------------------
/Src/InventoryMicroservice/InventoryCore/Class1.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace InventoryCore
4 | {
5 | public class Class1
6 | {
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/Src/SalesMicroservice/SalesDomainService/Class1.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace SalesDomainService
4 | {
5 | public class Class1
6 | {
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/Src/SalesMicroservice/SalesInfrastructure/Class1.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace SalesInfrastructure
4 | {
5 | public class Class1
6 | {
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/Src/InventoryMicroservice/InventoryDomainService/Class1.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace InventoryDomainService
4 | {
5 | public class Class1
6 | {
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/Src/InventoryMicroservice/InventoryQueryHandler/Class1.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace InventoryQueryHandler
4 | {
5 | public class Class1
6 | {
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/Src/InventoryMicroservice/InventoryInfrastructure/Class1.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace InventoryInfrastructure
4 | {
5 | public class Class1
6 | {
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/Src/InventoryMicroservice/Inventory.Event/Inventory.Event/PurchaseEvent.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Inventory.Event
4 | {
5 | public class PurchaseEvent
6 | {
7 |
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/Src/SalesMicroservice/SalesDto/Sales.DTO.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.1
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Src/SalesMicroservice/SalesCore/Sales.Core.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.1
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Src/InventoryMicroservice/InventoryQuery/StoreQuery.cs:
--------------------------------------------------------------------------------
1 | namespace Inventory.Query
2 | {
3 | using Common.Core;
4 | using System;
5 |
6 | public class StoreQuery : IQuery
7 | {
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/Src/PurchaseMicroservice/PurchaseDto/Purchase.DTO.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.1
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Src/InventoryMicroservice/InventoryCore/InventoryCore.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.1
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Src/InventoryMicroservice/InventoryDto/Inventory.DTO.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.1
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Src/CommonAll/Common.Core/IEvent.cs:
--------------------------------------------------------------------------------
1 | namespace Common.Core
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Text;
6 |
7 | public interface IEvent
8 | {
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/Src/CommonAll/Common.Core/IQuery.cs:
--------------------------------------------------------------------------------
1 | namespace Common.Core
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Text;
6 |
7 | public interface IQuery
8 | {
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/Src/SalesMicroservice/SalesDomainService/SalesDomainService.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.1
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Src/CommonAll/Common.Core/ICommand.cs:
--------------------------------------------------------------------------------
1 | namespace Common.Core
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Text;
6 |
7 | public interface ICommand
8 | {
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/Src/SalesMicroservice/SalesInfrastructure/SalesInfrastructure.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.1
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Src/CommonAll/Common.Core/IAggregate.cs:
--------------------------------------------------------------------------------
1 | namespace Common.Core
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Text;
6 |
7 | public interface IAggregate
8 | {
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/Src/InventoryMicroservice/InventoryQueryHandler/InventoryQueryHandler.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.1
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Src/InventoryMicroservice/Inventory.Event/Inventory.Event/Inventory.Event.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.0
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Src/InventoryMicroservice/InventoryDomainService/InventoryDomainService.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.1
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Src/InventoryMicroservice/InventoryInfrastructure/InventoryInfrastructure.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.1
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Src/PurchaseMicroservice/PurchaseDomain/Models/User.cs:
--------------------------------------------------------------------------------
1 | namespace Purchase.Domain.Model
2 | {
3 | using Common.Core;
4 |
5 | public class User : Aggregate
6 | {
7 | public string Name { get; set; }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/Src/InventoryMicroservice/InventoryDto/StoreQueryResultDTO.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace Inventory.DTO
6 | {
7 | class StoreQueryResultDTO
8 | {
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/Src/CommonAll/Common.Core/Aggregate.cs:
--------------------------------------------------------------------------------
1 | namespace Common.Core
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Text;
6 |
7 | public abstract class Aggregate : Entity, IAggregate
8 | {
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/Src/SalesMicroservice/SalesWebApi/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft": "Warning",
6 | "Microsoft.Hosting.Lifetime": "Information"
7 | }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/Src/PurchaseMicroservice/PurchaseWebApi/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft": "Warning",
6 | "Microsoft.Hosting.Lifetime": "Information"
7 | }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/Src/CommonAll/Common.Core.Tests/UnitTest1.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Xunit;
3 |
4 | namespace Common.Core.Tests
5 | {
6 | public class UnitTest1
7 | {
8 | [Fact]
9 | public void Test1()
10 | {
11 |
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Src/InventoryMicroservice/InventoryWebApi/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft": "Warning",
6 | "Microsoft.Hosting.Lifetime": "Information"
7 | }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/Src/InventoryMicroservice/Inventory.Api.Grpc/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Debug",
5 | "System": "Information",
6 | "Grpc": "Information",
7 | "Microsoft": "Information"
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/Src/InventoryMicroservice/Inventory.Api.Tests/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "profiles": {
3 | "Inventory.Api.Tests": {
4 | "commandName": "Project",
5 | "environmentVariables": {
6 | "ASPNETCORE_ENVIRONMENT": "Development"
7 | }
8 | }
9 | }
10 | }
--------------------------------------------------------------------------------
/Src/SalesMicroservice/SalesCore/Constants.cs:
--------------------------------------------------------------------------------
1 | namespace Sales.Core
2 | {
3 | using System;
4 |
5 | public class Constants
6 | {
7 | public class MessageQueue
8 | {
9 | public const string SalesQueue = "product-sales";
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Src/InventoryMicroservice/InventoryCommand/CreateStoreCommand.cs:
--------------------------------------------------------------------------------
1 | namespace Inventory.Command
2 | {
3 | using Common.Core;
4 |
5 | public class CreateStoreCommand : ICommand
6 | {
7 | public string StoreId { get; set; }
8 |
9 | public string ManagerName { get; set; }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Src/PurchaseMicroservice/PurchaseInfrastructure/IServiceBus.cs:
--------------------------------------------------------------------------------
1 | namespace Purchase.Infrastructure
2 | {
3 | using Common.All;
4 | using System;
5 | using System.Threading.Tasks;
6 |
7 | public interface IServiceBus
8 | {
9 | Task Publish(string message, string queue);
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Src/InventoryMicroservice/InventoryDomain/Store.cs:
--------------------------------------------------------------------------------
1 | namespace Inventory.Domain
2 | {
3 | using Common.Core;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Text;
7 |
8 | public class Store : Aggregate
9 | {
10 | public string Manager { get; set; }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Src/CommonAll/Common.Core/IEmailService.cs:
--------------------------------------------------------------------------------
1 | namespace Common.Core
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | public interface IEmailService
9 | {
10 | Task SendEmail(EmailParams emailParams);
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Src/CommonAll/Common.Core/IQueryHandler.cs:
--------------------------------------------------------------------------------
1 | namespace Common.Core
2 | {
3 | using System.Threading.Tasks;
4 |
5 | public interface IQueryHandler
6 | where TQuery : IQuery
7 | where TResult : QueryResult
8 | {
9 | public Task Handle(TQuery query);
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Src/PurchaseMicroservice/PurchaseCore/Purchase.Core.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.1
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/Src/InventoryMicroservice/InventoryDto/StoreDTO.cs:
--------------------------------------------------------------------------------
1 | namespace Inventory.DTO
2 | {
3 | using System;
4 |
5 | public class StoreDTO
6 | {
7 | public string StoreId { get; set; }
8 |
9 | public string ManagerName { get; set; }
10 |
11 | public DateTime CreatedDate { get; set; }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/Src/SalesMicroservice/SalesQuery/Sales.Query.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.1
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/Src/PurchaseMicroservice/PurchaseDomain/Models/Product.cs:
--------------------------------------------------------------------------------
1 | namespace Purchase.Domain.Model
2 | {
3 | using System;
4 | using Common.Core;
5 |
6 | ///
7 | /// Product Entity
8 | ///
9 | public class Product : Aggregate
10 | {
11 | public string ProductName { get; set; }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/Src/SalesMicroservice/SalesCommand/Sales.Command.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.1
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/Src/SalesMicroservice/SalesDomain/Sales.Domain.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.1
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/Src/PurchaseMicroservice/PurchaseQuery/Purchase.Query.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.1
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/Src/InventoryMicroservice/InventoryCommand/Inventory.Command.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.1
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/Src/InventoryMicroservice/InventoryDomain/Inventory.Domain.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.1
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/Src/CommonAll/Common.Core/IEventHandler.cs:
--------------------------------------------------------------------------------
1 | namespace Common.Core
2 | {
3 | using Common.Core.Events;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | public interface IEventHandler where T : IEvent
10 | {
11 | Task Handle(T @event);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/Src/SalesMicroservice/SalesQuery/SalesQuery.cs:
--------------------------------------------------------------------------------
1 | namespace Sales.Query
2 | {
3 | using Common.Core;
4 | using System;
5 |
6 | public class SalesQuery : IQuery
7 | {
8 | public string ProductId { get; set; }
9 |
10 | public DateTime DateFrom { get; set; }
11 |
12 | public DateTime DateTo { get; set; }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Src/SalesMicroservice/SalesWebApi/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft": "Warning",
6 | "Microsoft.Hosting.Lifetime": "Information"
7 | }
8 | },
9 | "AllowedHosts": "*",
10 | "ConnectionStrings": {
11 | "Default": "mongodb://localhost:27017/SalesDB"
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/Src/CommonAll/Common.Core/ICommandBus.cs:
--------------------------------------------------------------------------------
1 | namespace Common.Core
2 | {
3 | using System.Threading.Tasks;
4 |
5 | public interface ICommandBus
6 | {
7 | Task Send(TCommand command) where TCommand : ICommand
8 | where TResult : CommandResult;
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/Src/CommonAll/Common.Core/ICommandHandler.cs:
--------------------------------------------------------------------------------
1 | namespace Common.Core
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | public interface ICommandHandler
9 | {
10 | public Task Handle(ICommand command);
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Src/CommonAll/Common.Core/IRepository.cs:
--------------------------------------------------------------------------------
1 | namespace Common.Core
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | public interface IRepository where T: IAggregate
9 | {
10 | Task Save(T entity);
11 |
12 | Task GetById(string id);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Src/InventoryMicroservice/InventoryDomain/StoreItem.cs:
--------------------------------------------------------------------------------
1 | namespace Inventory.Domain
2 | {
3 | using Common.Core;
4 | using System;
5 |
6 | public class StoreItem : Aggregate
7 | {
8 | public string ItemName { get; set; }
9 |
10 | public Store Store { get; set; }
11 |
12 | public long BalanceQuantity { get; set; }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Src/InventoryMicroservice/InventoryWebApi/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft": "Warning",
6 | "Microsoft.Hosting.Lifetime": "Information"
7 | }
8 | },
9 | "ConnectionStrings": {
10 | "Default": "mongodb://localhost:27017/InvetoryDB"
11 | },
12 | "AllowedHosts": "*"
13 | }
14 |
--------------------------------------------------------------------------------
/Src/CommonAll/Common.Core/ISerializer.cs:
--------------------------------------------------------------------------------
1 | namespace Common.Core
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | public interface ISerializer
9 | {
10 | Task Serialize(T t);
11 |
12 | Task Decerialize(string data);
13 |
14 |
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Src/InventoryMicroservice/Inventory.Api.Grpc/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft": "Warning",
6 | "Microsoft.Hosting.Lifetime": "Information"
7 | }
8 | },
9 | "AllowedHosts": "*",
10 | "Kestrel": {
11 | "EndpointDefaults": {
12 | "Protocols": "Http2"
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Src/CommonAll/Common.Core/Common.Core.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.1
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/Src/CommonAll/Common.Core/QueryResult.cs:
--------------------------------------------------------------------------------
1 | namespace Common.Core
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Text;
6 |
7 | public class QueryResult
8 | {
9 | public string Error { get; set; }
10 | public object Result { get; set; }
11 |
12 | public bool Succeed => string.IsNullOrEmpty(Error);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Src/SalesMicroservice/SalesDto/ProductSalesDTO.cs:
--------------------------------------------------------------------------------
1 | namespace Sales.DTO
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Text;
6 |
7 | public class ProductSalesDTO
8 | {
9 | public string ProductId { get; set; }
10 |
11 | public string ProductName { get; set; }
12 |
13 | public long SalesQuantity { get; set; }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Src/CommonAll/Common.Core/IEventBus.cs:
--------------------------------------------------------------------------------
1 | namespace Common.Core
2 | {
3 | using Common.Core.Events;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Threading.Tasks;
7 |
8 | public interface IEventBus
9 | {
10 | Task Publish(string queue, T @event) where T : IEvent;
11 |
12 | Task Subscribe(string queue) where T : IEvent;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Src/PurchaseMicroservice/PurchaseDto/PurchaseItemDTO.cs:
--------------------------------------------------------------------------------
1 | namespace Purchase.DTO
2 | {
3 | public class PurchaseItemDTO
4 | {
5 | public string ProductId { get; set; }
6 |
7 | public string ProductName { get; set; }
8 |
9 | public long UnitPrice { get; set; }
10 |
11 | public string UnitName { get; set; }
12 |
13 | public long Quantity { get; set; }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Src/InventoryMicroservice/Inventory.Api.Grpc/Protos/InventoryService.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | option csharp_namespace = "Inventory.Api.Grpc";
4 |
5 | package greet;
6 |
7 | service InventoryServiceProvider {
8 | rpc CountTotalItems (ServiceRequest) returns (ServiceReplay);
9 | }
10 |
11 | message ServiceRequest {
12 | string storeId = 1;
13 | }
14 |
15 | message ServiceReplay {
16 | string itemCount = 1;
17 | }
18 |
--------------------------------------------------------------------------------
/Src/InventoryMicroservice/Inventory.Api.Grpc.Tests/Protos/InventoryService.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | option csharp_namespace = "Inventory.Api.Grpc";
4 |
5 | package greet;
6 |
7 | service InventoryServiceProvider {
8 | rpc CountTotalItems (ServiceRequest) returns (ServiceReplay);
9 | }
10 |
11 | message ServiceRequest {
12 | string storeId = 1;
13 | }
14 |
15 | message ServiceReplay {
16 | string itemCount = 1;
17 | }
18 |
--------------------------------------------------------------------------------
/Src/PurchaseMicroservice/PurchaseCommandHandler/Protos/InventoryService.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | option csharp_namespace = "Inventory.Api.Grpc";
4 |
5 | package greet;
6 |
7 | service InventoryServiceProvider {
8 | rpc CountTotalItems (ServiceRequest) returns (ServiceReplay);
9 | }
10 |
11 | message ServiceRequest {
12 | string storeId = 1;
13 | }
14 |
15 | message ServiceReplay {
16 | string itemCount = 1;
17 | }
18 |
--------------------------------------------------------------------------------
/Src/.dockerignore:
--------------------------------------------------------------------------------
1 | **/.classpath
2 | **/.dockerignore
3 | **/.env
4 | **/.git
5 | **/.gitignore
6 | **/.project
7 | **/.settings
8 | **/.toolstarget
9 | **/.vs
10 | **/.vscode
11 | **/*.*proj.user
12 | **/*.dbmdl
13 | **/*.jfm
14 | **/azds.yaml
15 | **/bin
16 | **/charts
17 | **/docker-compose*
18 | **/Dockerfile*
19 | **/node_modules
20 | **/npm-debug.log
21 | **/obj
22 | **/secrets.dev.yaml
23 | **/values.dev.yaml
24 | LICENSE
25 | README.md
--------------------------------------------------------------------------------
/Src/InventoryMicroservice/InventoryRepository/IStoreRepository.cs:
--------------------------------------------------------------------------------
1 | namespace Inventory.Repository
2 | {
3 | using Common.Core;
4 | using Inventory.Domain;
5 | using System;
6 | using System.Collections.Generic;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 |
10 | public interface IStoreRepository : IRepository
11 | {
12 | public Task> GetAll();
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Src/CommonAll/Common.Core/IQueryBus.cs:
--------------------------------------------------------------------------------
1 | namespace Common.Core
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | public interface IQueryBus
9 | {
10 | Task Send(TQuery query) where TQuery : IQuery
11 | where TResult : QueryResult;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/Src/CommonAll/Common.Infrastructure/MessageBrokerSettings.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace Common.Infrastructure
6 | {
7 | public class MessageBrokerSettings
8 | {
9 | public string Host { get; set; }
10 | public int Port { get; set; }
11 |
12 | public string UserId { get; set; }
13 |
14 | public string Password { get; set; }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Src/PurchaseMicroservice/PurchaseCore/BusinessException.cs:
--------------------------------------------------------------------------------
1 | namespace Purchase.Core
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Text;
6 |
7 | public class BusinessException : Exception
8 | {
9 | public BusinessException():base()
10 | {
11 | }
12 | public BusinessException(string message) : base(message)
13 | {
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Src/InventoryMicroservice/InventoryQuery/Inventory.Query.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.1
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/Src/PurchaseMicroservice/PurchaseDto/ProductPurchasedDTO.cs:
--------------------------------------------------------------------------------
1 | namespace Purchase.DTO
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Text;
6 |
7 | public class ProductPurchasedDTO
8 | {
9 | public DateTime Date { get; set; }
10 |
11 | public string ProductName { get; set; }
12 |
13 | public long PurchasedQuantity { get; set; }
14 |
15 | public long PurchasedAmount { get; set; }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Src/InventoryMicroservice/InventoryWebApi/Constants.cs:
--------------------------------------------------------------------------------
1 | namespace Inventory.Api
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Threading.Tasks;
7 |
8 | public class Constants
9 | {
10 | public class MessageQueue
11 | {
12 | public const string PurchaseQueue = "product-purchased";
13 | public const string SalesQueue = "product-sales";
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Src/PurchaseMicroservice/PurchaseCommand/LineItemCommand.cs:
--------------------------------------------------------------------------------
1 | namespace Purchase.Command
2 | {
3 | using Common.Core;
4 |
5 | public class LineItemCommand : ICommand
6 | {
7 | public string ProductId { get; set; }
8 |
9 | public string ProductName { get; set; }
10 |
11 | public string PurchaseUnitName { get; set; }
12 |
13 | public long PurchaseUnitPrice { get; set; }
14 |
15 | public long PurchaseQuantity { get; set; }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Src/InventoryMicroservice/Inventory.Api.Grpc/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "profiles": {
3 | "Inventory.Api.Grpc": {
4 | "commandName": "Project",
5 | "environmentVariables": {
6 | "ASPNETCORE_ENVIRONMENT": "Development"
7 | },
8 | "applicationUrl": "https://localhost:7001"
9 | },
10 | "Docker": {
11 | "commandName": "Docker",
12 | "launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}",
13 | "publishAllPorts": true
14 | }
15 | }
16 | }
--------------------------------------------------------------------------------
/Src/SalesMicroservice/SalesRepository/ISalesRepository.cs:
--------------------------------------------------------------------------------
1 | namespace Sales.Repository
2 | {
3 | using Common.Core;
4 | using Sales.DTO;
5 | using System;
6 | using System.Collections.Generic;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 | using Sales = Domain.Sales;
10 |
11 | public interface ISalesRepository : IRepository
12 | {
13 | Task FindSoldProductInfo(string productId, DateTime dateFrom, DateTime dateTo);
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Src/InventoryMicroservice/InventoryRepository/IStoreItemRepository.cs:
--------------------------------------------------------------------------------
1 | namespace Inventory.Repository
2 | {
3 | using Common.Core;
4 | using Inventory.Domain;
5 | using System.Collections.Generic;
6 | using System.Threading.Tasks;
7 |
8 | public interface IStoreItemRepository : IRepository
9 | {
10 | Task SaveItems(IEnumerable entities);
11 |
12 | Task UpdateItem(StoreItem entity);
13 |
14 | Task RemoveItem(string id);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Src/SalesMicroservice/SalesDomain/Sales.cs:
--------------------------------------------------------------------------------
1 | namespace Sales.Domain
2 | {
3 | using Common.Core;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Text;
7 |
8 | public class Sales : Aggregate
9 | {
10 | public DateTime SalesDate { get; set; }
11 |
12 | public IList SalesLineItems { get; set; }
13 |
14 | public Sales()
15 | {
16 | this.SalesLineItems = new List();
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/Src/PurchaseMicroservice/PurchaseWebApi/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft": "Warning",
6 | "Microsoft.Hosting.Lifetime": "Information"
7 | }
8 | },
9 | "AllowedHosts": "*",
10 |
11 | "EmailSettings": {
12 | "Host": "127.0.0.1",
13 | "Port": 27,
14 | "UserId": "a@gmail.com",
15 | "Password": "****"
16 | },
17 | "ConnectionStrings": {
18 | "Default": "mongodb://localhost:27017/PurchaseDB"
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Src/CommonAll/Common.Core/CommandResult.cs:
--------------------------------------------------------------------------------
1 | namespace Common.Core
2 | {
3 | using System;
4 |
5 | public class CommandResult
6 | {
7 | public string Error { get; set; }
8 |
9 | public CommandResult()
10 | {
11 | }
12 |
13 | public CommandResult(string errorData)
14 | {
15 | this.Error = errorData;
16 | }
17 |
18 | public bool Succeed
19 | {
20 | get { return String.IsNullOrEmpty(Error); }
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Src/PurchaseMicroservice/PurchaseCommand/Purchase.Command.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.1
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/Src/PurchaseMicroservice/PurchaseCore/Constants.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace Purchase.Core
6 | {
7 | public class Constants
8 | {
9 | public class MessageQueues
10 | {
11 | public const string PurchasedQueue = "product-purchased";
12 | }
13 |
14 | public class EmailAddressess
15 | {
16 | public const string AdminPurchaseEmailAddress = "admin-purchase@gmail.com";
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/Src/CommonAll/Common.Core/EmailSettings.cs:
--------------------------------------------------------------------------------
1 | namespace Common.Core
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Text;
6 |
7 | public class EmailSettings
8 | {
9 | public string Host { get; set; }
10 |
11 | public int Port { get; set; }
12 |
13 | public string UserId { get; set; }
14 |
15 | public string Password { get; set; }
16 |
17 | public bool Ssl { get; set; }
18 |
19 | public string FromAddress { get; set; }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Src/PurchaseMicroservice/PurchaseInfrastructure/Purchase.Infrastructure.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.1
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/Src/InventoryMicroservice/InventoryRepository/Inventory.Repository.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.1
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/Src/PurchaseMicroservice/PurchaseCommand/PurchaseCommand.cs:
--------------------------------------------------------------------------------
1 | namespace Purchase.Command
2 | {
3 | using Common.Core;
4 | using System;
5 | using System.Collections.Generic;
6 |
7 | public class PurchaseCommand : ICommand
8 | {
9 | public string PurchaseId { get; set; }
10 |
11 | public DateTime PurchaseDate { get; set; }
12 |
13 | public string UserId { get; set; }
14 |
15 | public string UserName { get; set; }
16 |
17 | public IList LineItems { get; set; }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/Src/PurchaseMicroservice/PurchaseRepository/IPurchaseRepostiory.cs:
--------------------------------------------------------------------------------
1 | namespace Purchase.Repository
2 | {
3 | using Common.Core;
4 | using Purchase.Domain.Model;
5 | using Purchase.DTO;
6 | using System;
7 | using System.Collections.Generic;
8 | using System.Threading.Tasks;
9 |
10 | public interface IPurchaseRepostiory : IRepository
11 | {
12 | public Task> SearchPurchases(DateTime from, DateTime to, int pageNumber, int pageSize, string sort, int sortDirection);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Src/PurchaseMicroservice/PurchaseDomain/Purchase.Domain.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.1
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/Src/CommonAll/Common.Infrastructure/Common.Infrastructure.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.1
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/Src/SalesMicroservice/SalesRepository/Sales.Repository.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.1
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/Src/CommonAll/Common.Core/EmailParams.cs:
--------------------------------------------------------------------------------
1 | namespace Common.Core
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Text;
6 |
7 | public class EmailParams
8 | {
9 | public List ToList { get; set; }
10 |
11 | public List CcList { get; set; }
12 |
13 | public string Subject { get; set; }
14 |
15 | public string Body { get; set; }
16 |
17 | public EmailParams()
18 | {
19 | ToList = new List();
20 | CcList = new List();
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Src/PurchaseMicroservice/PurchaseDomain/Models/Purchase.cs:
--------------------------------------------------------------------------------
1 | namespace Purchase.Domain.Model
2 | {
3 | using Common.Core;
4 | using System;
5 | using System.Collections.Generic;
6 |
7 | ///
8 | /// Product Purchase Entity
9 | ///
10 | public class Purchase : Aggregate
11 | {
12 | public DateTime PurchaseDate { get; set; }
13 |
14 | public User User { get; set; }
15 |
16 | public IList LineItems { get; set; }
17 |
18 | public Purchase()
19 | {
20 | LineItems = new List();
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Src/PurchaseMicroservice/PurchaseRepository/Purchase.Repository.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.1
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/Src/PurchaseMicroservice/PurchaseDto/PurchaseQueryDTO.cs:
--------------------------------------------------------------------------------
1 | namespace Purchase.DTO
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Text;
6 |
7 | public class PurchaseQueryDTO
8 | {
9 | public DateTime DateFrom { get; set; }
10 |
11 | public DateTime DateTo { get; set; }
12 |
13 | public int PageNumber { get; set; }
14 |
15 | public int PageSize { get; set; }
16 |
17 | public string SortField { get; set; }
18 |
19 | ///
20 | /// 0 > Asending 1 > Decending
21 | ///
22 | public int SortDirection { get; set; }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/Src/InventoryMicroservice/Inventory.EventHandler/Inventory.EventHandler/Inventory.EventHandler.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.1
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/Src/SalesMicroservice/SalesQueryHandler/Sales.QueryHandler.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.1
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/Src/SalesMicroservice/SalesDomain/SalesLineItem.cs:
--------------------------------------------------------------------------------
1 | namespace Sales.Domain
2 | {
3 | using Common.Core;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Text;
7 |
8 | public class SalesLineItem
9 | {
10 | public string ProductId { get; set; }
11 |
12 | public string ProductName { get; set; }
13 |
14 | public string UnitName { get; set; }
15 |
16 | public long UnitSalePrice { get; set; }
17 |
18 | public long SalesQuantity { get; set; }
19 |
20 | public long SalesTotalPrice
21 | {
22 | get { return UnitSalePrice * SalesQuantity; }
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/Src/CommonAll/Common.Core.Tests/Common.Core.Tests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp3.1
5 |
6 | false
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/Src/InventoryMicroservice/Inventory.Api.Grpc/Services/GreeterService.cs:
--------------------------------------------------------------------------------
1 | namespace Inventory.Api.Grpc
2 | {
3 | using global::Grpc.Core;
4 | using Microsoft.Extensions.Logging;
5 | using System.Threading.Tasks;
6 |
7 | public class InventoryService : InventoryServiceProvider.InventoryServiceProviderBase
8 | {
9 |
10 | public InventoryService()
11 | {
12 | }
13 |
14 | public override Task CountTotalItems(ServiceRequest request, ServerCallContext context)
15 | {
16 | // Need to fetch from db. Now it is hardcode value
17 |
18 | return Task.FromResult(new ServiceReplay { ItemCount = "999" });
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Src/InventoryMicroservice/InventoryCommandHandler/Inventory.CommandHandler.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.1
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/Src/CommonAll/Common.Core/Entity.cs:
--------------------------------------------------------------------------------
1 | namespace Common.Core
2 | {
3 | using MongoDB.Bson.Serialization.Attributes;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Text;
7 |
8 | public abstract class Entity
9 | {
10 | [BsonElement("_id")]
11 | public string Id { get; set; }
12 |
13 | public DateTime CreatedOn { get; set; }
14 |
15 | public DateTime UpdatedOn { get; set; }
16 |
17 | public string CreatedBy { get; set; }
18 |
19 | public string UpdatedBy { get; set; }
20 |
21 | public Entity()
22 | {
23 | CreatedOn = DateTime.UtcNow;
24 | UpdatedOn = DateTime.UtcNow;
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/Src/PurchaseMicroservice/PurchaseDomain/Models/ProductLineItem.cs:
--------------------------------------------------------------------------------
1 | namespace Purchase.Domain.Model
2 | {
3 | using Common.Core;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Text;
7 |
8 | ///
9 | /// Product Purchase Line Item Entity
10 | ///
11 | public class ProductLineItem : Entity
12 | {
13 | public Product Product { get; set; }
14 |
15 | public long PurchaseUnitPrice { get; set; }
16 |
17 | public long PurchaseQuantity { get; set; }
18 |
19 | public long PurchaseTotalPrice
20 | {
21 | get
22 | {
23 | return PurchaseQuantity * PurchaseUnitPrice;
24 | }
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/Src/InventoryMicroservice/Inventory.Api.Grpc/Inventory.Api.Grpc.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp3.1
5 | 98f4083c-b443-499d-8fc3-ac5c3cda9802
6 | Linux
7 | ..\..
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/Src/CommonAll/Common.Core/JsonSerializer.cs:
--------------------------------------------------------------------------------
1 | namespace Common.Core
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Text;
6 | using System.Text.Json;
7 | using System.Threading.Tasks;
8 |
9 | public class JsonSerializer : ISerializer
10 | {
11 | public virtual Task Serialize(T obj)
12 | {
13 | string jsonData = System.Text.Json.JsonSerializer.Serialize(obj);
14 |
15 | return Task.FromResult(jsonData);
16 | }
17 |
18 | public virtual Task Decerialize(string jsonData)
19 | {
20 | T obj = System.Text.Json.JsonSerializer.Deserialize(jsonData);
21 |
22 | return Task.FromResult(obj);
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/Src/PurchaseMicroservice/PurchaseDto/PurchaseDTO.cs:
--------------------------------------------------------------------------------
1 | namespace Purchase.DTO
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 |
6 | public class PurchaseDTO
7 | {
8 | public DateTime PurchaseDate { get; set; }
9 |
10 | public IList PurchaseItems { get; set; }
11 |
12 | public PurchaseDTO()
13 | {
14 | PurchaseItems = new List();
15 | }
16 |
17 | public long GetTotalPrice()
18 | {
19 | long total = 0;
20 |
21 | foreach (PurchaseItemDTO dto in PurchaseItems)
22 | {
23 | total += dto.UnitPrice * dto.Quantity;
24 | }
25 |
26 | return total;
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/Src/SalesMicroservice/SalesDto/SalesDTO.cs:
--------------------------------------------------------------------------------
1 | namespace Sales.DTO
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 |
6 | public class SalesDTO
7 | {
8 | public DateTime SalesDate { get; set; }
9 |
10 | public IList SalesProducts { get; set; }
11 |
12 | public SalesDTO()
13 | {
14 | this.SalesProducts = new List();
15 | }
16 | }
17 |
18 | public class SalesProductDTO
19 | {
20 | public string ProductId { get; set; }
21 |
22 | public string ProductName { get; set; }
23 |
24 | public string UnitName { get; set; }
25 |
26 | public long UnitPrice { get; set; }
27 |
28 | public long Quantity { get; set; }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/Src/InventoryMicroservice/Inventory.QueryHandler/Inventory.QueryHandler.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.1
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/Src/SalesMicroservice/SalesCommandHandler/Sales.CommandHandler.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.1
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/Src/InventoryMicroservice/InventoryWebApi/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "iisSettings": {
3 | "windowsAuthentication": false,
4 | "anonymousAuthentication": true,
5 | "iisExpress": {
6 | "applicationUrl": "http://localhost:53158",
7 | "sslPort": 44318
8 | }
9 | },
10 | "profiles": {
11 | "IIS Express": {
12 | "commandName": "IISExpress",
13 | "launchBrowser": true,
14 | "environmentVariables": {
15 | "ASPNETCORE_ENVIRONMENT": "Development"
16 | }
17 | },
18 | "InventoryWebApi": {
19 | "commandName": "Project",
20 | "launchBrowser": false,
21 | "applicationUrl": "https://localhost:4001;http://localhost:4000",
22 | "environmentVariables": {
23 | "ASPNETCORE_ENVIRONMENT": "Development"
24 | }
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/Src/PurchaseMicroservice/PurchaseWebApi/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "iisSettings": {
3 | "windowsAuthentication": false,
4 | "anonymousAuthentication": true,
5 | "iisExpress": {
6 | "applicationUrl": "http://localhost:52995",
7 | "sslPort": 44347
8 | }
9 | },
10 | "profiles": {
11 | "IIS Express": {
12 | "commandName": "IISExpress",
13 | "launchBrowser": true,
14 | "environmentVariables": {
15 | "ASPNETCORE_ENVIRONMENT": "Development"
16 | }
17 | },
18 | "PurchaseWebApi": {
19 | "commandName": "Project",
20 | "launchBrowser": false,
21 | "applicationUrl": "https://localhost:5001;http://localhost:5000",
22 | "environmentVariables": {
23 | "ASPNETCORE_ENVIRONMENT": "Development"
24 | }
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/Src/SalesMicroservice/SalesWebApi/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using Microsoft.AspNetCore.Hosting;
6 | using Microsoft.Extensions.Configuration;
7 | using Microsoft.Extensions.Hosting;
8 | using Microsoft.Extensions.Logging;
9 |
10 | namespace SalesWebApi
11 | {
12 | public class Program
13 | {
14 | public static void Main(string[] args)
15 | {
16 | CreateHostBuilder(args).Build().Run();
17 | }
18 |
19 | public static IHostBuilder CreateHostBuilder(string[] args) =>
20 | Host.CreateDefaultBuilder(args)
21 | .ConfigureWebHostDefaults(webBuilder =>
22 | {
23 | webBuilder.UseStartup();
24 | });
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Src/PurchaseMicroservice/Purchase.QueryHandler/Purchase.QueryHandler.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.1
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/Src/CommonAll/Common.Infrastructure/QueryBus.cs:
--------------------------------------------------------------------------------
1 | namespace Common.Infrastructure
2 | {
3 | using Common.Core;
4 | using System;
5 | using System.Threading.Tasks;
6 | using Microsoft.Extensions.DependencyInjection;
7 |
8 | public class QueryBus : IQueryBus
9 | {
10 | private readonly IServiceProvider serviceProvider;
11 |
12 | public QueryBus(IServiceProvider serviceProvider)
13 | {
14 | this.serviceProvider = serviceProvider;
15 | }
16 |
17 | public async Task Send(TQuery query)
18 | where TQuery : IQuery
19 | where TResult : QueryResult
20 | {
21 | var queryHandler = serviceProvider.GetService>();
22 |
23 | return await queryHandler.Handle(query);
24 | }
25 | }
26 | }
27 |
28 |
--------------------------------------------------------------------------------
/Src/PurchaseMicroservice/PurchaseWebApi/Program.cs:
--------------------------------------------------------------------------------
1 | namespace Purchase.Api
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Threading.Tasks;
7 | using Microsoft.AspNetCore.Hosting;
8 | using Microsoft.Extensions.Configuration;
9 | using Microsoft.Extensions.Hosting;
10 | using Microsoft.Extensions.Logging;
11 |
12 | public class Program
13 | {
14 | public static void Main(string[] args)
15 | {
16 | CreateHostBuilder(args).Build().Run();
17 | }
18 |
19 | public static IHostBuilder CreateHostBuilder(string[] args) =>
20 | Host.CreateDefaultBuilder(args)
21 | .ConfigureWebHostDefaults(webBuilder =>
22 | {
23 | webBuilder.UseStartup();
24 | });
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Src/InventoryMicroservice/InventoryWebApi/Program.cs:
--------------------------------------------------------------------------------
1 | namespace Inventory.Api
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Threading.Tasks;
7 | using Microsoft.AspNetCore.Hosting;
8 | using Microsoft.Extensions.Configuration;
9 | using Microsoft.Extensions.Hosting;
10 | using Microsoft.Extensions.Logging;
11 |
12 | public class Program
13 | {
14 | public static void Main(string[] args)
15 | {
16 | CreateHostBuilder(args).Build().Run();
17 | }
18 |
19 | public static IHostBuilder CreateHostBuilder(string[] args) =>
20 | Host.CreateDefaultBuilder(args)
21 | .ConfigureWebHostDefaults(webBuilder =>
22 | {
23 | webBuilder.UseStartup();
24 | });
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Src/InventoryMicroservice/Inventory.Api.Tests/Inventory.Api.Tests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp3.1
5 |
6 | false
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/Src/SalesMicroservice/SalesQueryHandler/SalesQueryHandler.cs:
--------------------------------------------------------------------------------
1 | namespace Sales.QueryHandler
2 | {
3 | using Common.Core;
4 | using Sales.DTO;
5 | using Sales.Query;
6 | using Sales.Repository;
7 | using System.Threading.Tasks;
8 |
9 | public class SalesQueryHandler : IQueryHandler
10 | {
11 | private readonly ISalesRepository salesRepository;
12 |
13 | public SalesQueryHandler(ISalesRepository salesRepository)
14 | {
15 | this.salesRepository = salesRepository;
16 | }
17 |
18 | public async Task Handle(SalesQuery query)
19 | {
20 | ProductSalesDTO productSalesDTO = await salesRepository.FindSoldProductInfo(query.ProductId, query.DateFrom, query.DateTo);
21 |
22 | return new QueryResult { Result = productSalesDTO };
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/Src/SalesMicroservice/SalesWebApi/Dockerfile:
--------------------------------------------------------------------------------
1 | #See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging.
2 |
3 | FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-buster-slim AS base
4 | WORKDIR /app
5 | EXPOSE 80
6 | EXPOSE 443
7 |
8 | FROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster AS build
9 | WORKDIR /src
10 | COPY ["SalesMicroservice/SalesWebApi/SalesWebApi.csproj", "SalesMicroservice/SalesWebApi/"]
11 | RUN dotnet restore "SalesMicroservice/SalesWebApi/SalesWebApi.csproj"
12 | COPY . .
13 | WORKDIR "/src/SalesMicroservice/SalesWebApi"
14 | RUN dotnet build "SalesWebApi.csproj" -c Release -o /app/build
15 |
16 | FROM build AS publish
17 | RUN dotnet publish "SalesWebApi.csproj" -c Release -o /app/publish
18 |
19 | FROM base AS final
20 | WORKDIR /app
21 | COPY --from=publish /app/publish .
22 | ENTRYPOINT ["dotnet", "SalesWebApi.dll"]
--------------------------------------------------------------------------------
/Src/PurchaseMicroservice/PurchaseQuery/ProductPurchasedQuery.cs:
--------------------------------------------------------------------------------
1 | namespace Purchase.Query
2 | {
3 | using Common.Core;
4 | using System;
5 |
6 | public class ProductPurchasedQuery : IQuery
7 | {
8 | public DateTime DateFrom { get; set; }
9 |
10 | public DateTime DateTo { get; set; }
11 |
12 | ///
13 | /// Page stared from 1
14 | ///
15 | public int PageNumber { get; set; }
16 |
17 | ///
18 | /// No of records per page
19 | ///
20 | public int PageSize { get; set; }
21 |
22 | ///
23 | /// Field Name to be ordered
24 | ///
25 | public string SortFiled { get; set; }
26 |
27 | ///
28 | /// 0 -> Ascending 1 -> Descending
29 | ///
30 | public int SortDirection { get; set; }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/Src/SalesMicroservice/SalesCommand/SalesCommand.cs:
--------------------------------------------------------------------------------
1 | namespace Sales.Command
2 | {
3 | using Common.Core;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Text;
7 |
8 | public class SalesCommand : ICommand
9 | {
10 | public string SalesId { get; set; }
11 |
12 | public DateTime SalesDate { get; set; }
13 |
14 | public IList SalesProducts { get; set; }
15 |
16 | public SalesCommand()
17 | {
18 | this.SalesProducts = new List();
19 | }
20 | }
21 |
22 | public class SalesProduct
23 | {
24 | public string ProductId { get; set; }
25 |
26 | public string ProductName { get; set; }
27 |
28 | public string UnitName { get; set; }
29 |
30 | public long SalesUnitPrice { get; set; }
31 |
32 | public long SalesQuantity { get; set; }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/Src/CommonAll/Common.Infrastructure.Tests/Common.Infrastructure.Tests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp3.1
5 |
6 | false
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/Src/InventoryMicroservice/Inventory.Api.Grpc.Tests/InventoryServiceTest.cs:
--------------------------------------------------------------------------------
1 | namespace Inventory.Api.Grpc.Tests
2 | {
3 | using FluentAssertions;
4 | using global::Grpc.Net.Client;
5 | using System.Threading.Tasks;
6 | using Xunit;
7 | using static Inventory.Api.Grpc.InventoryServiceProvider;
8 |
9 | public class InventoryServiceTest
10 | {
11 | [Fact]
12 | public async Task ShouldReturnTotalItemsCountWhenValidStoreId()
13 | {
14 | using GrpcChannel channel = GrpcChannel.ForAddress("https://localhost:7001");
15 |
16 | var client = new InventoryServiceProviderClient(channel);
17 |
18 | var request = new ServiceRequest
19 | {
20 | StoreId = "S001"
21 | };
22 |
23 | ServiceReplay replay = await client.CountTotalItemsAsync(request);
24 |
25 | replay.ItemCount.Should().Equals("999");
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Src/InventoryMicroservice/Inventory.Api.Grpc/Dockerfile:
--------------------------------------------------------------------------------
1 | #See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging.
2 |
3 | FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-buster-slim AS base
4 | WORKDIR /app
5 | EXPOSE 80
6 | EXPOSE 443
7 |
8 | FROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster AS build
9 | WORKDIR /src
10 | COPY ["InventoryMicroservice/Inventory.Api.Grpc/Inventory.Api.Grpc.csproj", "InventoryMicroservice/Inventory.Api.Grpc/"]
11 | RUN dotnet restore "InventoryMicroservice/Inventory.Api.Grpc/Inventory.Api.Grpc.csproj"
12 | COPY . .
13 | WORKDIR "/src/InventoryMicroservice/Inventory.Api.Grpc"
14 | RUN dotnet build "Inventory.Api.Grpc.csproj" -c Release -o /app/build
15 |
16 | FROM build AS publish
17 | RUN dotnet publish "Inventory.Api.Grpc.csproj" -c Release -o /app/publish
18 |
19 | FROM base AS final
20 | WORKDIR /app
21 | COPY --from=publish /app/publish .
22 | ENTRYPOINT ["dotnet", "Inventory.Api.Grpc.dll"]
--------------------------------------------------------------------------------
/Src/CommonAll/Common.Infrastructure/CommandBus.cs:
--------------------------------------------------------------------------------
1 | namespace Common.Infrastructure
2 | {
3 | using Common.Core;
4 | using Microsoft.Extensions.DependencyInjection;
5 | using System;
6 | using System.Threading.Tasks;
7 |
8 | ///
9 | /// Delegate commands with its handler with the help of IOC
10 | ///
11 | public class CommandBus : ICommandBus
12 | {
13 | private readonly IServiceProvider serviceProvider;
14 |
15 | public CommandBus(IServiceProvider serviceProvider)
16 | {
17 | this.serviceProvider = serviceProvider;
18 | }
19 |
20 | public async Task Send(TCommand command)
21 | where TCommand : ICommand
22 | where TResult : CommandResult
23 | {
24 | var commandHandler = serviceProvider.GetService>();
25 |
26 | return await commandHandler.Handle(command);
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/Src/InventoryMicroservice/Inventory.Api.Grpc/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Threading.Tasks;
6 | using Microsoft.AspNetCore.Hosting;
7 | using Microsoft.Extensions.Hosting;
8 |
9 | namespace Inventory.Api.Grpc
10 | {
11 | public class Program
12 | {
13 | public static void Main(string[] args)
14 | {
15 | CreateHostBuilder(args).Build().Run();
16 | }
17 |
18 | // Additional configuration is required to successfully run gRPC on macOS.
19 | // For instructions on how to configure Kestrel and gRPC clients on macOS, visit https://go.microsoft.com/fwlink/?linkid=2099682
20 | public static IHostBuilder CreateHostBuilder(string[] args) =>
21 | Host.CreateDefaultBuilder(args)
22 | .ConfigureWebHostDefaults(webBuilder =>
23 | {
24 | webBuilder.UseStartup();
25 | });
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/Src/CommonAll/Common.Core/IMongoService.cs:
--------------------------------------------------------------------------------
1 | namespace Common.Core
2 | {
3 | using MongoDB.Driver;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Text;
7 |
8 | public interface IMongoService
9 | {
10 | ///
11 | /// If provide null instead of databasename it will provide default database
12 | ///
13 | ///
14 | ///
15 | IMongoDatabase GetDatabase(string databaseName);
16 |
17 | ///
18 | /// Convenstion that followed -> Collection name would be pluralize from its type name. ex: UserRole -> UserRoles
19 | ///
20 | ///
21 | ///
22 | ///
23 | IMongoCollection GetCollection();
24 |
25 | IMongoCollection GetCollection(string collectionName, string databaseName);
26 |
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Src/SalesMicroservice/SalesWebApi/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "iisSettings": {
3 | "windowsAuthentication": false,
4 | "anonymousAuthentication": true,
5 | "iisExpress": {
6 | "applicationUrl": "http://localhost:53205",
7 | "sslPort": 44354
8 | }
9 | },
10 | "profiles": {
11 | "IIS Express": {
12 | "commandName": "IISExpress",
13 | "launchBrowser": true,
14 | "environmentVariables": {
15 | "ASPNETCORE_ENVIRONMENT": "Development"
16 | }
17 | },
18 | "SalesWebApi": {
19 | "commandName": "Project",
20 | "environmentVariables": {
21 | "ASPNETCORE_ENVIRONMENT": "Development"
22 | },
23 | "applicationUrl": "https://localhost:6001;http://localhost:6000",
24 | "launchBrowser": false
25 | },
26 | "Docker": {
27 | "commandName": "Docker",
28 | "launchBrowser": false,
29 | "launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}",
30 | "publishAllPorts": true,
31 | "useSSL": true
32 | }
33 | }
34 | }
--------------------------------------------------------------------------------
/Src/InventoryMicroservice/Inventory.Api.Grpc/Startup.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using Microsoft.AspNetCore.Builder;
6 | using Microsoft.AspNetCore.Hosting;
7 | using Microsoft.AspNetCore.Http;
8 | using Microsoft.Extensions.DependencyInjection;
9 | using Microsoft.Extensions.Hosting;
10 |
11 | namespace Inventory.Api.Grpc
12 | {
13 | public class Startup
14 | {
15 | public void ConfigureServices(IServiceCollection services)
16 | {
17 | services.AddGrpc();
18 | }
19 |
20 | public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
21 | {
22 | if (env.IsDevelopment())
23 | {
24 | app.UseDeveloperExceptionPage();
25 | }
26 |
27 | app.UseRouting();
28 |
29 | app.UseEndpoints(endpoints =>
30 | {
31 | endpoints.MapGrpcService();
32 | });
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/Src/InventoryMicroservice/InventoryWebApi/Controllers/StoreQueryController.cs:
--------------------------------------------------------------------------------
1 | namespace Inventory.Api.Controllers
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Threading.Tasks;
7 | using Common.Core;
8 | using Inventory.Query;
9 | using Microsoft.AspNetCore.Http;
10 | using Microsoft.AspNetCore.Mvc;
11 |
12 | [Route("api/[controller]")]
13 | [ApiController]
14 | public class StoreQueryController : ControllerBase
15 | {
16 | private readonly IQueryBus queryBus;
17 |
18 | public StoreQueryController(IQueryBus queryBus)
19 | {
20 | this.queryBus = queryBus;
21 | }
22 |
23 | [HttpGet("stores")]
24 | public Task GetAllStores()
25 | {
26 | return queryBus.Send(new StoreQuery());
27 | }
28 |
29 | [HttpGet("is-service-on")]
30 | public Task IsServiceOn()
31 | {
32 | return Task.FromResult(true);
33 | }
34 | }
35 | }
--------------------------------------------------------------------------------
/Src/InventoryMicroservice/InventoryWebApi/Controllers/StoreCommandController.cs:
--------------------------------------------------------------------------------
1 | namespace Inventory.Api.Controllers
2 | {
3 | using Common.Core;
4 | using Inventory.Command;
5 | using Inventory.DTO;
6 | using Microsoft.AspNetCore.Mvc;
7 | using System;
8 | using System.Threading.Tasks;
9 |
10 | [Route("api/[controller]")]
11 | [ApiController]
12 | public class StoreCommandController : ControllerBase
13 | {
14 | private readonly ICommandBus commandBus;
15 |
16 | public StoreCommandController(ICommandBus commandBus)
17 | {
18 | this.commandBus = commandBus;
19 | }
20 |
21 | [HttpPost]
22 | [Route("[action]")]
23 | public Task CreateStore(StoreDTO store)
24 | {
25 | var command = new CreateStoreCommand
26 | {
27 | StoreId = Guid.NewGuid().ToString(),
28 | ManagerName = store.ManagerName
29 | };
30 |
31 | return commandBus.Send(command);
32 | }
33 | }
34 | }
--------------------------------------------------------------------------------
/Src/CommonAll/Common.Core/Events/ProductPurchasedEvent.cs:
--------------------------------------------------------------------------------
1 | namespace Common.Core.Events
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 |
6 | public class ProductPurchasedEvent : IEvent
7 | {
8 | public string PurchaseId { get; set; }
9 |
10 | public DateTime PurchaseDate { get; set; }
11 |
12 | public IList LineItems { get; set; }
13 |
14 | public ProductPurchasedEvent()
15 | {
16 | LineItems = new List();
17 | }
18 | }
19 |
20 | public class PurchasedLineItem
21 | {
22 | public string ProductId { get; set; }
23 |
24 | public string ProductName { get; set; }
25 |
26 | public long PurchasedQuantity { get; set; }
27 |
28 | public string PurchasedUnitName { get; set; }
29 |
30 | public long PurchasedUnitPrice { get; set; }
31 |
32 | public long PurchaedTotalPrice
33 | {
34 | get
35 | {
36 | return PurchasedUnitPrice * PurchasedQuantity;
37 | }
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/Src/SalesMicroservice/Sales.Repository.Tests/Sales.Repository.Tests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp3.1
5 |
6 | false
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 s. m. ahasan habib
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Src/SalesMicroservice/SalesWebApi/Controllers/SalesQueryController.cs:
--------------------------------------------------------------------------------
1 | namespace Sales.Api.Controllers
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Threading.Tasks;
7 | using Common.Core;
8 | using Microsoft.AspNetCore.Http;
9 | using Microsoft.AspNetCore.Mvc;
10 | using Sales.Query;
11 |
12 | [Route("api/[controller]")]
13 | [ApiController]
14 | public class SalesQueryController : ControllerBase
15 | {
16 | private readonly IQueryBus queryBus;
17 |
18 | public SalesQueryController(IQueryBus queryBus)
19 | {
20 | this.queryBus = queryBus;
21 | }
22 |
23 | [HttpGet("sales")]
24 | public Task GetProudctSalesInfo(string productId, DateTime dateFrom, DateTime dateTo)
25 | {
26 | var salesQuery = new SalesQuery
27 | {
28 | ProductId = productId,
29 | DateFrom = dateFrom,
30 | DateTo = dateTo
31 | };
32 |
33 | return queryBus.Send(salesQuery);
34 | }
35 | }
36 | }
--------------------------------------------------------------------------------
/Src/InventoryMicroservice/Inventory.Api.Tests/TestClientProvider.cs:
--------------------------------------------------------------------------------
1 | namespace Inventory.Api.Tests
2 | {
3 | using Microsoft.AspNetCore.Hosting;
4 | using Microsoft.AspNetCore.TestHost;
5 | using Microsoft.Extensions.Configuration;
6 | using System;
7 | using System.Collections.Generic;
8 | using System.IO;
9 | using System.Net.Http;
10 | using System.Text;
11 |
12 | public class TestClientProvider
13 | {
14 | public HttpClient HttpClient { get; private set; }
15 |
16 | public TestClientProvider()
17 | {
18 | var webHostBuilder = new WebHostBuilder();
19 | webHostBuilder.UseConfiguration(GetConfig());
20 | webHostBuilder.UseStartup();
21 |
22 | HttpClient = new TestServer(webHostBuilder).CreateClient();
23 | }
24 |
25 | private IConfiguration GetConfig()
26 | {
27 | var builder = new ConfigurationBuilder()
28 | .SetBasePath(Directory.GetCurrentDirectory())
29 | .AddJsonFile("appsettings.json", true, true)
30 | .AddEnvironmentVariables();
31 |
32 | return builder.Build();
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/Src/CommonAll/Common.Core/Events/ProductSoldEvent.cs:
--------------------------------------------------------------------------------
1 | namespace Common.Core.Events
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Text;
6 |
7 | public class ProductSoldEvent : IEvent
8 | {
9 | public string SalesId { get; set; }
10 |
11 | public DateTime SalesDate { get; set; }
12 |
13 | public IList ProductSoldLineItems { get; set; }
14 |
15 | public ProductSoldEvent()
16 | {
17 | ProductSoldLineItems = new List();
18 | }
19 | }
20 |
21 | ///
22 | /// Part of ProductSoldEvent
23 | ///
24 | public class ProductSoldLineItem
25 | {
26 | public string ProductId { get; set; }
27 |
28 | public string ProductName { get; set; }
29 |
30 | public long SoldQuantity { get; set; }
31 |
32 | public string SoldUnitName { get; set; }
33 |
34 | public long SoldUnitPrice { get; set; }
35 |
36 | public long SoldTotalPrice
37 | {
38 | get
39 | {
40 | return SoldUnitPrice * SoldQuantity;
41 | }
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/Src/PurchaseMicroservice/PurchaseWebApi/Purchase.Api.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp3.1
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/Src/InventoryMicroservice/Inventory.Api.Grpc.Tests/Inventory.Api.Grpc.Tests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp3.1
5 |
6 | false
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | all
16 | runtime; build; native; contentfiles; analyzers; buildtransitive
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/Src/InventoryMicroservice/Inventory.EventHandler/Inventory.EventHandler/ProductSoldEventHandler.cs:
--------------------------------------------------------------------------------
1 | namespace Inventory.EventHandler
2 | {
3 | using Common.Core;
4 | using Common.Core.Events;
5 | using Inventory.Domain;
6 | using Inventory.Repository;
7 | using System;
8 | using System.Threading.Tasks;
9 |
10 | public class ProductSoldEventHandler : IEventHandler
11 | {
12 | private readonly IStoreItemRepository storeItemRepository;
13 |
14 | public ProductSoldEventHandler(IStoreItemRepository storeItemRepository)
15 | {
16 | this.storeItemRepository = storeItemRepository;
17 | }
18 |
19 | public async Task Handle(ProductSoldEvent @event)
20 | {
21 | foreach (ProductSoldLineItem soldItem in @event.ProductSoldLineItems)
22 | {
23 | StoreItem storeItem = await storeItemRepository.GetById(soldItem.ProductId);
24 | if (null == storeItem)
25 | throw new ApplicationException($"Sorry! StoreItem: {soldItem.ProductId} not found in store.");
26 |
27 | storeItem.BalanceQuantity -= soldItem.SoldQuantity;
28 |
29 | await storeItemRepository.UpdateItem(storeItem);
30 | }
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/Src/InventoryMicroservice/Inventory.Api.Tests/StoredCommandControllerTest.cs:
--------------------------------------------------------------------------------
1 | namespace Inventory.Api.Tests
2 | {
3 | using FluentAssertions;
4 | using Inventory.DTO;
5 | using Newtonsoft.Json;
6 | using System.Net.Http;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 | using Xunit;
10 |
11 | public class StoredCommandControllerTest
12 | {
13 | private readonly HttpClient httpClient;
14 |
15 | public StoredCommandControllerTest()
16 | {
17 | var testServerProvider = new TestClientProvider();
18 | this.httpClient = testServerProvider.HttpClient;
19 | }
20 |
21 | [Fact]
22 | public async Task ShouldCreateStore()
23 | {
24 | var storeDTO = new StoreDTO
25 | {
26 | StoreId = "S001",
27 | ManagerName = "Mr. Manager"
28 | };
29 |
30 | var storeJson = JsonConvert.SerializeObject(storeDTO);
31 | var content = new StringContent(storeJson, Encoding.UTF8, "application/json");
32 |
33 | var response = await httpClient.PostAsync("/api/StoreCommand/CreateStore", content);
34 |
35 | response.EnsureSuccessStatusCode();
36 |
37 | response.IsSuccessStatusCode.Should().BeTrue();
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/Src/InventoryMicroservice/Inventory.Api.Tests/StoreQueryControllerTest.cs:
--------------------------------------------------------------------------------
1 | namespace Inventory.Api.Tests
2 | {
3 | using Common.Core;
4 | using FluentAssertions;
5 | using Inventory.Domain;
6 | using Newtonsoft.Json;
7 | using Newtonsoft.Json.Linq;
8 | using System.Collections.Generic;
9 | using System.Net.Http;
10 | using System.Threading.Tasks;
11 | using Xunit;
12 |
13 | public class StoreQueryControllerTest
14 | {
15 | private readonly HttpClient httpClient;
16 |
17 | public StoreQueryControllerTest()
18 | {
19 | httpClient = new TestClientProvider().HttpClient;
20 | }
21 |
22 | [Fact]
23 | public async Task ShouldFetchAllStoreInfo()
24 | {
25 | HttpResponseMessage responseMessage = await httpClient.GetAsync("/api/storequery/stores");
26 | responseMessage.EnsureSuccessStatusCode();
27 |
28 | var storesJson = await responseMessage.Content.ReadAsStringAsync();
29 | var queryResult = JsonConvert.DeserializeObject(storesJson);
30 |
31 | queryResult.Succeed.Should().BeTrue();
32 | var storeList = ((JArray) queryResult.Result).ToObject>();
33 |
34 | storeList.Should().HaveCountGreaterOrEqualTo(1);
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/Src/InventoryMicroservice/InventoryWebApi/Inventory.Api.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp3.1
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | Always
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/Src/PurchaseMicroservice/PurchaseWebApi/Controllers/PurchaseQueryController.cs:
--------------------------------------------------------------------------------
1 | namespace Purchase.Api.Controllers
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Threading.Tasks;
7 | using Common.Core;
8 | using Microsoft.AspNetCore.Http;
9 | using Microsoft.AspNetCore.Mvc;
10 | using Purchase.DTO;
11 | using Purchase.Query;
12 |
13 | [Route("api/[controller]")]
14 | [ApiController]
15 | public class PurchaseQueryController : ControllerBase
16 | {
17 | private readonly IQueryBus queryBus;
18 |
19 | public PurchaseQueryController(IQueryBus queryBus)
20 | {
21 | this.queryBus = queryBus;
22 | }
23 |
24 | [HttpGet("purchase")]
25 | public Task GetPurchasedData([FromQuery] PurchaseQueryDTO query)
26 | {
27 | var productPurchaseQuery = new ProductPurchasedQuery
28 | {
29 | DateFrom = query.DateFrom,
30 | DateTo = query.DateTo,
31 | PageNumber = query.PageNumber,
32 | PageSize = query.PageSize,
33 | SortFiled = query.SortField,
34 | SortDirection = query.SortDirection
35 | };
36 |
37 | return queryBus.Send(productPurchaseQuery);
38 | }
39 | }
40 | }
--------------------------------------------------------------------------------
/Src/PurchaseMicroservice/PurchaseInfrastructure/RabbitMqBus.cs:
--------------------------------------------------------------------------------
1 | namespace Purchase.Infrastructure
2 | {
3 | using Common.All;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 | using RabbitMQ.Client;
9 | using System.Text.Json;
10 |
11 | public class RabbitMqBus : IServiceBus
12 | {
13 | private readonly IDictionary settings;
14 |
15 | public RabbitMqBus(IDictionary settings)
16 | {
17 | this.settings = settings;
18 | }
19 |
20 | public Task Publish(string message, string queue)
21 | {
22 | PublishLocal(message, queue);
23 |
24 | return Task.CompletedTask;
25 | }
26 |
27 | private void PublishLocal(string message, string queue)
28 | {
29 | var factory = new ConnectionFactory
30 | {
31 | HostName = settings["host"],
32 | Port = Convert.ToInt32(settings["port"])
33 | };
34 | using var connection = factory.CreateConnection();
35 | using var model = connection.CreateModel();
36 |
37 | QueueDeclareOk ok = model.QueueDeclare(queue, true, false, false, null);
38 | byte[] bodyBytes = Encoding.UTF8.GetBytes(message);
39 |
40 | model.BasicPublish(string.Empty, queue, null, bodyBytes);
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/Src/CommonAll/Common.Infrastructure/EmailService.cs:
--------------------------------------------------------------------------------
1 | namespace Common.Infrastructure
2 | {
3 | using Common.Core;
4 | using MailKit.Net.Smtp;
5 | using MimeKit;
6 | using System;
7 | using System.Diagnostics;
8 | using System.Threading.Tasks;
9 |
10 | public class EmailService : IEmailService
11 | {
12 | private readonly EmailSettings settings;
13 |
14 | public EmailService(EmailSettings settings)
15 | {
16 | this.settings = settings;
17 | }
18 |
19 | public async Task SendEmail(EmailParams emailParams)
20 | {
21 | var mimeMessage = new MimeMessage();
22 | emailParams.ToList.ForEach(to => mimeMessage.To.Add(new MailboxAddress(to)));
23 | emailParams.CcList.ForEach(to => mimeMessage.Cc.Add(new MailboxAddress(to)));
24 | mimeMessage.From.Add(new MailboxAddress(settings.FromAddress));
25 | mimeMessage.Subject = emailParams.Subject;
26 | mimeMessage.Body = new TextPart("plain") { Text = emailParams.Body };
27 |
28 | using var smtpClient = new SmtpClient();
29 |
30 | try
31 | {
32 | smtpClient.Connect(settings.Host, settings.Port, settings.Ssl);
33 | await smtpClient.AuthenticateAsync(settings.UserId, settings.Password);
34 |
35 | await smtpClient.SendAsync(mimeMessage);
36 | }
37 | catch(Exception ex)
38 | {
39 | Debug.WriteLine(ex);
40 | }
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/Src/InventoryMicroservice/Inventory.QueryHandler/StoreQueryHandler.cs:
--------------------------------------------------------------------------------
1 | namespace Inventory.QueryHandler
2 | {
3 | using Common.Core;
4 | using Inventory.Domain;
5 | using Inventory.DTO;
6 | using Inventory.Query;
7 | using Inventory.Repository;
8 | using System;
9 | using System.Collections.Generic;
10 | using System.Threading.Tasks;
11 |
12 | public class StoreQueryHandler : IQueryHandler
13 | {
14 | public readonly IStoreRepository storeRepository;
15 |
16 | public StoreQueryHandler(IStoreRepository storeRepository)
17 | {
18 | this.storeRepository = storeRepository;
19 | }
20 |
21 | public async Task Handle(StoreQuery query)
22 | {
23 | IEnumerable stores = await storeRepository.GetAll();
24 |
25 | return new QueryResult
26 | {
27 | Result = Map(stores)
28 | };
29 | }
30 |
31 | private IEnumerable Map(IEnumerable stores)
32 | {
33 | var dtoList = new List();
34 |
35 | foreach(Store store in stores)
36 | {
37 | var storeDto = new StoreDTO
38 | {
39 | StoreId = store.Id,
40 | ManagerName = store.Manager,
41 | CreatedDate = store.CreatedOn
42 | };
43 |
44 | dtoList.Add(storeDto);
45 | }
46 |
47 | return dtoList;
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/Src/InventoryMicroservice/InventoryRepository/StoreRepository.cs:
--------------------------------------------------------------------------------
1 | namespace Inventory.Repository
2 | {
3 | using Common.Core;
4 | using Inventory.Domain;
5 | using MongoDB.Driver;
6 | using System.Collections.Generic;
7 | using System.Threading.Tasks;
8 |
9 | public class StoreRepository : IStoreRepository
10 | {
11 | private readonly IMongoService mongoDbService;
12 |
13 | public StoreRepository(IMongoService mongoDbService)
14 | {
15 | this.mongoDbService = mongoDbService;
16 | }
17 |
18 | public async Task> GetAll()
19 | {
20 | IMongoCollection storeCollection = mongoDbService.GetCollection();
21 |
22 | IAsyncCursor storeCursor = await storeCollection.FindAsync(_ => true);
23 |
24 | return storeCursor.ToEnumerable();
25 | }
26 |
27 | public async Task GetById(string id)
28 | {
29 | IMongoCollection storeCollection = mongoDbService.GetCollection();
30 |
31 | IAsyncCursor storeCursor = await storeCollection.FindAsync(item => item.Id.Equals(id));
32 |
33 | return await storeCursor.FirstOrDefaultAsync() ?? new Store { Id = id};
34 | }
35 |
36 | public async Task Save(Store entity)
37 | {
38 | IMongoCollection storeCollection = mongoDbService.GetCollection();
39 |
40 | await storeCollection.InsertOneAsync(entity);
41 |
42 | return entity;
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/Src/PurchaseMicroservice/Purchase.QueryHandler/ProductPurchaseQueryHandler.cs:
--------------------------------------------------------------------------------
1 | namespace Purchase.QueryHandler
2 | {
3 | using Common.Core;
4 | using Purchase.Query;
5 | using Purchase.Repository;
6 | using System.Collections.Generic;
7 | using System.Threading.Tasks;
8 |
9 | public class ProductPurchaseQueryHandler : IQueryHandler
10 | {
11 | private readonly IPurchaseRepostiory purchaseRepository;
12 |
13 | public ProductPurchaseQueryHandler(IPurchaseRepostiory purchaseRepository)
14 | {
15 | this.purchaseRepository = purchaseRepository;
16 | }
17 |
18 | public async Task Handle(ProductPurchasedQuery query)
19 | {
20 | QueryResult queryResult = await ValidateQuery(query);
21 |
22 | if (!queryResult.Succeed)
23 | {
24 | return queryResult;
25 | }
26 |
27 | queryResult.Result = await purchaseRepository.SearchPurchases(query.DateFrom, query.DateTo, query.PageNumber, query.PageSize, query.SortFiled, query.SortDirection);
28 |
29 |
30 | return queryResult;
31 | }
32 |
33 | private Task ValidateQuery(ProductPurchasedQuery query)
34 | {
35 | var queryResult = new QueryResult();
36 |
37 | if (query.DateFrom > query.DateTo)
38 | {
39 | queryResult.Error = $"Sorry! DateFrom should not be greter than DateTo";
40 | }
41 |
42 | return Task.FromResult(queryResult);
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/Src/SalesMicroservice/SalesWebApi/Sales.Api.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp3.1
5 | 6f3f0e8f-fb88-4e5c-b9ef-0aa62f52e827
6 | Linux
7 | ..\..
8 |
9 |
10 |
11 |
12 | all
13 | runtime; build; native; contentfiles; analyzers; buildtransitive
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/Src/CommonAll/Common.Infrastructure/MongoService.cs:
--------------------------------------------------------------------------------
1 | namespace Common.Infrastructure
2 | {
3 | using Common.Core;
4 | using MongoDB.Driver;
5 | using System;
6 |
7 | public class MongoService : IMongoService
8 | {
9 | private readonly MongoUrlBuilder mongoUrlBuilder;
10 |
11 | public MongoService(string connectionUrl)
12 | {
13 | this.mongoUrlBuilder = new MongoUrlBuilder(connectionUrl);
14 | }
15 |
16 | public IMongoCollection GetCollection()
17 | {
18 | string collectionName = $"{typeof(T).Name}s";
19 | var mongoClient = new MongoClient(mongoUrlBuilder.ToMongoUrl());
20 | IMongoDatabase mongoDatabase = mongoClient.GetDatabase(mongoUrlBuilder.DatabaseName);
21 | IMongoCollection collection = mongoDatabase.GetCollection(collectionName);
22 |
23 | return collection;
24 | }
25 |
26 | public IMongoCollection GetCollection(string collectionName, string databaseName)
27 | {
28 | var mongoClient = new MongoClient(mongoUrlBuilder.ToMongoUrl());
29 | IMongoDatabase mongoDatabase = mongoClient.GetDatabase(databaseName);
30 | IMongoCollection collection = mongoDatabase.GetCollection(collectionName);
31 |
32 | return collection;
33 | }
34 |
35 | public IMongoDatabase GetDatabase(string databaseName)
36 | {
37 | var mongoClient = new MongoClient(mongoUrlBuilder.ToMongoUrl());
38 | IMongoDatabase mongoDatabase = mongoClient.GetDatabase(databaseName);
39 |
40 | return mongoDatabase;
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/Src/SalesMicroservice/SalesWebApi/Controllers/SalesCommandController.cs:
--------------------------------------------------------------------------------
1 | namespace Sales.Api.Controllers
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Threading.Tasks;
7 | using Common.Core;
8 | using Microsoft.AspNetCore.Http;
9 | using Microsoft.AspNetCore.Mvc;
10 | using Sales.Command;
11 | using Sales.DTO;
12 |
13 | [Route("api/[controller]")]
14 | [ApiController]
15 | public class SalesCommandController : ControllerBase
16 | {
17 | private readonly ICommandBus commandBus;
18 |
19 | public SalesCommandController(ICommandBus commandBus)
20 | {
21 | this.commandBus = commandBus;
22 | }
23 |
24 | [HttpPost("sales")]
25 | public Task ProductSales([FromBody] SalesDTO salesDTO)
26 | {
27 | var salesCommand = new SalesCommand
28 | {
29 | SalesId = Guid.NewGuid().ToString(),
30 | SalesDate = salesDTO.SalesDate
31 | };
32 | foreach(SalesProductDTO productDTO in salesDTO.SalesProducts)
33 | {
34 | var product = new SalesProduct
35 | {
36 | ProductId = productDTO.ProductId,
37 | ProductName = productDTO.ProductName,
38 | UnitName = productDTO.UnitName,
39 | SalesUnitPrice = productDTO.UnitPrice,
40 | SalesQuantity = productDTO.Quantity
41 | };
42 | salesCommand.SalesProducts.Add(product);
43 | }
44 |
45 | return commandBus.Send(salesCommand);
46 | }
47 | }
48 | }
--------------------------------------------------------------------------------
/Src/InventoryMicroservice/InventoryCommandHandler/CreateStoreCommandHandler.cs:
--------------------------------------------------------------------------------
1 | namespace Inventory.CommandHandler
2 | {
3 | using Common.Core;
4 | using Inventory.Command;
5 | using Inventory.Domain;
6 | using Inventory.Repository;
7 | using System;
8 | using System.Threading.Tasks;
9 |
10 | public class CreateStoreCommandHandler : ICommandHandler
11 | {
12 | private readonly IStoreRepository storeRepository;
13 |
14 | public CreateStoreCommandHandler(IStoreRepository storeRepository)
15 | {
16 | this.storeRepository = storeRepository;
17 | }
18 |
19 | public async Task Handle(CreateStoreCommand command)
20 | {
21 | CommandResult commandResponse = ValidateCommand(command);
22 | if (!commandResponse.Succeed)
23 | {
24 | return commandResponse;
25 | }
26 | Store store = Map(command);
27 | await storeRepository.Save(store);
28 |
29 | return commandResponse;
30 | }
31 |
32 | private CommandResult ValidateCommand(CreateStoreCommand command)
33 | {
34 | var commandResponse = new CommandResult();
35 |
36 | if (string.IsNullOrEmpty(command.ManagerName))
37 | {
38 | commandResponse.Error = "Sorry! Manager name should not be empty.";
39 | }
40 |
41 | return commandResponse;
42 | }
43 |
44 | private Store Map(CreateStoreCommand command)
45 | {
46 | return new Store
47 | {
48 | Id = command.StoreId,
49 | Manager = command.ManagerName
50 | };
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/Src/PurchaseMicroservice/PurchaseCommandHandler/Purchase.CommandHandler.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.1
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | all
24 | runtime; build; native; contentfiles; analyzers; buildtransitive
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/Src/InventoryMicroservice/Inventory.EventHandler/Inventory.EventHandler/ProductPurchasedEventHandler.cs:
--------------------------------------------------------------------------------
1 | namespace Inventory.EventHandler
2 | {
3 | using Common.Core;
4 | using Common.Core.Events;
5 | using Inventory.Domain;
6 | using Inventory.Repository;
7 | using System.Threading.Tasks;
8 |
9 | public class ProductPurchasedEventHandler : IEventHandler
10 | {
11 | private readonly IStoreItemRepository storeItemRepository;
12 | private readonly IStoreRepository storeRepository;
13 |
14 | public ProductPurchasedEventHandler(IStoreItemRepository storeItemRepository, IStoreRepository storeRepository)
15 | {
16 | this.storeItemRepository = storeItemRepository;
17 | this.storeRepository = storeRepository;
18 | }
19 |
20 | public async Task Handle(ProductPurchasedEvent @event)
21 | {
22 | foreach (PurchasedLineItem purchasedItem in @event.LineItems)
23 | {
24 | StoreItem storeItem = await storeItemRepository.GetById(purchasedItem.ProductId);
25 |
26 | if (null == storeItem)
27 | {
28 | Store store = await storeRepository.GetById("S001");
29 |
30 | var newStoreItem = new StoreItem
31 | {
32 | Id = purchasedItem.ProductId,
33 | ItemName = purchasedItem.ProductName,
34 | Store = store,
35 | BalanceQuantity = purchasedItem.PurchasedQuantity
36 | };
37 |
38 | await storeItemRepository.Save(newStoreItem);
39 | }
40 | else
41 | {
42 | storeItem.BalanceQuantity += purchasedItem.PurchasedQuantity;
43 |
44 | await storeItemRepository.UpdateItem(storeItem);
45 | }
46 | }
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/Src/PurchaseMicroservice/PurchaseWebApi/Controllers/PurchaseCommandController.cs:
--------------------------------------------------------------------------------
1 | namespace Purchase.Api.Controllers
2 | {
3 | using Common.Core;
4 | using Microsoft.AspNetCore.Mvc;
5 | using Purchase.Command;
6 | using Purchase.DTO;
7 | using System;
8 | using System.Collections.Generic;
9 | using System.Threading.Tasks;
10 |
11 | [Route("api/[controller]")]
12 | [ApiController]
13 | public class PurchaseCommandController : ControllerBase
14 | {
15 | private readonly ICommandBus commandBus;
16 |
17 | public PurchaseCommandController(ICommandBus commandBus)
18 | {
19 | this.commandBus = commandBus;
20 | }
21 |
22 | [HttpPost("purchase")]
23 | public Task Purchase([FromBody] PurchaseDTO purchaseDTO)
24 | {
25 | var command = new PurchaseCommand
26 | {
27 | PurchaseId = Guid.NewGuid().ToString(),
28 | PurchaseDate = purchaseDTO.PurchaseDate
29 | };
30 | command.LineItems = new List();
31 |
32 | foreach (PurchaseItemDTO purchaseItemDTO in purchaseDTO.PurchaseItems ?? new List())
33 | {
34 | command.LineItems.Add(new LineItemCommand
35 | {
36 | ProductId = purchaseItemDTO.ProductId,
37 | ProductName = purchaseItemDTO.ProductName,
38 | PurchaseQuantity = purchaseItemDTO.Quantity,
39 | PurchaseUnitName = purchaseItemDTO.UnitName,
40 | PurchaseUnitPrice = purchaseItemDTO.UnitPrice
41 | });
42 | }
43 |
44 | return commandBus.Send(command);
45 | }
46 |
47 | [HttpPost("ping")]
48 | [HttpGet("ping")]
49 | public string Ping()
50 | {
51 | return new Random().Next().ToString();
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/Src/SalesMicroservice/Sales.Repository.Tests/SalesRepositoryTest.cs:
--------------------------------------------------------------------------------
1 | namespace Sales.Repository.Tests
2 | {
3 | using Common.Infrastructure;
4 | using FluentAssertions;
5 | using Sales.Domain;
6 | using System;
7 | using System.Threading.Tasks;
8 | using Xunit;
9 | using Sales = Domain.Sales;
10 |
11 | public class SalesRepositoryTest
12 | {
13 | private readonly SalesRepository salesRepository;
14 |
15 | public SalesRepositoryTest()
16 | {
17 | const string connectionUrl = "mongodb://localhost:27017/SalesDB";
18 | var mongoDbService = new MongoService(connectionUrl);
19 | this.salesRepository = new SalesRepository(mongoDbService);
20 | }
21 |
22 | [Fact]
23 | public async Task ShouldSaveSales()
24 | {
25 | var sales = new Sales
26 | {
27 | Id = Guid.NewGuid().ToString(),
28 | SalesDate = DateTime.UtcNow,
29 | };
30 |
31 | sales.SalesLineItems.Add(new SalesLineItem
32 | {
33 | ProductId = "P001",
34 | ProductName = "Product-P001",
35 | UnitName = "Piece",
36 | UnitSalePrice = 100,
37 | SalesQuantity = 10
38 | });
39 | sales.SalesLineItems.Add(new SalesLineItem
40 | {
41 | ProductId = "P002",
42 | ProductName = "Product-P002",
43 | UnitName = "Piece",
44 | UnitSalePrice = 200,
45 | SalesQuantity = 2
46 | });
47 |
48 | Sales resultSales = await salesRepository.Save(sales);
49 |
50 | resultSales.Should().NotBeNull();
51 | resultSales.SalesLineItems.Should().HaveCount(2);
52 | }
53 |
54 | [Fact]
55 | public async Task ShouldReturnSalesWhenValidId()
56 | {
57 | const string salesId = "6978887e-955f-4d38-9925-379348a29a8d";
58 |
59 | Sales sales = await salesRepository.GetById(salesId);
60 |
61 | sales.Should().NotBeNull();
62 | sales.Id.Should().BeEquivalentTo(salesId);
63 | }
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/Src/InventoryMicroservice/InventoryRepository/StoreItemRepository.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace Inventory.Repository
3 | {
4 | using Common.Core;
5 | using Inventory.Domain;
6 | using MongoDB.Driver;
7 | using System.Collections.Generic;
8 | using System.Threading.Tasks;
9 |
10 | public class StoreItemRepository : IStoreItemRepository
11 | {
12 | private readonly IMongoService mongoService;
13 |
14 | public StoreItemRepository(IMongoService mongoDbService)
15 | {
16 | this.mongoService = mongoDbService;
17 | }
18 |
19 | public async Task GetById(string id)
20 | {
21 | IMongoCollection storeItemCollection = mongoService.GetCollection();
22 |
23 | IAsyncCursor itemCursor = await storeItemCollection.FindAsync(item => item.Id.Equals(id));
24 |
25 | return await itemCursor.FirstOrDefaultAsync();
26 | }
27 |
28 | public async Task RemoveItem(string id)
29 | {
30 | IMongoCollection storeItemCollection = mongoService.GetCollection();
31 |
32 | await storeItemCollection.DeleteOneAsync(item => item.Id.Equals(id));
33 | }
34 |
35 | public async Task Save(StoreItem entity)
36 | {
37 | IMongoCollection storeItemCollection = mongoService.GetCollection();
38 |
39 | await storeItemCollection.InsertOneAsync(entity);
40 |
41 | return entity;
42 | }
43 |
44 | public async Task SaveItems(IEnumerable entities)
45 | {
46 | foreach (StoreItem item in entities)
47 | {
48 | await Save(item);
49 | }
50 | }
51 |
52 | public async Task UpdateItem(StoreItem entity)
53 | {
54 | IMongoCollection storeItemCollection = mongoService.GetCollection();
55 | FilterDefinition criterial = Builders.Filter.Eq(item => item.Id, entity.Id);
56 |
57 | await storeItemCollection.ReplaceOneAsync(criterial, entity);
58 |
59 | return entity;
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/Src/SalesMicroservice/SalesRepository/SalesRepository.cs:
--------------------------------------------------------------------------------
1 | namespace Sales.Repository
2 | {
3 | using Common.Core;
4 | using MongoDB.Driver;
5 | using Sales.DTO;
6 | using System;
7 | using System.Collections.Generic;
8 | using System.Threading.Tasks;
9 | using Sales = Domain.Sales;
10 | using System.Linq;
11 | using Sales.Domain;
12 |
13 | public class SalesRepository : ISalesRepository
14 | {
15 | private readonly IMongoService mongoDbService;
16 |
17 | public SalesRepository(IMongoService mongoDbService)
18 | {
19 | this.mongoDbService = mongoDbService;
20 | }
21 |
22 | public async Task GetById(string id)
23 | {
24 | IMongoCollection salesCollection = mongoDbService.GetCollection();
25 |
26 | IAsyncCursor salesCursor = await salesCollection.FindAsync(item => item.Id.Equals(id));
27 |
28 | return await salesCursor.FirstOrDefaultAsync();
29 | }
30 |
31 | public async Task Save(Sales entity)
32 | {
33 | IMongoCollection salesCollection = mongoDbService.GetCollection();
34 |
35 | await salesCollection.InsertOneAsync(entity);
36 |
37 | return entity;
38 | }
39 |
40 | public Task FindSoldProductInfo(string productId, DateTime dateFrom, DateTime dateTo)
41 | {
42 | var resultDic = new Dictionary();
43 | IMongoCollection salesCollection = mongoDbService.GetCollection();
44 | IEnumerable salesList = salesCollection.AsQueryable().Where(item => item.SalesDate >= dateFrom && item.SalesDate <= dateTo);
45 |
46 | long totalSalesQuantity = 0;
47 | string productName = string.Empty;
48 |
49 | foreach (Sales sales in salesList)
50 | {
51 | IEnumerable SalesLineItems = sales.SalesLineItems.Where(item => item.ProductId.Equals(productId));
52 |
53 | foreach (SalesLineItem item in SalesLineItems)
54 | {
55 | totalSalesQuantity += item.SalesQuantity;
56 | if (string.IsNullOrEmpty(productName))
57 | {
58 | productName = item.ProductName;
59 | }
60 | }
61 | }
62 |
63 | var proudctSalesDTO = new ProductSalesDTO
64 | {
65 | ProductId = productId,
66 | ProductName = productName,
67 | SalesQuantity = totalSalesQuantity
68 | };
69 |
70 | return Task.FromResult(proudctSalesDTO);
71 | }
72 |
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/Src/CommonAll/Common.Infrastructure.Tests/RabbitMqServiceBusTest.cs:
--------------------------------------------------------------------------------
1 | namespace Common.Infrastructure.Tests
2 | {
3 | using Common.Core;
4 | using Common.Core.Events;
5 | using FluentAssertions;
6 | using Microsoft.Extensions.DependencyInjection;
7 | using Moq;
8 | using Moq.Language.Flow;
9 | using RabbitMQ.Client;
10 | using System;
11 | using System.Collections.Generic;
12 | using System.Threading.Tasks;
13 | using Xunit;
14 |
15 | public class RabbitMqServiceBusTest
16 | {
17 | private readonly MessageBrokerSettings rabbitMqSettings;
18 | private readonly EventBus rabbitMqServiceBus;
19 | private const string QueueName = "product-purchased";
20 |
21 | public RabbitMqServiceBusTest()
22 | {
23 | rabbitMqSettings = new MessageBrokerSettings
24 | {
25 | Host = "127.0.0.1",
26 | Port = 5672,
27 | UserId = "guest",
28 | Password = "guest"
29 | };
30 |
31 | var serviceProvider = new Mock();
32 | serviceProvider.Setup(srv => srv.GetService(typeof(MessageBrokerSettings))).Returns(rabbitMqSettings);
33 | serviceProvider.Setup(srv => srv.GetService(typeof(ISerializer))).Returns(new JsonSerializer());
34 | serviceProvider.Setup(item => item.GetService(typeof(IEventHandler)))
35 | .Returns(new PurchaseEventHandler());
36 |
37 | rabbitMqServiceBus = new EventBus(serviceProvider.Object);
38 | }
39 |
40 | [Fact]
41 | public async Task ShouldPublishMessageWhenValidQueueProvided()
42 | {
43 | var lineItems = new List
44 | {
45 | new PurchasedLineItem{ProductId = Guid.NewGuid().ToString(), PurchasedUnitPrice = 100, PurchasedQuantity = 100},
46 | new PurchasedLineItem{ProductId = Guid.NewGuid().ToString(), PurchasedUnitPrice = 200, PurchasedQuantity = 200},
47 | };
48 |
49 | var productPurchasedEvent = new ProductPurchasedEvent
50 | {
51 | PurchaseDate = DateTime.UtcNow,
52 | LineItems = lineItems
53 | };
54 |
55 | await rabbitMqServiceBus.Publish(QueueName, productPurchasedEvent);
56 | }
57 |
58 | [Fact]
59 | public async Task ShouldReceiveMessageWhenValidQueueProvided()
60 | {
61 | await rabbitMqServiceBus.Subscribe(QueueName);
62 |
63 | await Task.Delay(1000 * 3);
64 | }
65 | }
66 |
67 | public class PurchaseEventHandler : IEventHandler
68 | {
69 | public async Task Handle(ProductPurchasedEvent @event)
70 | {
71 | @event.Should().NotBeNull();
72 |
73 | await Task.CompletedTask;
74 | }
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/Src/PurchaseMicroservice/PurchaseRepository/PurchaseRepository.cs:
--------------------------------------------------------------------------------
1 | namespace Purchase.Repository
2 | {
3 | using Common.Core;
4 | using MongoDB.Driver;
5 | using Purchase.Domain.Model;
6 | using Purchase.DTO;
7 | using Purchase.Repository;
8 | using System;
9 | using System.Collections.Generic;
10 | using System.Linq;
11 | using System.Threading.Tasks;
12 |
13 | public class PurchaseRepository : IPurchaseRepostiory
14 | {
15 | private readonly IMongoService mongoDbService;
16 |
17 | public PurchaseRepository(IMongoService mongoDbService)
18 | {
19 | this.mongoDbService = mongoDbService;
20 | }
21 |
22 | public async Task GetById(string id)
23 | {
24 | IMongoCollection purchaseCollection = mongoDbService.GetCollection();
25 |
26 | IAsyncCursor purchaseCursor = await purchaseCollection.FindAsync(item => item.Id.Equals(id));
27 |
28 | return await purchaseCursor.FirstOrDefaultAsync();
29 | }
30 |
31 | public async Task Save(Purchase purchase)
32 | {
33 | IMongoCollection purchaseCollection = mongoDbService.GetCollection();
34 |
35 | await purchaseCollection.InsertOneAsync(purchase);
36 |
37 | return purchase;
38 | }
39 |
40 | public Task> SearchPurchases(DateTime from, DateTime to, int pageNumber, int pageSize, string sortField, int sortDirection)
41 | {
42 | IMongoCollection purchaseCollection = mongoDbService.GetCollection();
43 |
44 | int skip = (pageNumber - 1) * pageSize;
45 |
46 | IQueryable query = purchaseCollection.AsQueryable().Where(item => item.PurchaseDate >= from && item.PurchaseDate <= to);
47 |
48 | var orderBy = sortDirection == 0 ? query.OrderBy(item => sortField) : query.OrderByDescending(item => sortField);
49 |
50 | IEnumerable purchases = query.Skip(skip).Take(pageSize);
51 |
52 | IEnumerable productPurchasedDtoList = Map(purchases);
53 |
54 | return Task.FromResult(productPurchasedDtoList);
55 | }
56 |
57 | private IEnumerable Map(IEnumerable purchases)
58 | {
59 | var dtoList = new List();
60 |
61 | foreach (Purchase purchase in purchases)
62 | {
63 | foreach (ProductLineItem productLineItem in purchase.LineItems)
64 | {
65 | var productPurchasedDTO = new ProductPurchasedDTO
66 | {
67 | Date = purchase.PurchaseDate,
68 | ProductName = productLineItem.Product.ProductName,
69 | PurchasedQuantity = productLineItem.PurchaseQuantity,
70 | PurchasedAmount = productLineItem.PurchaseTotalPrice
71 | };
72 |
73 | dtoList.Add(productPurchasedDTO);
74 | }
75 | }
76 |
77 | return dtoList;
78 | }
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/Src/SalesMicroservice/SalesCommandHandler/SalesCommandHandler.cs:
--------------------------------------------------------------------------------
1 | namespace Sales.CommandHandler
2 | {
3 | using Common.Core;
4 | using Common.Core.Events;
5 | using Sales.Command;
6 | using Sales.Core;
7 | using Sales.Domain;
8 | using Sales.Repository;
9 | using System.Threading.Tasks;
10 | using Sales = Sales.Domain.Sales;
11 |
12 | public class SalesCommandHandler : ICommandHandler
13 | {
14 | private readonly ISalesRepository salesRepository;
15 | private readonly IEventBus eventBus;
16 |
17 | public SalesCommandHandler(ISalesRepository salesRepository, IEventBus eventBus)
18 | {
19 | this.salesRepository = salesRepository;
20 | this.eventBus = eventBus;
21 | }
22 |
23 | public async Task Handle(SalesCommand command)
24 | {
25 | CommandResult commandResult = await ValidateCommand(command);
26 | if (!commandResult.Succeed)
27 | {
28 | return commandResult;
29 | }
30 |
31 | Sales sales = Map(command);
32 | await salesRepository.Save(sales);
33 |
34 | ProductSoldEvent productSoldEvent = MapEvent(command);
35 | await eventBus.Publish(Constants.MessageQueue.SalesQueue, productSoldEvent);
36 |
37 | return commandResult;
38 |
39 | }
40 |
41 | private Task ValidateCommand(SalesCommand command)
42 | {
43 | var commandResult = new CommandResult();
44 |
45 | if (command.SalesProducts.Count == 0)
46 | {
47 | commandResult.Error = "Sorry! Atlease 1 item should be present";
48 | }
49 |
50 | return Task.FromResult(commandResult);
51 | }
52 |
53 | private Sales Map(SalesCommand command)
54 | {
55 | var sales = new Sales
56 | {
57 | Id = command.SalesId,
58 | SalesDate = command.SalesDate
59 | };
60 | foreach(SalesProduct product in command.SalesProducts)
61 | {
62 | var salesLineItem = new SalesLineItem
63 | {
64 | ProductId = product.ProductId,
65 | ProductName = product.ProductName,
66 | SalesQuantity = product.SalesQuantity,
67 | UnitName = product.UnitName,
68 | UnitSalePrice = product.SalesUnitPrice
69 | };
70 | sales.SalesLineItems.Add(salesLineItem);
71 | }
72 |
73 | return sales;
74 | }
75 |
76 | private ProductSoldEvent MapEvent(SalesCommand command)
77 | {
78 | var productSoldEvent = new ProductSoldEvent
79 | {
80 | SalesId = command.SalesId,
81 | SalesDate = command.SalesDate
82 | };
83 | foreach (SalesProduct product in command.SalesProducts)
84 | {
85 | var proudctSoldLineItem = new ProductSoldLineItem
86 | {
87 | ProductId = product.ProductId,
88 | ProductName = product.ProductName,
89 | SoldQuantity = product.SalesQuantity,
90 | SoldUnitPrice = product.SalesUnitPrice
91 | };
92 | productSoldEvent.ProductSoldLineItems.Add(proudctSoldLineItem);
93 | }
94 |
95 | return productSoldEvent;
96 | }
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/Src/SalesMicroservice/SalesWebApi/Startup.cs:
--------------------------------------------------------------------------------
1 | namespace SalesWebApi
2 | {
3 | using Common.Core;
4 | using Common.Infrastructure;
5 | using Microsoft.AspNetCore.Builder;
6 | using Microsoft.AspNetCore.Hosting;
7 | using Microsoft.Extensions.Configuration;
8 | using Microsoft.Extensions.DependencyInjection;
9 | using Microsoft.Extensions.Hosting;
10 | using Sales.Command;
11 | using Sales.CommandHandler;
12 | using Sales.Query;
13 | using Sales.QueryHandler;
14 | using Sales.Repository;
15 |
16 | public class Startup
17 | {
18 | private readonly IConfiguration configRoot;
19 |
20 | public Startup(IConfiguration configRoot)
21 | {
22 | this.configRoot = configRoot;
23 | }
24 |
25 | public void ConfigureServices(IServiceCollection services)
26 | {
27 | services.AddMvc();
28 | services.AddControllers();
29 |
30 | RegisterServices(services);
31 | }
32 |
33 | public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
34 | {
35 | if (env.IsDevelopment())
36 | {
37 | app.UseDeveloperExceptionPage();
38 | }
39 |
40 | app.UseRouting();
41 |
42 | app.UseEndpoints(endpoints =>
43 | {
44 | endpoints.MapDefaultControllerRoute();
45 | });
46 | }
47 |
48 | private void RegisterServices(IServiceCollection services)
49 | {
50 | var fi = new System.IO.FileInfo(@$"{System.IO.Directory.GetCurrentDirectory()}\appsettings.json");
51 | var ff = fi.OpenText().ReadToEnd();
52 |
53 | RegisterHelperServices(services);
54 | RegisterBuses(services);
55 | RegisterCommandHandlers(services);
56 | RegisterEventHandlers(services);
57 | RegisterQueryHandlers(services);
58 | RegisterRepositories(services);
59 |
60 | }
61 |
62 | private void RegisterHelperServices(IServiceCollection services)
63 | {
64 | var rabbitMqSettings = new MessageBrokerSettings
65 | {
66 | Host = "127.0.0.1",
67 | Port = 5672,
68 | UserId = "guest",
69 | Password = "guest"
70 | };
71 | services.AddSingleton(rabbitMqSettings);
72 | services.AddSingleton(new MongoService(configRoot.GetConnectionString("Default")));
73 |
74 | services.AddSingleton();
75 | }
76 |
77 | private void RegisterBuses(IServiceCollection services)
78 | {
79 | services.AddSingleton();
80 | services.AddSingleton();
81 | services.AddSingleton();
82 | }
83 |
84 | private void RegisterCommandHandlers(IServiceCollection services)
85 | {
86 | services.AddSingleton, SalesCommandHandler>();
87 | }
88 |
89 | private void RegisterEventHandlers(IServiceCollection services)
90 | {
91 | }
92 |
93 | private void RegisterQueryHandlers(IServiceCollection services)
94 | {
95 | services.AddSingleton, SalesQueryHandler>();
96 | }
97 |
98 | private void RegisterRepositories(IServiceCollection services)
99 | {
100 | services.AddSingleton();
101 | }
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/Src/InventoryMicroservice/InventoryWebApi/Startup.cs:
--------------------------------------------------------------------------------
1 | namespace Inventory.Api
2 | {
3 | using Common.Core;
4 | using Common.Core.Events;
5 | using Common.Infrastructure;
6 | using Inventory.Command;
7 | using Inventory.CommandHandler;
8 | using Inventory.EventHandler;
9 | using Inventory.Query;
10 | using Inventory.QueryHandler;
11 | using Inventory.Repository;
12 | using Microsoft.AspNetCore.Builder;
13 | using Microsoft.AspNetCore.Hosting;
14 | using Microsoft.Extensions.Configuration;
15 | using Microsoft.Extensions.DependencyInjection;
16 | using Microsoft.Extensions.Hosting;
17 | using System.Threading.Tasks;
18 |
19 | public class Startup
20 | {
21 | public IConfiguration Configuration { get; private set; }
22 |
23 | public Startup(IConfiguration configRoot)
24 | {
25 | this.Configuration = configRoot;
26 | }
27 |
28 | public void ConfigureServices(IServiceCollection services)
29 | {
30 | services.AddMvc();
31 | services.AddControllers();
32 | RegisterServices(services);
33 | }
34 |
35 | public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
36 | {
37 | if (env.IsDevelopment())
38 | {
39 | app.UseDeveloperExceptionPage();
40 | }
41 |
42 | app.UseRouting();
43 |
44 | app.UseEndpoints(endpoints =>
45 | {
46 | endpoints.MapDefaultControllerRoute();
47 | });
48 | }
49 |
50 | private void RegisterServices(IServiceCollection services)
51 | {
52 | RegisterHelperServices(services);
53 | RegisterCommandHanders(services);
54 | RegisterQueryHandlers(services);
55 | RegisterEventHandlers(services);
56 | RegisterRepositories(services);
57 | RegisterBuses(services).Wait();
58 | }
59 |
60 | private void RegisterHelperServices(IServiceCollection services)
61 | {
62 | var rabbitMqSettings = new MessageBrokerSettings
63 | {
64 | Host = "127.0.0.1",
65 | Port = 5672,
66 | UserId = "guest",
67 | Password = "guest"
68 | };
69 | services.AddSingleton(rabbitMqSettings);
70 | services.AddSingleton(new MongoService(Configuration.GetConnectionString("Default")));
71 | services.AddSingleton();
72 | }
73 |
74 | private async Task RegisterBuses(IServiceCollection services)
75 | {
76 | services.AddSingleton();
77 | services.AddSingleton();
78 |
79 | var eventBus = new EventBus(services.BuildServiceProvider());
80 | await eventBus.Subscribe(Constants.MessageQueue.PurchaseQueue);
81 | await eventBus.Subscribe(Constants.MessageQueue.SalesQueue);
82 | services.AddSingleton(eventBus);
83 | }
84 |
85 | private void RegisterCommandHanders(IServiceCollection services)
86 | {
87 | services.AddSingleton, CreateStoreCommandHandler>();
88 | }
89 |
90 | private void RegisterQueryHandlers(IServiceCollection services)
91 | {
92 | services.AddSingleton, StoreQueryHandler>();
93 | }
94 |
95 | private void RegisterEventHandlers(IServiceCollection services)
96 | {
97 | services.AddSingleton, ProductPurchasedEventHandler>();
98 | services.AddSingleton, ProductSoldEventHandler>();
99 | }
100 |
101 | private void RegisterRepositories(IServiceCollection services)
102 | {
103 | services.AddSingleton();
104 | services.AddSingleton();
105 | }
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/Src/PurchaseMicroservice/PurchaseWebApi/Startup.cs:
--------------------------------------------------------------------------------
1 | namespace Purchase.Api
2 | {
3 | using Common.Core;
4 | using Common.Infrastructure;
5 | using Microsoft.AspNetCore.Builder;
6 | using Microsoft.AspNetCore.Hosting;
7 | using Microsoft.Extensions.Configuration;
8 | using Microsoft.Extensions.DependencyInjection;
9 | using Microsoft.Extensions.Hosting;
10 | using Purchase.Command;
11 | using Purchase.CommandHandler;
12 | using Purchase.Query;
13 | using Purchase.QueryHandler;
14 | using Purchase.Repository;
15 | using System;
16 |
17 | public class Startup
18 | {
19 | private readonly IConfiguration configRoot;
20 |
21 | public Startup(IConfiguration configRoot)
22 | {
23 | this.configRoot = configRoot;
24 | }
25 |
26 | public void ConfigureServices(IServiceCollection services)
27 | {
28 | services.AddMvc();
29 | services.AddControllers();
30 | services.AddHttpClient();
31 |
32 | RegisterServices(services);
33 | }
34 |
35 | public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
36 | {
37 | if (env.IsDevelopment())
38 | {
39 | app.UseDeveloperExceptionPage();
40 | }
41 |
42 | app.UseRouting();
43 |
44 | app.UseEndpoints(endpoints =>
45 | {
46 | endpoints.MapControllerRoute(
47 | name: "default",
48 | pattern: "{controller}/{action}/{id?}");
49 | });
50 | }
51 |
52 | private void RegisterServices(IServiceCollection serviceCollection)
53 | {
54 | RegisterHelperServices(serviceCollection);
55 | RegisterBuses(serviceCollection);
56 | RegisterCommandHandlers(serviceCollection);
57 | RegisterQueryHandlers(serviceCollection);
58 | RegisterEventHanders(serviceCollection);
59 | RegisterRepositories(serviceCollection);
60 | }
61 |
62 | private void RegisterRepositories(IServiceCollection services)
63 | {
64 | services.AddSingleton();
65 | }
66 |
67 | private void RegisterCommandHandlers(IServiceCollection services)
68 | {
69 | services.AddSingleton, PurchaseCommandHandler>();
70 | }
71 |
72 | private void RegisterQueryHandlers(IServiceCollection services)
73 | {
74 | services.AddSingleton, ProductPurchaseQueryHandler>();
75 | }
76 |
77 | private void RegisterEventHanders(IServiceCollection services)
78 | {
79 |
80 | }
81 |
82 | private void RegisterBuses(IServiceCollection services)
83 | {
84 | services.AddSingleton();
85 | services.AddSingleton();
86 | services.AddSingleton();
87 | }
88 |
89 | private void RegisterHelperServices(IServiceCollection services)
90 | {
91 | services.AddSingleton(item =>
92 | {
93 | string connectionString = configRoot.GetConnectionString("default");
94 | return new MongoService(connectionString);
95 | });
96 |
97 | services.AddSingleton();
98 |
99 | services.AddSingleton(item =>
100 | {
101 | IConfigurationSection emailSettings = configRoot.GetSection("EmailSettings");
102 | var settings = new EmailSettings
103 | {
104 | Host = emailSettings["Host"],
105 | Port = int.Parse(emailSettings["Port"]),
106 | UserId = emailSettings["UserId"],
107 | Password = emailSettings["Password"]
108 | };
109 | return new EmailService(settings);
110 | });
111 |
112 | var rabbitMqSettings = new MessageBrokerSettings
113 | {
114 | Host = "127.0.0.1",
115 | Port = 5672,
116 | UserId = "guest",
117 | Password = "guest"
118 | };
119 | services.AddSingleton(rabbitMqSettings);
120 | }
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/Src/CommonAll/Common.Infrastructure/EventBus.cs:
--------------------------------------------------------------------------------
1 | namespace Common.Infrastructure
2 | {
3 | using Common.Core;
4 | using Microsoft.Extensions.DependencyInjection;
5 | using RabbitMQ.Client;
6 | using RabbitMQ.Client.Events;
7 | using System;
8 | using System.Text;
9 | using System.Threading.Tasks;
10 |
11 | ///
12 | /// RabbitMQ implementaiton
13 | ///
14 | public class EventBus : IEventBus
15 | {
16 | private readonly IServiceProvider serviceProvider;
17 | private readonly IConnection connection;
18 | private readonly IModel channel;
19 | private readonly EventingBasicConsumer consumer;
20 |
21 | public EventBus(IServiceProvider serviceProvider)
22 | {
23 | this.serviceProvider = serviceProvider;
24 |
25 | ConnectionFactory connectionFactory = CreateRabbitMqConnectionFactory();
26 | connection = connectionFactory.CreateConnection();
27 | channel = connection.CreateModel();
28 | consumer = new EventingBasicConsumer(channel);
29 | }
30 |
31 | public async Task Publish(string queue, T @event) where T : IEvent
32 | {
33 | var serializer = serviceProvider.GetRequiredService();
34 | string json = await serializer.Serialize(@event);
35 | byte[] messageBytes = Encoding.UTF8.GetBytes(json);
36 |
37 | await PublishInner(queue, messageBytes);
38 | }
39 |
40 | public async Task Subscribe(string queue) where T : IEvent
41 | {
42 | await SubscribeInner(channel, queue);
43 | }
44 |
45 | private Task PublishInner(string queue, byte[] messageBytes)
46 | {
47 | string exchangeName = CreateExchangeName(queue);
48 | string queueName = CreateQueueName(queue);
49 |
50 | channel.ExchangeDeclare(exchangeName, "fanout");
51 | channel.QueueDeclare(queueName, true, false, false, null);
52 | channel.QueueBind(queueName, exchangeName, queueName);
53 |
54 | channel.BasicPublish(exchangeName, queueName, null, messageBytes);
55 |
56 | return Task.CompletedTask;
57 | }
58 |
59 | private Task SubscribeInner(IModel channel, string queue) where T:IEvent
60 | {
61 | string queueName = CreateQueueName(queue);
62 | string exchangeName = CreateExchangeName(queue);
63 |
64 | channel.ExchangeDeclare(exchangeName, "fanout");
65 | channel.QueueDeclare(queueName, true, false, false, null);
66 | channel.QueueBind(queueName, exchangeName, queueName);
67 |
68 | consumer.Received += async (sender, e) =>
69 | {
70 | byte[] bytes = e.Body.ToArray();
71 | string messageJson = Encoding.UTF8.GetString(bytes);
72 | var serializer = serviceProvider.GetRequiredService();
73 | T messageObject = await serializer.Decerialize(messageJson);
74 | var eventHandler = serviceProvider.GetService>();
75 |
76 | await eventHandler.Handle(messageObject);
77 | };
78 |
79 | channel.BasicConsume(queue: queueName, autoAck: true, consumer: consumer);
80 |
81 | return Task.CompletedTask;
82 | }
83 |
84 | private ConnectionFactory CreateRabbitMqConnectionFactory()
85 | {
86 | var settings = serviceProvider.GetRequiredService();
87 |
88 | return new ConnectionFactory
89 | {
90 | HostName = settings.Host,
91 | Port = settings.Port,
92 | UserName = settings.UserId,
93 | Password = settings.Password
94 | };
95 | }
96 |
97 | ///
98 | /// Modifed Queue name
99 | ///
100 | ///
101 | ///
102 | private string CreateQueueName(string queueName)
103 | {
104 | return $"{queueName}-queue";
105 | }
106 |
107 | ///
108 | /// Create exchange name from QueueName
109 | ///
110 | ///
111 | ///
112 | private string CreateExchangeName(string queueName)
113 | {
114 | return $"{queueName}-exchange";
115 | }
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.userosscache
8 | *.sln.docstates
9 |
10 | # User-specific files (MonoDevelop/Xamarin Studio)
11 | *.userprefs
12 |
13 | # Build results
14 | [Dd]ebug/
15 | [Dd]ebugPublic/
16 | [Rr]elease/
17 | [Rr]eleases/
18 | x64/
19 | x86/
20 | bld/
21 | [Bb]in/
22 | [Oo]bj/
23 | [Ll]og/
24 | *.cache
25 | # Visual Studio 2015 cache/options directory
26 | src/.vs/
27 | # Uncomment if you have tasks that create the project's static files in wwwroot
28 | #wwwroot/
29 |
30 | # MSTest test Results
31 | [Tt]est[Rr]esult*/
32 | [Bb]uild[Ll]og.*
33 |
34 | # NUNIT
35 | *.VisualState.xml
36 | TestResult.xml
37 |
38 | # Build Results of an ATL Project
39 | [Dd]ebugPS/
40 | [Rr]eleasePS/
41 | dlldata.c
42 |
43 | # DNX
44 | project.lock.json
45 | project.fragment.lock.json
46 | artifacts/
47 |
48 | *_i.c
49 | *_p.c
50 | *_i.h
51 | *.ilk
52 | *.meta
53 | *.obj
54 | *.pch
55 | *.pdb
56 | *.pgc
57 | *.pgd
58 | *.rsp
59 | *.sbr
60 | *.tlb
61 | *.tli
62 | *.tlh
63 | *.tmp
64 | *.tmp_proj
65 | *.log
66 | *.vspscc
67 | *.vssscc
68 | .builds
69 | *.pidb
70 | *.svclog
71 | *.scc
72 | *.cache
73 |
74 | # Chutzpah Test files
75 | _Chutzpah*
76 |
77 | # Visual C++ cache files
78 | ipch/
79 | *.aps
80 | *.ncb
81 | *.opendb
82 | *.opensdf
83 | *.sdf
84 | *.cachefile
85 | *.VC.db
86 | *.VC.VC.opendb
87 |
88 | # Visual Studio profiler
89 | *.psess
90 | *.vsp
91 | *.vspx
92 | *.sap
93 |
94 | # TFS 2012 Local Workspace
95 | $tf/
96 |
97 | # Guidance Automation Toolkit
98 | *.gpState
99 |
100 | # ReSharper is a .NET coding add-in
101 | _ReSharper*/
102 | *.[Rr]e[Ss]harper
103 | *.DotSettings.user
104 |
105 | # JustCode is a .NET coding add-in
106 | .JustCode
107 |
108 | # TeamCity is a build add-in
109 | _TeamCity*
110 |
111 | # DotCover is a Code Coverage Tool
112 | *.dotCover
113 |
114 | # NCrunch
115 | _NCrunch_*
116 | .*crunch*.local.xml
117 | nCrunchTemp_*
118 |
119 | # MightyMoose
120 | *.mm.*
121 | AutoTest.Net/
122 |
123 | # Web workbench (sass)
124 | .sass-cache/
125 |
126 | # Installshield output folder
127 | [Ee]xpress/
128 |
129 | # DocProject is a documentation generator add-in
130 | DocProject/buildhelp/
131 | DocProject/Help/*.HxT
132 | DocProject/Help/*.HxC
133 | DocProject/Help/*.hhc
134 | DocProject/Help/*.hhk
135 | DocProject/Help/*.hhp
136 | DocProject/Help/Html2
137 | DocProject/Help/html
138 |
139 | # Click-Once directory
140 | publish/
141 |
142 | # Publish Web Output
143 | *.[Pp]ublish.xml
144 | *.azurePubxml
145 | # TODO: Comment the next line if you want to checkin your web deploy settings
146 | # but database connection strings (with potential passwords) will be unencrypted
147 | #*.pubxml
148 | *.publishproj
149 |
150 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
151 | # checkin your Azure Web App publish settings, but sensitive information contained
152 | # in these scripts will be unencrypted
153 | PublishScripts/
154 |
155 | # NuGet Packages
156 | *.nupkg
157 | # The packages folder can be ignored because of Package Restore
158 | **/packages/*
159 | # except build/, which is used as an MSBuild target.
160 | !**/packages/build/
161 | # Uncomment if necessary however generally it will be regenerated when needed
162 | #!**/packages/repositories.config
163 | # NuGet v3's project.json files produces more ignoreable files
164 | *.nuget.props
165 | *.nuget.targets
166 |
167 | # Microsoft Azure Build Output
168 | csx/
169 | *.build.csdef
170 |
171 | # Microsoft Azure Emulator
172 | ecf/
173 | rcf/
174 |
175 | # Windows Store app package directories and files
176 | AppPackages/
177 | BundleArtifacts/
178 | Package.StoreAssociation.xml
179 | _pkginfo.txt
180 |
181 | # Visual Studio cache files
182 | # files ending in .cache can be ignored
183 | *.[Cc]ache
184 | # but keep track of directories ending in .cache
185 | !*.[Cc]ache/
186 |
187 | # Others
188 | ClientBin/
189 | ~$*
190 | *~
191 | *.dbmdl
192 | *.dbproj.schemaview
193 | *.jfm
194 | *.pfx
195 | *.publishsettings
196 | node_modules/
197 | orleans.codegen.cs
198 |
199 | # Since there are multiple workflows, uncomment next line to ignore bower_components
200 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
201 | #bower_components/
202 |
203 | # RIA/Silverlight projects
204 | Generated_Code/
205 |
206 | # Backup & report files from converting an old project file
207 | # to a newer Visual Studio version. Backup files are not needed,
208 | # because we have git ;-)
209 | _UpgradeReport_Files/
210 | Backup*/
211 | UpgradeLog*.XML
212 | UpgradeLog*.htm
213 |
214 | # SQL Server files
215 | *.mdf
216 | *.ldf
217 |
218 | # Business Intelligence projects
219 | *.rdl.data
220 | *.bim.layout
221 | *.bim_*.settings
222 |
223 | # Microsoft Fakes
224 | FakesAssemblies/
225 |
226 | # GhostDoc plugin setting file
227 | *.GhostDoc.xml
228 |
229 | # Node.js Tools for Visual Studio
230 | .ntvs_analysis.dat
231 |
232 | # Visual Studio 6 build log
233 | *.plg
234 |
235 | # Visual Studio 6 workspace options file
236 | *.opt
237 |
238 | # Visual Studio LightSwitch build output
239 | **/*.HTMLClient/GeneratedArtifacts
240 | **/*.DesktopClient/GeneratedArtifacts
241 | **/*.DesktopClient/ModelManifest.xml
242 | **/*.Server/GeneratedArtifacts
243 | **/*.Server/ModelManifest.xml
244 | _Pvt_Extensions
245 |
246 | # Paket dependency manager
247 | .paket/paket.exe
248 | paket-files/
249 |
250 | # FAKE - F# Make
251 | .fake/
252 |
253 | # JetBrains Rider
254 | .idea/
255 | *.sln.iml
256 |
257 | # CodeRush
258 | .cr/
259 |
260 | # Python Tools for Visual Studio (PTVS)
261 | __pycache__/
262 | *.pyc
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # TheMicroServices
2 |
3 | Demonastrate Event Driven Microservice based architecture.
4 |
5 |
6 | ## Domain:
7 |
8 | Borrowed 3 Boundned context from ERP:
9 |
10 | 1. **Purchase**: User can purchase Item. Purchase department store that purchased item information.
11 | 2. **Sales**: After saling items, user can store sales information
12 | 3. **Inventory**: When any purchase or Sales occured, Stock will be automatically updated.
13 |
14 |
15 | ## Architecture:
16 |
17 | System is consist of 3 Microservices:
18 |
19 | * **Purchase Microservice**: This microservice is responsible to manage Purchase related informtion and raised an event after purchase done. Based on the event,
20 | consumer will be updated accordingly.
21 |
22 | * **Sales Microservice**: This microservice is responsible to manage Sales related information. When any sales happend it will raised an event so that its interested
23 | party can update and act accordingly.
24 |
25 | * **Inventory Microservice**: This microservice is responsible to manage Products and also when any purchase or sales happended it will update stock based on their raised events.
26 |
27 | * **CQRS**: CQRS is implemented inside Microservices.
28 |
29 | * **Nothing shared architecture**. Every Microservice has its own database.
30 |
31 |
32 | Here, I have shouwn 3 ways to communicate Microservice to Microservice communication:
33 |
34 | * **Event Driven**: Any microservice Publish events to the Message Queue. Other Microservices subscribe those events and act accordingly.
35 | * **REST**: Not recommended approach. But showing here as an example. One Microservice Directly call other Micrservice to the REST way.
36 | * **GRPC**: Recommended approach for now a days. It is very similar like old Remote Procedure Call(RPC).
37 |
38 |
39 | #### High Level Design:
40 |
41 | 
42 |
43 | #### Command/Query Segrigation:
44 |
45 | * In CQRS command and query are two distinct parts. Here Read Model and Write Model are different.
46 | * Command execution change the application state. So command execution flows are risky by nature and very carefully need to implement.
47 | * Query execution does not change anything just read the data. So little relux but if application contain sensitive data than
48 | it might be risky too.
49 |
50 | 
51 |
52 |
53 | ## Event Driven Architecture:
54 |
55 | It is difference than traditional Request driven model. In event driven architecture one system emit events, other systems
56 | capture those events and react accordingly. The system communicate, processing based on event flows. Someone called
57 | it as Publisher subscriber Model.
58 |
59 | 
60 |
61 | ## CAP theorem:
62 |
63 | It is also called brewer's theorem. It says whether any distributed system either achieve at most 2 out of 3 (It is actually proved).By cleaverly design so many systems in real world, if has achieved all 3 based on some tricks or you can say made balanced between them. It is business decission rather technical decission.
64 |
65 | #### 3 Parts are:
66 | * **C**onsistency: All clients must see the same data from all differnce places.
67 | * **A**vailability: When any client requests for data, he/she can get data immediately, event 1 or 2 or mnore nodes are down.
68 | * **P**artitioning: ommunication break within a distributed system.
69 |
70 | 
71 |
72 | ## Eventual Consistency:
73 |
74 | It name described data is replicated other sources gradually. It is weekest consistency but many benifits, one of is easy scaling & best performace. For that reason many distributed system
75 | use this and sacrifice strong consistency. Its sequence is:
76 | **1**. Write node-1 from client
77 | **2**. Acknoledge to client from node-1
78 | **3**. Eventual write propagates other nodes via cluster.
79 |
80 | 
81 |
82 | ## Circuit Breaker/Retry Policy
83 |
84 | Circuit breaker and retry policy are two important things in Microservice world. Here It assume that network is unreliable and may lost its
85 | connection any time. It is a major issue here. So solve this issue and build a system resilece 2 patters play important role.
86 |
87 | * **Retry Policy**: Allow how many times (after time interval) a service call.
88 |
89 | * **Circuit Breaker Policy**: Idea is very simple. We should wrap any function with Circuit breaker object and circuit breaker object monitor its failure.
90 | When failure happend at cirtain time interval, circuit breaker trips all futher call with a error message. It has 3 states:
91 |
92 | * **i)Open**: Returns an error for calls without executing functions.
93 | * **ii)Closed**: Call all the services.
94 | * **iii)Half-Open**: After timeperiod, any issue raised then check underlying problem still exists or not. Any single call failed half CB changed to half open state.
95 |
96 | 
97 |
98 | ## Technology Used:
99 |
100 | * C# Language
101 | * ASP.NET Core Framework.
102 | * RabbitMQ: Message Broker for event pub/sub feature.
103 | * MongoDB: NoSQL database (Prefefer NoSQL instead of SQL for better schemaless/scalability/speed etc.
104 | * Rest/GRPC: Service-to-service communication.
105 | * Polly: A Nuget package for setting Auto Retry Remote call settings.
106 | * TestHost: (Microsoft.AspNetCore.TestHost) for WebAPI integration test.
107 |
108 | ## Demonastration:
109 |
110 | * Synchronous Event Driven with Service Broker
111 | * CQRS
112 | * NOSQL
113 | * Service to Service communication with REST with Retry Policy
114 | * Service to Service communication with GRPC with Circuit Breaker Policy
115 | * Web API service Integration Test
116 |
--------------------------------------------------------------------------------
/Src/PurchaseMicroservice/PurchaseCommandHandler/PurchaseCommandHandler.cs:
--------------------------------------------------------------------------------
1 | namespace Purchase.CommandHandler
2 | {
3 | using Common.Core;
4 | using Common.Core.Events;
5 | using Grpc.Core;
6 | using Grpc.Net.Client;
7 | using Inventory.Api.Grpc;
8 | using Polly;
9 | using Polly.CircuitBreaker;
10 | using Polly.Retry;
11 | using Purchase.Command;
12 | using Purchase.Core;
13 | using Purchase.Domain.Model;
14 | using Purchase.Repository;
15 | using System;
16 | using System.Diagnostics;
17 | using System.Linq;
18 | using System.Net.Http;
19 | using System.Threading.Tasks;
20 | using static Inventory.Api.Grpc.InventoryServiceProvider;
21 |
22 | public class PurchaseCommandHandler : ICommandHandler
23 | {
24 | private readonly IPurchaseRepostiory purchaseRepository;
25 | private readonly IEventBus serviceBus;
26 | private readonly IEmailService emailService;
27 | private IHttpClientFactory httpClientFactory;
28 | private AsyncCircuitBreakerPolicy circuitAsyncBreakerPolicy;
29 |
30 | public PurchaseCommandHandler(IPurchaseRepostiory purchaseRepository, IEventBus serviceBus, IEmailService emailService,
31 | IHttpClientFactory httpClientFactory)
32 | {
33 | this.purchaseRepository = purchaseRepository;
34 | this.serviceBus = serviceBus;
35 | this.emailService = emailService;
36 | this.httpClientFactory = httpClientFactory;
37 |
38 | // Circuit breaker policy defined
39 | circuitAsyncBreakerPolicy = Policy
40 | .Handle().CircuitBreakerAsync(2, TimeSpan.FromSeconds(15));
41 | }
42 |
43 | public async Task Handle(PurchaseCommand purchaseCommand)
44 | {
45 | CommandResult commandResponse = ValidateCommand(purchaseCommand);
46 | //if (!commandResponse.Succeed)
47 | //{
48 | // return commandResponse;
49 | //}
50 | //if (!await IsStoreServiceOn()) // REST call with auto retry policy
51 | //{
52 | // commandResponse.Error = "Sorry! Store Service is not On. You have to wait until it is open";
53 |
54 | // return commandResponse;
55 | //}
56 | if (await GetCurrentStoreItems() > 1000L) // GRPC call with Circuit breaker policy
57 | {
58 | commandResponse.Error = "Sorry! Current storeitems more than 1000. So no more purchase possible";
59 |
60 | return commandResponse;
61 | }
62 |
63 | Purchase purchase = Map(purchaseCommand);
64 | await purchaseRepository.Save(purchase);
65 |
66 | ProductPurchasedEvent productPurchasedEvent = Map(purchase);
67 | await serviceBus.Publish(Constants.MessageQueues.PurchasedQueue, productPurchasedEvent);
68 |
69 | EmailParams emailParams = BuildEmailParameters(productPurchasedEvent);
70 | await emailService.SendEmail(emailParams);
71 |
72 | return new CommandResult();
73 | }
74 |
75 | private CommandResult ValidateCommand(PurchaseCommand productPurchaseCommand)
76 | {
77 | var commandResponse = new CommandResult();
78 |
79 | if (null == productPurchaseCommand)
80 | {
81 | commandResponse.Error = "Sorry! Product Purchase Command should not be null.";
82 | }
83 | else if (productPurchaseCommand.LineItems == null || productPurchaseCommand.LineItems.Count == 0)
84 | {
85 | commandResponse.Error = "Sorry! Should have at least one Purchase Item.";
86 | }
87 |
88 | return commandResponse;
89 | }
90 |
91 | private Purchase Map(PurchaseCommand purchaseCommand)
92 | {
93 | var purchase = new Purchase
94 | {
95 | Id = purchaseCommand.PurchaseId,
96 | PurchaseDate = DateTime.UtcNow
97 | };
98 |
99 | foreach (LineItemCommand lineItemCommand in purchaseCommand.LineItems)
100 | {
101 | var productLineItem = new ProductLineItem
102 | {
103 | Product = new Product
104 | {
105 | Id = lineItemCommand.ProductId,
106 | ProductName = lineItemCommand.ProductName
107 | }
108 | };
109 | productLineItem.PurchaseUnitPrice = lineItemCommand.PurchaseUnitPrice;
110 | productLineItem.PurchaseQuantity = lineItemCommand.PurchaseQuantity;
111 |
112 | purchase.LineItems.Add(productLineItem);
113 | }
114 |
115 | return purchase;
116 | }
117 |
118 | private ProductPurchasedEvent Map(Purchase purchase)
119 | {
120 | var productPurchasedEvent = new ProductPurchasedEvent
121 | {
122 | PurchaseDate = purchase.PurchaseDate
123 | };
124 |
125 | foreach (ProductLineItem productLineItem in purchase.LineItems)
126 | {
127 | var lineItem = new PurchasedLineItem
128 | {
129 | ProductId = productLineItem.Product.Id,
130 | PurchasedUnitPrice = productLineItem.PurchaseUnitPrice,
131 | PurchasedQuantity = productLineItem.PurchaseQuantity
132 | };
133 | productPurchasedEvent.LineItems.Add(lineItem);
134 | }
135 |
136 | return productPurchasedEvent;
137 | }
138 |
139 | private EmailParams BuildEmailParameters(ProductPurchasedEvent @event)
140 | {
141 | long purchasedTotalPrice = 0;
142 |
143 | @event.LineItems.ToList().ForEach(item => purchasedTotalPrice += item.PurchaedTotalPrice);
144 |
145 | var emailParams = new EmailParams
146 | {
147 | Subject = "Product Purchased",
148 | Body = $"The Product Purchased Amount={purchasedTotalPrice}"
149 | };
150 |
151 | emailParams.ToList.Add(Constants.EmailAddressess.AdminPurchaseEmailAddress);
152 |
153 | return emailParams;
154 | }
155 |
156 | ///
157 | /// Implement Retry policy with REST call.
158 | /// Considering network is unreliable. so retry is needed.
159 | ///
160 | ///
161 | private async Task IsStoreServiceOn()
162 | {
163 | bool serviceOn = false;
164 | const string url = "http://localhost:4000/api/storequery/is-service-on";
165 | HttpClient httpClient = httpClientFactory.CreateClient();
166 |
167 | // Retry Policy Defined
168 | AsyncRetryPolicy retryPolicy
169 | = Policy.Handle().WaitAndRetryAsync(3, item => TimeSpan.FromSeconds(2));
170 | try
171 | {
172 | await retryPolicy.ExecuteAsync(async () =>
173 | {
174 | HttpResponseMessage response = await httpClient.GetAsync(url);
175 | response.EnsureSuccessStatusCode();
176 | serviceOn = await response.Content.ReadAsAsync();
177 | });
178 | }
179 | catch (HttpRequestException) { }
180 |
181 | return serviceOn;
182 | }
183 |
184 | ///
185 | /// GRPC Call with Circuit breaker policy
186 | ///
187 | ///
188 | private async Task GetCurrentStoreItems()
189 | {
190 | const string url = "https://localhost:7001";
191 | using GrpcChannel channel = GrpcChannel.ForAddress(url);
192 | var client = new InventoryServiceProviderClient(channel);
193 | var request = new ServiceRequest { StoreId = "S001" };
194 | long totalItems = 0L;
195 |
196 | try
197 | {
198 | await circuitAsyncBreakerPolicy.ExecuteAsync(async () =>
199 | {
200 | ServiceReplay replay = await client.CountTotalItemsAsync(request);
201 | totalItems = long.Parse(replay.ItemCount);
202 | });
203 | }
204 | catch(RpcException rEx)
205 | {
206 | Debug.WriteLine($"Grpc Exception:{rEx.Message}");
207 | await Task.Delay(1000);
208 | }
209 |
210 | return totalItems;
211 | }
212 | }
213 | }
214 |
--------------------------------------------------------------------------------
/Src/TheMicroservices.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.29613.14
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "PurchaseMicroservice", "PurchaseMicroservice", "{66EE5B92-EBBC-4F0A-A67F-232B0F1FA5C0}"
7 | EndProject
8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Purchase.Api", "PurchaseMicroservice\PurchaseWebApi\Purchase.Api.csproj", "{4A96FD48-1F32-4787-8914-CE61765E2D7B}"
9 | EndProject
10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Purchase.Command", "PurchaseMicroservice\PurchaseCommand\Purchase.Command.csproj", "{AB5DD339-5F31-4B97-B883-8D87119A4D9C}"
11 | EndProject
12 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Purchase.Query", "PurchaseMicroservice\PurchaseQuery\Purchase.Query.csproj", "{37C9ABAA-E217-43C1-9E78-D45B721DA6B7}"
13 | EndProject
14 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Purchase.Core", "PurchaseMicroservice\PurchaseCore\Purchase.Core.csproj", "{ADF5C5A0-292A-47E8-933D-0E49159ECF8A}"
15 | EndProject
16 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Purchase.Repository", "PurchaseMicroservice\PurchaseRepository\Purchase.Repository.csproj", "{1E5B4E96-249C-4239-81E1-ECC45EC1E84E}"
17 | EndProject
18 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Purchase.Domain", "PurchaseMicroservice\PurchaseDomain\Purchase.Domain.csproj", "{B73A83B8-8E52-4CBA-AA33-19073A170AE1}"
19 | EndProject
20 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Purchase.DTO", "PurchaseMicroservice\PurchaseDto\Purchase.DTO.csproj", "{3293F4D5-E1A8-46BA-A1B3-B06095D16FBA}"
21 | EndProject
22 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SalesMicroservice", "SalesMicroservice", "{B5EA3087-36A6-4F1B-B57D-B4A0439552AF}"
23 | EndProject
24 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "InventoryMicroservice", "InventoryMicroservice", "{A520C293-BEE3-463F-A448-488C5EC15D24}"
25 | EndProject
26 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Inventory.Api", "InventoryMicroservice\InventoryWebApi\Inventory.Api.csproj", "{039921D8-4248-4929-9600-F6794AEB46E0}"
27 | EndProject
28 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Inventory.Command", "InventoryMicroservice\InventoryCommand\Inventory.Command.csproj", "{2242FC5A-384D-4644-85C0-8D8AA1D7D2DB}"
29 | EndProject
30 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Inventory.CommandHandler", "InventoryMicroservice\InventoryCommandHandler\Inventory.CommandHandler.csproj", "{DCE0ABDE-C706-4357-B2C2-508E5E5E4028}"
31 | EndProject
32 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Inventory.Query", "InventoryMicroservice\InventoryQuery\Inventory.Query.csproj", "{F6BCF270-F199-4DD7-A1C3-D4132FDBDC03}"
33 | EndProject
34 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "InventoryQueryHandler", "InventoryMicroservice\InventoryQueryHandler\InventoryQueryHandler.csproj", "{495F1E24-3A2E-44D1-BE21-07ABAD784B22}"
35 | EndProject
36 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Inventory.Domain", "InventoryMicroservice\InventoryDomain\Inventory.Domain.csproj", "{8B8EEB17-30F9-40D5-9C6B-BB80E0C5E5CC}"
37 | EndProject
38 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Inventory.Repository", "InventoryMicroservice\InventoryRepository\Inventory.Repository.csproj", "{9F7C7EF9-DFE1-4CF1-BBA4-E76618D973E8}"
39 | EndProject
40 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Inventory.DTO", "InventoryMicroservice\InventoryDto\Inventory.DTO.csproj", "{2B8CA8C4-B09F-4161-9687-14CCC589D1F4}"
41 | EndProject
42 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sales.Api", "SalesMicroservice\SalesWebApi\Sales.Api.csproj", "{39EA2A18-2DD0-4C9D-988F-E61EF77ADF1A}"
43 | EndProject
44 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sales.Core", "SalesMicroservice\SalesCore\Sales.Core.csproj", "{59677058-994E-487E-B294-EE9C71DA96D2}"
45 | EndProject
46 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sales.Command", "SalesMicroservice\SalesCommand\Sales.Command.csproj", "{16A1506C-A00D-450F-8782-43060B8C240B}"
47 | EndProject
48 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sales.CommandHandler", "SalesMicroservice\SalesCommandHandler\Sales.CommandHandler.csproj", "{5B2200C9-36FE-4D5B-BA73-B0171FAE6A01}"
49 | EndProject
50 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sales.Query", "SalesMicroservice\SalesQuery\Sales.Query.csproj", "{165E63CF-5C74-4DF5-A4B1-5883ED032F2C}"
51 | EndProject
52 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sales.QueryHandler", "SalesMicroservice\SalesQueryHandler\Sales.QueryHandler.csproj", "{80F6E25B-6F22-4D14-9C0D-9C6AEF30A5D1}"
53 | EndProject
54 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sales.Domain", "SalesMicroservice\SalesDomain\Sales.Domain.csproj", "{6D8DC78C-F1D1-43E6-B1FC-3DA5AE1CF8D2}"
55 | EndProject
56 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sales.Repository", "SalesMicroservice\SalesRepository\Sales.Repository.csproj", "{3E5DC4CA-772C-4FAF-8B11-CC3AECE210E0}"
57 | EndProject
58 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sales.DTO", "SalesMicroservice\SalesDto\Sales.DTO.csproj", "{2A91ABB0-3955-4E08-8C20-6231A2D0F17D}"
59 | EndProject
60 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "CommonAll", "CommonAll", "{7A660546-3B3E-44B8-BF65-422CDA59BED4}"
61 | EndProject
62 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Purchase.CommandHandler", "PurchaseMicroservice\PurchaseCommandHandler\Purchase.CommandHandler.csproj", "{EF1FF2CC-BC36-497B-9D21-E0851909325F}"
63 | EndProject
64 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Common.Infrastructure", "CommonAll\Common.Infrastructure\Common.Infrastructure.csproj", "{72DAEC1C-873C-43BC-B027-9FD67AF7E4B8}"
65 | EndProject
66 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Common.Core", "CommonAll\Common.Core\Common.Core.csproj", "{B2ED16D4-F4CB-4B93-817C-C787213D8A6E}"
67 | EndProject
68 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Inventory.EventHandler", "InventoryMicroservice\Inventory.EventHandler\Inventory.EventHandler\Inventory.EventHandler.csproj", "{5028999F-F0EC-4421-A786-606372EC0B01}"
69 | EndProject
70 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Common.Infrastructure.Tests", "CommonAll\Common.Infrastructure.Tests\Common.Infrastructure.Tests.csproj", "{E17DA84E-69C1-4EB9-AC24-39A9605259EE}"
71 | EndProject
72 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Purchase.QueryHandler", "PurchaseMicroservice\Purchase.QueryHandler\Purchase.QueryHandler.csproj", "{0D327170-0673-4A43-8A29-07912377A898}"
73 | EndProject
74 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Common.Core.Tests", "CommonAll\Common.Core.Tests\Common.Core.Tests.csproj", "{DAE9ABA6-E347-4659-B579-D80A6AC2000E}"
75 | EndProject
76 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Inventory.QueryHandler", "InventoryMicroservice\Inventory.QueryHandler\Inventory.QueryHandler.csproj", "{1E79EA40-B395-4D11-AA12-A9ED08D18983}"
77 | EndProject
78 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sales.Repository.Tests", "SalesMicroservice\Sales.Repository.Tests\Sales.Repository.Tests.csproj", "{5D8E595F-6C68-47DE-9D1A-538AA6720A02}"
79 | EndProject
80 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Inventory.Api.Grpc", "InventoryMicroservice\Inventory.Api.Grpc\Inventory.Api.Grpc.csproj", "{E904AF5C-35A2-40F9-8EF2-0FDE5390D6F6}"
81 | EndProject
82 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Inventory.Api.Grpc.Tests", "InventoryMicroservice\Inventory.Api.Grpc.Tests\Inventory.Api.Grpc.Tests.csproj", "{F1BF0BC9-38BC-432B-AB28-4BF68A1A344C}"
83 | EndProject
84 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Inventory.Api.Tests", "InventoryMicroservice\Inventory.Api.Tests\Inventory.Api.Tests.csproj", "{FB7E260A-C146-40C3-BF7C-641BEF92A7A0}"
85 | EndProject
86 | Global
87 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
88 | Debug|Any CPU = Debug|Any CPU
89 | Release|Any CPU = Release|Any CPU
90 | EndGlobalSection
91 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
92 | {4A96FD48-1F32-4787-8914-CE61765E2D7B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
93 | {4A96FD48-1F32-4787-8914-CE61765E2D7B}.Debug|Any CPU.Build.0 = Debug|Any CPU
94 | {4A96FD48-1F32-4787-8914-CE61765E2D7B}.Release|Any CPU.ActiveCfg = Release|Any CPU
95 | {4A96FD48-1F32-4787-8914-CE61765E2D7B}.Release|Any CPU.Build.0 = Release|Any CPU
96 | {AB5DD339-5F31-4B97-B883-8D87119A4D9C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
97 | {AB5DD339-5F31-4B97-B883-8D87119A4D9C}.Debug|Any CPU.Build.0 = Debug|Any CPU
98 | {AB5DD339-5F31-4B97-B883-8D87119A4D9C}.Release|Any CPU.ActiveCfg = Release|Any CPU
99 | {AB5DD339-5F31-4B97-B883-8D87119A4D9C}.Release|Any CPU.Build.0 = Release|Any CPU
100 | {37C9ABAA-E217-43C1-9E78-D45B721DA6B7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
101 | {37C9ABAA-E217-43C1-9E78-D45B721DA6B7}.Debug|Any CPU.Build.0 = Debug|Any CPU
102 | {37C9ABAA-E217-43C1-9E78-D45B721DA6B7}.Release|Any CPU.ActiveCfg = Release|Any CPU
103 | {37C9ABAA-E217-43C1-9E78-D45B721DA6B7}.Release|Any CPU.Build.0 = Release|Any CPU
104 | {ADF5C5A0-292A-47E8-933D-0E49159ECF8A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
105 | {ADF5C5A0-292A-47E8-933D-0E49159ECF8A}.Debug|Any CPU.Build.0 = Debug|Any CPU
106 | {ADF5C5A0-292A-47E8-933D-0E49159ECF8A}.Release|Any CPU.ActiveCfg = Release|Any CPU
107 | {ADF5C5A0-292A-47E8-933D-0E49159ECF8A}.Release|Any CPU.Build.0 = Release|Any CPU
108 | {1E5B4E96-249C-4239-81E1-ECC45EC1E84E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
109 | {1E5B4E96-249C-4239-81E1-ECC45EC1E84E}.Debug|Any CPU.Build.0 = Debug|Any CPU
110 | {1E5B4E96-249C-4239-81E1-ECC45EC1E84E}.Release|Any CPU.ActiveCfg = Release|Any CPU
111 | {1E5B4E96-249C-4239-81E1-ECC45EC1E84E}.Release|Any CPU.Build.0 = Release|Any CPU
112 | {B73A83B8-8E52-4CBA-AA33-19073A170AE1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
113 | {B73A83B8-8E52-4CBA-AA33-19073A170AE1}.Debug|Any CPU.Build.0 = Debug|Any CPU
114 | {B73A83B8-8E52-4CBA-AA33-19073A170AE1}.Release|Any CPU.ActiveCfg = Release|Any CPU
115 | {B73A83B8-8E52-4CBA-AA33-19073A170AE1}.Release|Any CPU.Build.0 = Release|Any CPU
116 | {3293F4D5-E1A8-46BA-A1B3-B06095D16FBA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
117 | {3293F4D5-E1A8-46BA-A1B3-B06095D16FBA}.Debug|Any CPU.Build.0 = Debug|Any CPU
118 | {3293F4D5-E1A8-46BA-A1B3-B06095D16FBA}.Release|Any CPU.ActiveCfg = Release|Any CPU
119 | {3293F4D5-E1A8-46BA-A1B3-B06095D16FBA}.Release|Any CPU.Build.0 = Release|Any CPU
120 | {039921D8-4248-4929-9600-F6794AEB46E0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
121 | {039921D8-4248-4929-9600-F6794AEB46E0}.Debug|Any CPU.Build.0 = Debug|Any CPU
122 | {039921D8-4248-4929-9600-F6794AEB46E0}.Release|Any CPU.ActiveCfg = Release|Any CPU
123 | {039921D8-4248-4929-9600-F6794AEB46E0}.Release|Any CPU.Build.0 = Release|Any CPU
124 | {2242FC5A-384D-4644-85C0-8D8AA1D7D2DB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
125 | {2242FC5A-384D-4644-85C0-8D8AA1D7D2DB}.Debug|Any CPU.Build.0 = Debug|Any CPU
126 | {2242FC5A-384D-4644-85C0-8D8AA1D7D2DB}.Release|Any CPU.ActiveCfg = Release|Any CPU
127 | {2242FC5A-384D-4644-85C0-8D8AA1D7D2DB}.Release|Any CPU.Build.0 = Release|Any CPU
128 | {DCE0ABDE-C706-4357-B2C2-508E5E5E4028}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
129 | {DCE0ABDE-C706-4357-B2C2-508E5E5E4028}.Debug|Any CPU.Build.0 = Debug|Any CPU
130 | {DCE0ABDE-C706-4357-B2C2-508E5E5E4028}.Release|Any CPU.ActiveCfg = Release|Any CPU
131 | {DCE0ABDE-C706-4357-B2C2-508E5E5E4028}.Release|Any CPU.Build.0 = Release|Any CPU
132 | {F6BCF270-F199-4DD7-A1C3-D4132FDBDC03}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
133 | {F6BCF270-F199-4DD7-A1C3-D4132FDBDC03}.Debug|Any CPU.Build.0 = Debug|Any CPU
134 | {F6BCF270-F199-4DD7-A1C3-D4132FDBDC03}.Release|Any CPU.ActiveCfg = Release|Any CPU
135 | {F6BCF270-F199-4DD7-A1C3-D4132FDBDC03}.Release|Any CPU.Build.0 = Release|Any CPU
136 | {495F1E24-3A2E-44D1-BE21-07ABAD784B22}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
137 | {495F1E24-3A2E-44D1-BE21-07ABAD784B22}.Debug|Any CPU.Build.0 = Debug|Any CPU
138 | {495F1E24-3A2E-44D1-BE21-07ABAD784B22}.Release|Any CPU.ActiveCfg = Release|Any CPU
139 | {495F1E24-3A2E-44D1-BE21-07ABAD784B22}.Release|Any CPU.Build.0 = Release|Any CPU
140 | {8B8EEB17-30F9-40D5-9C6B-BB80E0C5E5CC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
141 | {8B8EEB17-30F9-40D5-9C6B-BB80E0C5E5CC}.Debug|Any CPU.Build.0 = Debug|Any CPU
142 | {8B8EEB17-30F9-40D5-9C6B-BB80E0C5E5CC}.Release|Any CPU.ActiveCfg = Release|Any CPU
143 | {8B8EEB17-30F9-40D5-9C6B-BB80E0C5E5CC}.Release|Any CPU.Build.0 = Release|Any CPU
144 | {9F7C7EF9-DFE1-4CF1-BBA4-E76618D973E8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
145 | {9F7C7EF9-DFE1-4CF1-BBA4-E76618D973E8}.Debug|Any CPU.Build.0 = Debug|Any CPU
146 | {9F7C7EF9-DFE1-4CF1-BBA4-E76618D973E8}.Release|Any CPU.ActiveCfg = Release|Any CPU
147 | {9F7C7EF9-DFE1-4CF1-BBA4-E76618D973E8}.Release|Any CPU.Build.0 = Release|Any CPU
148 | {2B8CA8C4-B09F-4161-9687-14CCC589D1F4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
149 | {2B8CA8C4-B09F-4161-9687-14CCC589D1F4}.Debug|Any CPU.Build.0 = Debug|Any CPU
150 | {2B8CA8C4-B09F-4161-9687-14CCC589D1F4}.Release|Any CPU.ActiveCfg = Release|Any CPU
151 | {2B8CA8C4-B09F-4161-9687-14CCC589D1F4}.Release|Any CPU.Build.0 = Release|Any CPU
152 | {39EA2A18-2DD0-4C9D-988F-E61EF77ADF1A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
153 | {39EA2A18-2DD0-4C9D-988F-E61EF77ADF1A}.Debug|Any CPU.Build.0 = Debug|Any CPU
154 | {39EA2A18-2DD0-4C9D-988F-E61EF77ADF1A}.Release|Any CPU.ActiveCfg = Release|Any CPU
155 | {39EA2A18-2DD0-4C9D-988F-E61EF77ADF1A}.Release|Any CPU.Build.0 = Release|Any CPU
156 | {59677058-994E-487E-B294-EE9C71DA96D2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
157 | {59677058-994E-487E-B294-EE9C71DA96D2}.Debug|Any CPU.Build.0 = Debug|Any CPU
158 | {59677058-994E-487E-B294-EE9C71DA96D2}.Release|Any CPU.ActiveCfg = Release|Any CPU
159 | {59677058-994E-487E-B294-EE9C71DA96D2}.Release|Any CPU.Build.0 = Release|Any CPU
160 | {16A1506C-A00D-450F-8782-43060B8C240B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
161 | {16A1506C-A00D-450F-8782-43060B8C240B}.Debug|Any CPU.Build.0 = Debug|Any CPU
162 | {16A1506C-A00D-450F-8782-43060B8C240B}.Release|Any CPU.ActiveCfg = Release|Any CPU
163 | {16A1506C-A00D-450F-8782-43060B8C240B}.Release|Any CPU.Build.0 = Release|Any CPU
164 | {5B2200C9-36FE-4D5B-BA73-B0171FAE6A01}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
165 | {5B2200C9-36FE-4D5B-BA73-B0171FAE6A01}.Debug|Any CPU.Build.0 = Debug|Any CPU
166 | {5B2200C9-36FE-4D5B-BA73-B0171FAE6A01}.Release|Any CPU.ActiveCfg = Release|Any CPU
167 | {5B2200C9-36FE-4D5B-BA73-B0171FAE6A01}.Release|Any CPU.Build.0 = Release|Any CPU
168 | {165E63CF-5C74-4DF5-A4B1-5883ED032F2C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
169 | {165E63CF-5C74-4DF5-A4B1-5883ED032F2C}.Debug|Any CPU.Build.0 = Debug|Any CPU
170 | {165E63CF-5C74-4DF5-A4B1-5883ED032F2C}.Release|Any CPU.ActiveCfg = Release|Any CPU
171 | {165E63CF-5C74-4DF5-A4B1-5883ED032F2C}.Release|Any CPU.Build.0 = Release|Any CPU
172 | {80F6E25B-6F22-4D14-9C0D-9C6AEF30A5D1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
173 | {80F6E25B-6F22-4D14-9C0D-9C6AEF30A5D1}.Debug|Any CPU.Build.0 = Debug|Any CPU
174 | {80F6E25B-6F22-4D14-9C0D-9C6AEF30A5D1}.Release|Any CPU.ActiveCfg = Release|Any CPU
175 | {80F6E25B-6F22-4D14-9C0D-9C6AEF30A5D1}.Release|Any CPU.Build.0 = Release|Any CPU
176 | {6D8DC78C-F1D1-43E6-B1FC-3DA5AE1CF8D2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
177 | {6D8DC78C-F1D1-43E6-B1FC-3DA5AE1CF8D2}.Debug|Any CPU.Build.0 = Debug|Any CPU
178 | {6D8DC78C-F1D1-43E6-B1FC-3DA5AE1CF8D2}.Release|Any CPU.ActiveCfg = Release|Any CPU
179 | {6D8DC78C-F1D1-43E6-B1FC-3DA5AE1CF8D2}.Release|Any CPU.Build.0 = Release|Any CPU
180 | {3E5DC4CA-772C-4FAF-8B11-CC3AECE210E0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
181 | {3E5DC4CA-772C-4FAF-8B11-CC3AECE210E0}.Debug|Any CPU.Build.0 = Debug|Any CPU
182 | {3E5DC4CA-772C-4FAF-8B11-CC3AECE210E0}.Release|Any CPU.ActiveCfg = Release|Any CPU
183 | {3E5DC4CA-772C-4FAF-8B11-CC3AECE210E0}.Release|Any CPU.Build.0 = Release|Any CPU
184 | {2A91ABB0-3955-4E08-8C20-6231A2D0F17D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
185 | {2A91ABB0-3955-4E08-8C20-6231A2D0F17D}.Debug|Any CPU.Build.0 = Debug|Any CPU
186 | {2A91ABB0-3955-4E08-8C20-6231A2D0F17D}.Release|Any CPU.ActiveCfg = Release|Any CPU
187 | {2A91ABB0-3955-4E08-8C20-6231A2D0F17D}.Release|Any CPU.Build.0 = Release|Any CPU
188 | {EF1FF2CC-BC36-497B-9D21-E0851909325F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
189 | {EF1FF2CC-BC36-497B-9D21-E0851909325F}.Debug|Any CPU.Build.0 = Debug|Any CPU
190 | {EF1FF2CC-BC36-497B-9D21-E0851909325F}.Release|Any CPU.ActiveCfg = Release|Any CPU
191 | {EF1FF2CC-BC36-497B-9D21-E0851909325F}.Release|Any CPU.Build.0 = Release|Any CPU
192 | {72DAEC1C-873C-43BC-B027-9FD67AF7E4B8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
193 | {72DAEC1C-873C-43BC-B027-9FD67AF7E4B8}.Debug|Any CPU.Build.0 = Debug|Any CPU
194 | {72DAEC1C-873C-43BC-B027-9FD67AF7E4B8}.Release|Any CPU.ActiveCfg = Release|Any CPU
195 | {72DAEC1C-873C-43BC-B027-9FD67AF7E4B8}.Release|Any CPU.Build.0 = Release|Any CPU
196 | {B2ED16D4-F4CB-4B93-817C-C787213D8A6E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
197 | {B2ED16D4-F4CB-4B93-817C-C787213D8A6E}.Debug|Any CPU.Build.0 = Debug|Any CPU
198 | {B2ED16D4-F4CB-4B93-817C-C787213D8A6E}.Release|Any CPU.ActiveCfg = Release|Any CPU
199 | {B2ED16D4-F4CB-4B93-817C-C787213D8A6E}.Release|Any CPU.Build.0 = Release|Any CPU
200 | {5028999F-F0EC-4421-A786-606372EC0B01}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
201 | {5028999F-F0EC-4421-A786-606372EC0B01}.Debug|Any CPU.Build.0 = Debug|Any CPU
202 | {5028999F-F0EC-4421-A786-606372EC0B01}.Release|Any CPU.ActiveCfg = Release|Any CPU
203 | {5028999F-F0EC-4421-A786-606372EC0B01}.Release|Any CPU.Build.0 = Release|Any CPU
204 | {E17DA84E-69C1-4EB9-AC24-39A9605259EE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
205 | {E17DA84E-69C1-4EB9-AC24-39A9605259EE}.Debug|Any CPU.Build.0 = Debug|Any CPU
206 | {E17DA84E-69C1-4EB9-AC24-39A9605259EE}.Release|Any CPU.ActiveCfg = Release|Any CPU
207 | {E17DA84E-69C1-4EB9-AC24-39A9605259EE}.Release|Any CPU.Build.0 = Release|Any CPU
208 | {0D327170-0673-4A43-8A29-07912377A898}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
209 | {0D327170-0673-4A43-8A29-07912377A898}.Debug|Any CPU.Build.0 = Debug|Any CPU
210 | {0D327170-0673-4A43-8A29-07912377A898}.Release|Any CPU.ActiveCfg = Release|Any CPU
211 | {0D327170-0673-4A43-8A29-07912377A898}.Release|Any CPU.Build.0 = Release|Any CPU
212 | {DAE9ABA6-E347-4659-B579-D80A6AC2000E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
213 | {DAE9ABA6-E347-4659-B579-D80A6AC2000E}.Debug|Any CPU.Build.0 = Debug|Any CPU
214 | {DAE9ABA6-E347-4659-B579-D80A6AC2000E}.Release|Any CPU.ActiveCfg = Release|Any CPU
215 | {DAE9ABA6-E347-4659-B579-D80A6AC2000E}.Release|Any CPU.Build.0 = Release|Any CPU
216 | {1E79EA40-B395-4D11-AA12-A9ED08D18983}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
217 | {1E79EA40-B395-4D11-AA12-A9ED08D18983}.Debug|Any CPU.Build.0 = Debug|Any CPU
218 | {1E79EA40-B395-4D11-AA12-A9ED08D18983}.Release|Any CPU.ActiveCfg = Release|Any CPU
219 | {1E79EA40-B395-4D11-AA12-A9ED08D18983}.Release|Any CPU.Build.0 = Release|Any CPU
220 | {5D8E595F-6C68-47DE-9D1A-538AA6720A02}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
221 | {5D8E595F-6C68-47DE-9D1A-538AA6720A02}.Debug|Any CPU.Build.0 = Debug|Any CPU
222 | {5D8E595F-6C68-47DE-9D1A-538AA6720A02}.Release|Any CPU.ActiveCfg = Release|Any CPU
223 | {5D8E595F-6C68-47DE-9D1A-538AA6720A02}.Release|Any CPU.Build.0 = Release|Any CPU
224 | {E904AF5C-35A2-40F9-8EF2-0FDE5390D6F6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
225 | {E904AF5C-35A2-40F9-8EF2-0FDE5390D6F6}.Debug|Any CPU.Build.0 = Debug|Any CPU
226 | {E904AF5C-35A2-40F9-8EF2-0FDE5390D6F6}.Release|Any CPU.ActiveCfg = Release|Any CPU
227 | {E904AF5C-35A2-40F9-8EF2-0FDE5390D6F6}.Release|Any CPU.Build.0 = Release|Any CPU
228 | {F1BF0BC9-38BC-432B-AB28-4BF68A1A344C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
229 | {F1BF0BC9-38BC-432B-AB28-4BF68A1A344C}.Debug|Any CPU.Build.0 = Debug|Any CPU
230 | {F1BF0BC9-38BC-432B-AB28-4BF68A1A344C}.Release|Any CPU.ActiveCfg = Release|Any CPU
231 | {F1BF0BC9-38BC-432B-AB28-4BF68A1A344C}.Release|Any CPU.Build.0 = Release|Any CPU
232 | {FB7E260A-C146-40C3-BF7C-641BEF92A7A0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
233 | {FB7E260A-C146-40C3-BF7C-641BEF92A7A0}.Debug|Any CPU.Build.0 = Debug|Any CPU
234 | {FB7E260A-C146-40C3-BF7C-641BEF92A7A0}.Release|Any CPU.ActiveCfg = Release|Any CPU
235 | {FB7E260A-C146-40C3-BF7C-641BEF92A7A0}.Release|Any CPU.Build.0 = Release|Any CPU
236 | EndGlobalSection
237 | GlobalSection(SolutionProperties) = preSolution
238 | HideSolutionNode = FALSE
239 | EndGlobalSection
240 | GlobalSection(NestedProjects) = preSolution
241 | {4A96FD48-1F32-4787-8914-CE61765E2D7B} = {66EE5B92-EBBC-4F0A-A67F-232B0F1FA5C0}
242 | {AB5DD339-5F31-4B97-B883-8D87119A4D9C} = {66EE5B92-EBBC-4F0A-A67F-232B0F1FA5C0}
243 | {37C9ABAA-E217-43C1-9E78-D45B721DA6B7} = {66EE5B92-EBBC-4F0A-A67F-232B0F1FA5C0}
244 | {ADF5C5A0-292A-47E8-933D-0E49159ECF8A} = {66EE5B92-EBBC-4F0A-A67F-232B0F1FA5C0}
245 | {1E5B4E96-249C-4239-81E1-ECC45EC1E84E} = {66EE5B92-EBBC-4F0A-A67F-232B0F1FA5C0}
246 | {B73A83B8-8E52-4CBA-AA33-19073A170AE1} = {66EE5B92-EBBC-4F0A-A67F-232B0F1FA5C0}
247 | {3293F4D5-E1A8-46BA-A1B3-B06095D16FBA} = {66EE5B92-EBBC-4F0A-A67F-232B0F1FA5C0}
248 | {039921D8-4248-4929-9600-F6794AEB46E0} = {A520C293-BEE3-463F-A448-488C5EC15D24}
249 | {2242FC5A-384D-4644-85C0-8D8AA1D7D2DB} = {A520C293-BEE3-463F-A448-488C5EC15D24}
250 | {DCE0ABDE-C706-4357-B2C2-508E5E5E4028} = {A520C293-BEE3-463F-A448-488C5EC15D24}
251 | {F6BCF270-F199-4DD7-A1C3-D4132FDBDC03} = {A520C293-BEE3-463F-A448-488C5EC15D24}
252 | {495F1E24-3A2E-44D1-BE21-07ABAD784B22} = {A520C293-BEE3-463F-A448-488C5EC15D24}
253 | {8B8EEB17-30F9-40D5-9C6B-BB80E0C5E5CC} = {A520C293-BEE3-463F-A448-488C5EC15D24}
254 | {9F7C7EF9-DFE1-4CF1-BBA4-E76618D973E8} = {A520C293-BEE3-463F-A448-488C5EC15D24}
255 | {2B8CA8C4-B09F-4161-9687-14CCC589D1F4} = {A520C293-BEE3-463F-A448-488C5EC15D24}
256 | {39EA2A18-2DD0-4C9D-988F-E61EF77ADF1A} = {B5EA3087-36A6-4F1B-B57D-B4A0439552AF}
257 | {59677058-994E-487E-B294-EE9C71DA96D2} = {B5EA3087-36A6-4F1B-B57D-B4A0439552AF}
258 | {16A1506C-A00D-450F-8782-43060B8C240B} = {B5EA3087-36A6-4F1B-B57D-B4A0439552AF}
259 | {5B2200C9-36FE-4D5B-BA73-B0171FAE6A01} = {B5EA3087-36A6-4F1B-B57D-B4A0439552AF}
260 | {165E63CF-5C74-4DF5-A4B1-5883ED032F2C} = {B5EA3087-36A6-4F1B-B57D-B4A0439552AF}
261 | {80F6E25B-6F22-4D14-9C0D-9C6AEF30A5D1} = {B5EA3087-36A6-4F1B-B57D-B4A0439552AF}
262 | {6D8DC78C-F1D1-43E6-B1FC-3DA5AE1CF8D2} = {B5EA3087-36A6-4F1B-B57D-B4A0439552AF}
263 | {3E5DC4CA-772C-4FAF-8B11-CC3AECE210E0} = {B5EA3087-36A6-4F1B-B57D-B4A0439552AF}
264 | {2A91ABB0-3955-4E08-8C20-6231A2D0F17D} = {B5EA3087-36A6-4F1B-B57D-B4A0439552AF}
265 | {EF1FF2CC-BC36-497B-9D21-E0851909325F} = {66EE5B92-EBBC-4F0A-A67F-232B0F1FA5C0}
266 | {72DAEC1C-873C-43BC-B027-9FD67AF7E4B8} = {7A660546-3B3E-44B8-BF65-422CDA59BED4}
267 | {B2ED16D4-F4CB-4B93-817C-C787213D8A6E} = {7A660546-3B3E-44B8-BF65-422CDA59BED4}
268 | {5028999F-F0EC-4421-A786-606372EC0B01} = {A520C293-BEE3-463F-A448-488C5EC15D24}
269 | {E17DA84E-69C1-4EB9-AC24-39A9605259EE} = {7A660546-3B3E-44B8-BF65-422CDA59BED4}
270 | {0D327170-0673-4A43-8A29-07912377A898} = {66EE5B92-EBBC-4F0A-A67F-232B0F1FA5C0}
271 | {DAE9ABA6-E347-4659-B579-D80A6AC2000E} = {7A660546-3B3E-44B8-BF65-422CDA59BED4}
272 | {1E79EA40-B395-4D11-AA12-A9ED08D18983} = {A520C293-BEE3-463F-A448-488C5EC15D24}
273 | {5D8E595F-6C68-47DE-9D1A-538AA6720A02} = {B5EA3087-36A6-4F1B-B57D-B4A0439552AF}
274 | {E904AF5C-35A2-40F9-8EF2-0FDE5390D6F6} = {A520C293-BEE3-463F-A448-488C5EC15D24}
275 | {F1BF0BC9-38BC-432B-AB28-4BF68A1A344C} = {A520C293-BEE3-463F-A448-488C5EC15D24}
276 | {FB7E260A-C146-40C3-BF7C-641BEF92A7A0} = {A520C293-BEE3-463F-A448-488C5EC15D24}
277 | EndGlobalSection
278 | GlobalSection(ExtensibilityGlobals) = postSolution
279 | SolutionGuid = {A562724F-A53A-4048-8F82-F40597B34CE3}
280 | EndGlobalSection
281 | EndGlobal
282 |
--------------------------------------------------------------------------------