Full Code of BehzadDara/OnlineShop for AI

master bcf4372f0d9f cached
239 files
300.1 MB
41.5k tokens
212 symbols
1 requests
Download .txt
Repository: BehzadDara/OnlineShop
Branch: master
Commit: bcf4372f0d9f
Files: 239
Total size: 300.1 MB

Directory structure:
gitextract__0w2wh4p/

├── .dockerignore
├── .gitattributes
├── .gitignore
├── ApiGateways/
│   ├── OcelotApiGateway/
│   │   ├── Dockerfile
│   │   ├── OcelotApiGateway.csproj
│   │   ├── Program.cs
│   │   ├── Properties/
│   │   │   └── launchSettings.json
│   │   ├── appsettings.Development.json
│   │   ├── appsettings.json
│   │   ├── ocelot.Development.json
│   │   ├── ocelot.Local.json
│   │   └── ocelot.json
│   └── OnlineShop.Aggregator/
│       └── OnlineShop.Aggregator/
│           ├── Controllers/
│           │   └── ShoppingController.cs
│           ├── DTOs/
│           │   ├── BasketDTO.cs
│           │   ├── BasketItemExtendedDTO.cs
│           │   ├── CatalogDTO.cs
│           │   ├── OrderResponseDTO.cs
│           │   └── ShoppingDTO.cs
│           ├── Dockerfile
│           ├── Extensions/
│           │   └── HttpClientExtensions.cs
│           ├── OnlineShop.Aggregator.csproj
│           ├── OnlineShop.Aggregator.http
│           ├── Program.cs
│           ├── Properties/
│           │   └── launchSettings.json
│           ├── Services/
│           │   ├── BasketService.cs
│           │   ├── CatalogService.cs
│           │   ├── IBasketService.cs
│           │   ├── ICatalogService.cs
│           │   ├── IOrderService.cs
│           │   └── OrderService.cs
│           ├── appsettings.Development.json
│           └── appsettings.json
├── BuildingBlocks/
│   └── EventBus.Messages/
│       ├── Common/
│       │   └── EventBusConstant.cs
│       ├── EventBus.Messages.csproj
│       └── Events/
│           ├── BasketCheckoutEvent.cs
│           └── IntegrationBaseEvent.cs
├── OnlineShop.sln
├── README.md
├── Services/
│   ├── Basket/
│   │   └── Basket.Api/
│   │       ├── Basket.Api.csproj
│   │       ├── Basket.Api.http
│   │       ├── Controllers/
│   │       │   └── OrderController.cs
│   │       ├── Dockerfile
│   │       ├── Entities/
│   │       │   ├── BasketCheckout.cs
│   │       │   ├── Order.cs
│   │       │   └── OrderItem.cs
│   │       ├── GrpcServices/
│   │       │   └── DiscountGrpcService.cs
│   │       ├── Mapper/
│   │       │   └── BasketProfile.cs
│   │       ├── Program.cs
│   │       ├── Properties/
│   │       │   └── launchSettings.json
│   │       ├── Repositories/
│   │       │   ├── IOrderRepository.cs
│   │       │   └── OrderRepository.cs
│   │       ├── appsettings.Development.json
│   │       └── appsettings.json
│   ├── Catalog/
│   │   └── Catalog.Api/
│   │       ├── Catalog.Api.csproj
│   │       ├── Catalog.Api.http
│   │       ├── Controllers/
│   │       │   └── ProductController.cs
│   │       ├── Data/
│   │       │   ├── CatalogContext.cs
│   │       │   ├── CatalogContextSeed.cs
│   │       │   └── ICatalogContext.cs
│   │       ├── Dockerfile
│   │       ├── Entities/
│   │       │   └── Product.cs
│   │       ├── Products.Json
│   │       ├── Program.cs
│   │       ├── Properties/
│   │       │   └── launchSettings.json
│   │       ├── Repositories/
│   │       │   ├── IProductRepository.cs
│   │       │   └── ProductRepository.cs
│   │       ├── appsettings.Development.json
│   │       └── appsettings.json
│   ├── Discount/
│   │   ├── Discount.Api/
│   │   │   ├── Controllers/
│   │   │   │   └── CouponController.cs
│   │   │   ├── Discount.Api.csproj
│   │   │   ├── Discount.Api.http
│   │   │   ├── Dockerfile
│   │   │   ├── Entities/
│   │   │   │   └── Coupon.cs
│   │   │   ├── Extensions/
│   │   │   │   └── HostExtensions.cs
│   │   │   ├── Program.cs
│   │   │   ├── Properties/
│   │   │   │   └── launchSettings.json
│   │   │   ├── Repositories/
│   │   │   │   ├── CouponRepository.cs
│   │   │   │   └── ICouponRepository.cs
│   │   │   ├── appsettings.Development.json
│   │   │   └── appsettings.json
│   │   └── Discount.Grpc/
│   │       ├── Discount.Grpc.csproj
│   │       ├── Dockerfile
│   │       ├── Entities/
│   │       │   └── Coupon.cs
│   │       ├── Extensions/
│   │       │   └── HostExtensions.cs
│   │       ├── Mapper/
│   │       │   └── DiscountProfile.cs
│   │       ├── Program.cs
│   │       ├── Properties/
│   │       │   └── launchSettings.json
│   │       ├── Protos/
│   │       │   └── discount.proto
│   │       ├── Repositories/
│   │       │   ├── CouponRepository.cs
│   │       │   └── ICouponRepository.cs
│   │       ├── Services/
│   │       │   └── DiscountService.cs
│   │       ├── appsettings.Development.json
│   │       └── appsettings.json
│   └── Ordering/
│       ├── Ordering.Api/
│       │   ├── Controllers/
│       │   │   └── OrderController.cs
│       │   ├── Dockerfile
│       │   ├── EventBusConsumer/
│       │   │   └── BasketCheckoutConsumer.cs
│       │   ├── HostExtensions.cs
│       │   ├── Mapper/
│       │   │   └── CheckoutProfile.cs
│       │   ├── Ordering.Api.csproj
│       │   ├── Ordering.Api.http
│       │   ├── Program.cs
│       │   ├── Properties/
│       │   │   └── launchSettings.json
│       │   ├── appsettings.Development.json
│       │   └── appsettings.json
│       ├── Ordering.Application/
│       │   ├── ApplicationServiceRegistration.cs
│       │   ├── Behaviors/
│       │   │   ├── UnhandledExceptionBehavior.cs
│       │   │   └── ValidationBehavior.cs
│       │   ├── Contracts/
│       │   │   ├── Infrastructure/
│       │   │   │   └── IEmailService.cs
│       │   │   └── Persistence/
│       │   │       ├── IAsyncRepository.cs
│       │   │       └── IOrderRepository.cs
│       │   ├── Exceptions/
│       │   │   ├── NotFoundException.cs
│       │   │   └── ValidationException.cs
│       │   ├── Features/
│       │   │   └── Orders/
│       │   │       ├── Commands/
│       │   │       │   ├── CreateOrder/
│       │   │       │   │   ├── CreateOrderCommand.cs
│       │   │       │   │   ├── CreateOrderCommandHandler.cs
│       │   │       │   │   └── CreateOrderCommandValidator.cs
│       │   │       │   ├── DeleteOrder/
│       │   │       │   │   ├── DeleteOrderCommand.cs
│       │   │       │   │   └── DeleteOrderCommandHandler.cs
│       │   │       │   └── UpdateOrder/
│       │   │       │       ├── UpdateOrderCommand.cs
│       │   │       │       ├── UpdateOrderCommandHandler.cs
│       │   │       │       └── UpdateOrderCommandValidator.cs
│       │   │       └── Queries/
│       │   │           └── GetOrdersList/
│       │   │               ├── GetOrdersListQuery.cs
│       │   │               ├── GetOrdersListQueryHandler.cs
│       │   │               └── OrderViewModel.cs
│       │   ├── Mappings/
│       │   │   └── MappingProfile.cs
│       │   ├── Models/
│       │   │   ├── Email.cs
│       │   │   └── EmailSetting.cs
│       │   └── Ordering.Application.csproj
│       ├── Ordering.Domain/
│       │   ├── Common/
│       │   │   ├── EntityBase.cs
│       │   │   └── ValueObject.cs
│       │   ├── Entities/
│       │   │   └── Order.cs
│       │   └── Ordering.Domain.csproj
│       └── Ordering.Infrastructure/
│           ├── InfrastructureServiceRegistration.cs
│           ├── Migrations/
│           │   ├── 20231211200458_Init.Designer.cs
│           │   ├── 20231211200458_Init.cs
│           │   └── OrderDBContextModelSnapshot.cs
│           ├── Ordering.Infrastructure.csproj
│           ├── Persistence/
│           │   ├── OrderDBContext.cs
│           │   └── OrderDBContextSeed.cs
│           ├── Proxies/
│           │   └── EmailService.cs
│           └── Repositories/
│               ├── OrderRepository.cs
│               └── RepositoryBase.cs
├── docker-compose.dcproj
├── docker-compose.override.yml
├── docker-compose.yml
├── launchSettings.json
└── mongo_data/
    ├── WiredTiger
    ├── WiredTiger.turtle
    ├── WiredTiger.wt
    ├── WiredTigerHS.wt
    ├── _mdb_catalog.wt
    ├── collection-0--2162413245845826319.wt
    ├── collection-2--2162413245845826319.wt
    ├── collection-4--2162413245845826319.wt
    ├── collection-7--2162413245845826319.wt
    ├── diagnostic.data/
    │   ├── metrics.2023-12-05T22-35-19Z-00000
    │   ├── metrics.2023-12-05T22-54-37Z-00000
    │   ├── metrics.2023-12-05T22-56-43Z-00000
    │   ├── metrics.2023-12-05T22-58-50Z-00000
    │   ├── metrics.2023-12-05T23-02-35Z-00000
    │   ├── metrics.2023-12-05T23-04-34Z-00000
    │   ├── metrics.2023-12-06T09-50-37Z-00000
    │   ├── metrics.2023-12-06T11-17-57Z-00000
    │   ├── metrics.2023-12-06T11-45-54Z-00000
    │   ├── metrics.2023-12-06T11-47-38Z-00000
    │   ├── metrics.2023-12-06T11-49-51Z-00000
    │   ├── metrics.2023-12-06T11-51-33Z-00000
    │   ├── metrics.2023-12-06T12-01-34Z-00000
    │   ├── metrics.2023-12-06T12-22-29Z-00000
    │   ├── metrics.2023-12-06T12-25-10Z-00000
    │   ├── metrics.2023-12-06T13-14-10Z-00000
    │   ├── metrics.2023-12-06T22-44-00Z-00000
    │   ├── metrics.2023-12-07T10-00-48Z-00000
    │   ├── metrics.2023-12-07T10-42-49Z-00000
    │   ├── metrics.2023-12-09T20-35-09Z-00000
    │   ├── metrics.2023-12-09T20-52-53Z-00000
    │   ├── metrics.2023-12-09T21-12-07Z-00000
    │   ├── metrics.2023-12-09T21-22-39Z-00000
    │   ├── metrics.2023-12-10T08-52-41Z-00000
    │   ├── metrics.2023-12-10T08-53-11Z-00000
    │   ├── metrics.2023-12-10T09-02-16Z-00000
    │   ├── metrics.2023-12-10T09-03-51Z-00000
    │   ├── metrics.2023-12-10T09-10-11Z-00000
    │   ├── metrics.2023-12-10T09-12-08Z-00000
    │   ├── metrics.2023-12-10T09-12-44Z-00000
    │   ├── metrics.2023-12-10T09-14-28Z-00000
    │   ├── metrics.2023-12-10T09-22-38Z-00000
    │   ├── metrics.2023-12-10T09-24-18Z-00000
    │   ├── metrics.2023-12-10T09-26-25Z-00000
    │   ├── metrics.2023-12-10T09-27-56Z-00000
    │   ├── metrics.2023-12-10T09-31-41Z-00000
    │   ├── metrics.2023-12-10T09-34-53Z-00000
    │   ├── metrics.2023-12-10T10-05-22Z-00000
    │   ├── metrics.2023-12-10T10-06-22Z-00000
    │   ├── metrics.2023-12-10T10-12-00Z-00000
    │   ├── metrics.2023-12-10T10-20-34Z-00000
    │   ├── metrics.2023-12-10T10-27-09Z-00000
    │   ├── metrics.2023-12-10T12-12-15Z-00000
    │   ├── metrics.2023-12-10T13-36-47Z-00000
    │   ├── metrics.2023-12-10T13-43-27Z-00000
    │   ├── metrics.2023-12-10T20-59-24Z-00000
    │   ├── metrics.2023-12-11T12-23-14Z-00000
    │   ├── metrics.2023-12-11T12-30-27Z-00000
    │   ├── metrics.2023-12-11T13-08-05Z-00000
    │   ├── metrics.2023-12-11T14-37-06Z-00000
    │   ├── metrics.2023-12-11T19-48-10Z-00000
    │   ├── metrics.2023-12-11T19-48-31Z-00000
    │   ├── metrics.2023-12-12T08-42-51Z-00000
    │   ├── metrics.2023-12-12T08-46-13Z-00000
    │   ├── metrics.2023-12-12T08-49-01Z-00000
    │   ├── metrics.2023-12-12T09-02-14Z-00000
    │   ├── metrics.2023-12-12T12-16-33Z-00000
    │   ├── metrics.2023-12-12T12-34-54Z-00000
    │   ├── metrics.2023-12-12T12-37-21Z-00000
    │   ├── metrics.2023-12-12T12-40-44Z-00000
    │   ├── metrics.2023-12-12T12-45-56Z-00000
    │   ├── metrics.2023-12-12T13-11-29Z-00000
    │   ├── metrics.2023-12-12T13-14-47Z-00000
    │   ├── metrics.2023-12-12T13-16-13Z-00000
    │   ├── metrics.2023-12-12T13-17-38Z-00000
    │   ├── metrics.2023-12-12T14-53-07Z-00000
    │   ├── metrics.2023-12-13T09-56-35Z-00000
    │   ├── metrics.2023-12-13T10-54-21Z-00000
    │   ├── metrics.2023-12-13T10-56-58Z-00000
    │   ├── metrics.2023-12-13T11-45-51Z-00000
    │   ├── metrics.2023-12-13T11-46-22Z-00000
    │   ├── metrics.2023-12-16T16-22-45Z-00000
    │   ├── metrics.2023-12-17T14-03-32Z-00000
    │   ├── metrics.2023-12-17T15-15-10Z-00000
    │   └── metrics.2023-12-17T20-40-29Z-00000
    ├── index-1--2162413245845826319.wt
    ├── index-3--2162413245845826319.wt
    ├── index-5--2162413245845826319.wt
    ├── index-6--2162413245845826319.wt
    ├── index-8--2162413245845826319.wt
    ├── journal/
    │   ├── WiredTigerLog.0000000075
    │   ├── WiredTigerPreplog.0000000001
    │   └── WiredTigerPreplog.0000000002
    ├── sizeStorer.wt
    └── storage.bson

================================================
FILE CONTENTS
================================================

================================================
FILE: .dockerignore
================================================
**/.classpath
**/.dockerignore
**/.env
**/.git
**/.gitignore
**/.project
**/.settings
**/.toolstarget
**/.vs
**/.vscode
**/*.*proj.user
**/*.dbmdl
**/*.jfm
**/azds.yaml
**/bin
**/charts
**/docker-compose*
**/Dockerfile*
**/node_modules
**/npm-debug.log
**/obj
**/secrets.dev.yaml
**/values.dev.yaml
LICENSE
README.md
!**/.gitignore
!.git/HEAD
!.git/config
!.git/packed-refs
!.git/refs/heads/**

================================================
FILE: .gitattributes
================================================
###############################################################################
# Set default behavior to automatically normalize line endings.
###############################################################################
* text=auto

###############################################################################
# Set default behavior for command prompt diff.
#
# This is need for earlier builds of msysgit that does not have it on by
# default for csharp files.
# Note: This is only used by command line
###############################################################################
#*.cs     diff=csharp

###############################################################################
# Set the merge driver for project and solution files
#
# Merging from the command prompt will add diff markers to the files if there
# are conflicts (Merging from VS is not affected by the settings below, in VS
# the diff markers are never inserted). Diff markers may cause the following 
# file extensions to fail to load in VS. An alternative would be to treat
# these files as binary and thus will always conflict and require user
# intervention with every merge. To do so, just uncomment the entries below
###############################################################################
#*.sln       merge=binary
#*.csproj    merge=binary
#*.vbproj    merge=binary
#*.vcxproj   merge=binary
#*.vcproj    merge=binary
#*.dbproj    merge=binary
#*.fsproj    merge=binary
#*.lsproj    merge=binary
#*.wixproj   merge=binary
#*.modelproj merge=binary
#*.sqlproj   merge=binary
#*.wwaproj   merge=binary

###############################################################################
# behavior for image files
#
# image files are treated as binary by default.
###############################################################################
#*.jpg   binary
#*.png   binary
#*.gif   binary

###############################################################################
# diff behavior for common document formats
# 
# Convert binary document formats to text before diffing them. This feature
# is only available from the command line. Turn it on by uncommenting the 
# entries below.
###############################################################################
#*.doc   diff=astextplain
#*.DOC   diff=astextplain
#*.docx  diff=astextplain
#*.DOCX  diff=astextplain
#*.dot   diff=astextplain
#*.DOT   diff=astextplain
#*.pdf   diff=astextplain
#*.PDF   diff=astextplain
#*.rtf   diff=astextplain
#*.RTF   diff=astextplain


================================================
FILE: .gitignore
================================================
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore

# User-specific files
*.rsuser
*.suo
*.user
*.userosscache
*.sln.docstates

# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs

# Mono auto generated files
mono_crash.*

# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
[Ww][Ii][Nn]32/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Oo]ut/
[Ll]og/
[Ll]ogs/

# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/

# Visual Studio 2017 auto generated files
Generated\ Files/

# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*

# NUnit
*.VisualState.xml
TestResult.xml
nunit-*.xml

# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c

# Benchmark Results
BenchmarkDotNet.Artifacts/

# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/

# ASP.NET Scaffolding
ScaffoldingReadMe.txt

# StyleCop
StyleCopReport.xml

# Files built by Visual Studio
*_i.c
*_p.c
*_h.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*_wpftmp.csproj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc

# Chutzpah Test files
_Chutzpah*

# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb

# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap

# Visual Studio Trace Files
*.e2e

# TFS 2012 Local Workspace
$tf/

# Guidance Automation Toolkit
*.gpState

# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user

# TeamCity is a build add-in
_TeamCity*

# DotCover is a Code Coverage Tool
*.dotCover

# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json

# Coverlet is a free, cross platform Code Coverage Tool
coverage*.json
coverage*.xml
coverage*.info

# Visual Studio code coverage results
*.coverage
*.coveragexml

# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*

# MightyMoose
*.mm.*
AutoTest.Net/

# Web workbench (sass)
.sass-cache/

# Installshield output folder
[Ee]xpress/

# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html

# Click-Once directory
publish/

# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj

# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/

# NuGet Packages
*.nupkg
# NuGet Symbol Packages
*.snupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets

# Microsoft Azure Build Output
csx/
*.build.csdef

# Microsoft Azure Emulator
ecf/
rcf/

# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
*.appxbundle
*.appxupload

# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!?*.[Cc]ache/

# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs

# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk

# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/

# RIA/Silverlight projects
Generated_Code/

# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak

# SQL Server files
*.mdf
*.ldf
*.ndf

# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
*- [Bb]ackup.rdl
*- [Bb]ackup ([0-9]).rdl
*- [Bb]ackup ([0-9][0-9]).rdl

# Microsoft Fakes
FakesAssemblies/

# GhostDoc plugin setting file
*.GhostDoc.xml

# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/

# Visual Studio 6 build log
*.plg

# Visual Studio 6 workspace options file
*.opt

# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw

# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions

# Paket dependency manager
.paket/paket.exe
paket-files/

# FAKE - F# Make
.fake/

# CodeRush personal settings
.cr/personal

# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc

# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config

# Tabs Studio
*.tss

# Telerik's JustMock configuration file
*.jmconfig

# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs

# OpenCover UI analysis results
OpenCover/

# Azure Stream Analytics local run output
ASALocalRun/

# MSBuild Binary and Structured Log
*.binlog

# NVidia Nsight GPU debugger configuration file
*.nvuser

# MFractors (Xamarin productivity tool) working folder
.mfractor/

# Local History for Visual Studio
.localhistory/

# BeatPulse healthcheck temp database
healthchecksdb

# Backup folder for Package Reference Convert tool in Visual Studio 2017
MigrationBackup/

# Ionide (cross platform F# VS Code tools) working folder
.ionide/

# Fody - auto-generated XML schema
FodyWeavers.xsd

================================================
FILE: ApiGateways/OcelotApiGateway/Dockerfile
================================================
#See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging.

FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
USER app
WORKDIR /app
EXPOSE 8080

FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
ARG BUILD_CONFIGURATION=Release
WORKDIR /src
COPY ["ApiGateways/OcelotApiGateway/OcelotApiGateway.csproj", "ApiGateways/OcelotApiGateway/"]
RUN dotnet restore "./ApiGateways/OcelotApiGateway/./OcelotApiGateway.csproj"
COPY . .
WORKDIR "/src/ApiGateways/OcelotApiGateway"
RUN dotnet build "./OcelotApiGateway.csproj" -c $BUILD_CONFIGURATION -o /app/build

FROM build AS publish
ARG BUILD_CONFIGURATION=Release
RUN dotnet publish "./OcelotApiGateway.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "OcelotApiGateway.dll"]

================================================
FILE: ApiGateways/OcelotApiGateway/OcelotApiGateway.csproj
================================================
<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
    <DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
    <DockerfileContext>..\..</DockerfileContext>
    <DockerComposeProjectPath>..\..\docker-compose.dcproj</DockerComposeProjectPath>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.19.5" />
    <PackageReference Include="Ocelot" Version="22.0.1" />
    <PackageReference Include="Ocelot.Cache.CacheManager" Version="22.0.1" />
  </ItemGroup>

</Project>


================================================
FILE: ApiGateways/OcelotApiGateway/Program.cs
================================================
using Ocelot.Cache.CacheManager;
using Ocelot.DependencyInjection;
using Ocelot.Middleware;

var builder = WebApplication.CreateBuilder(args);

builder.Logging
    .AddConfiguration(builder.Configuration.GetSection("Logging"))
    .AddConsole()
    .AddDebug();

builder.Configuration
    .AddJsonFile($"ocelot.{builder.Environment.EnvironmentName}.json");

builder.Services
    .AddOcelot()
    .AddCacheManager(x =>
    {
        x.WithDictionaryHandle();
    });

var app = builder.Build();

await app.UseOcelot();

app.Run();


================================================
FILE: ApiGateways/OcelotApiGateway/Properties/launchSettings.json
================================================
{
  "profiles": {
    "OcelotApiGateway": {
      "commandName": "Project",
      "launchBrowser": true,
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Local"
      },
      "dotnetRunMessages": true,
      "applicationUrl": "http://localhost:5010"
    },
    "IIS Express": {
      "commandName": "IISExpress",
      "launchBrowser": true,
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Local"
      }
    },
    "Docker": {
      "commandName": "Docker",
      "launchBrowser": true,
      "launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}",
      "environmentVariables": {
        "ASPNETCORE_HTTP_PORTS": "8010"
      },
      "publishAllPorts": true
    }
  },
  "$schema": "http://json.schemastore.org/launchsettings.json",
  "iisSettings": {
    "windowsAuthentication": false,
    "anonymousAuthentication": true,
    "iisExpress": {
      "applicationUrl": "http://localhost:13294",
      "sslPort": 0
    }
  }
}

================================================
FILE: ApiGateways/OcelotApiGateway/appsettings.Development.json
================================================
{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  }
}


================================================
FILE: ApiGateways/OcelotApiGateway/appsettings.json
================================================
{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*"
}


================================================
FILE: ApiGateways/OcelotApiGateway/ocelot.Development.json
================================================
// BFF: Backend For Frontend
{
  "Routes": [
    // Catalog.Api
    {
      "DownStreamPathTemplate": "/api/v1/{controller}/{action}",
      "DownStreamScheme": "http",
      "DownStreamHostAndPorts": [
        {
          "Host": "catalog.api",
          "Port": 8000
        }
      ],
      "UpStreamPathTemplate": "/Catalog/{controller}/{action}",
      "UpStreamHttpMethod": [ "GET", "POST", "PUT" ],
      "FileCacheOptions": {
        "TtlSeconds": 30
      }
    },
    {
      "DownStreamPathTemplate": "/api/v1/{controller}/{action}/{idOrNameOrCategory}",
      "DownStreamScheme": "http",
      "DownStreamHostAndPorts": [
        {
          "Host": "catalog.api",
          "Port": 8000
        }
      ],
      "UpStreamPathTemplate": "/Catalog/{controller}/{action}/{idOrNameOrCategory}",
      "UpStreamHttpMethod": [ "GET", "DELETE" ]
    },
    // Basket.Api
    {
      "DownStreamPathTemplate": "/api/v1/{controller}/{action}",
      "DownStreamScheme": "http",
      "DownStreamHostAndPorts": [
        {
          "Host": "basket.api",
          "Port": 8001
        }
      ],
      "UpStreamPathTemplate": "/Basket/{controller}/{action}",
      "UpStreamHttpMethod": [ "POST" ],
      "RateLimitOptions": {
        "ClientWhiteList": [],
        "EnableRateLimiting": true,
        "Period": "5s",
        "PeriodTimeSpan": 1,
        "Limit": 1
      }
    },
    {
      "DownStreamPathTemplate": "/api/v1/{controller}/{action}/{userName}",
      "DownStreamScheme": "http",
      "DownStreamHostAndPorts": [
        {
          "Host": "basket.api",
          "Port": 8001
        }
      ],
      "UpStreamPathTemplate": "/Basket/{controller}/{action}/{userName}",
      "UpStreamHttpMethod": [ "GET", "DELETE" ]
    },
    // Discount.Api
    {
      "DownStreamPathTemplate": "/api/v1/{controller}/{action}",
      "DownStreamScheme": "http",
      "DownStreamHostAndPorts": [
        {
          "Host": "discount.api",
          "Port": 8002
        }
      ],
      "UpStreamPathTemplate": "/Discount/{controller}/{action}",
      "UpStreamHttpMethod": [ "POST", "PUT" ]
    },
    {
      "DownStreamPathTemplate": "/api/v1/{controller}/{action}/{productName}",
      "DownStreamScheme": "http",
      "DownStreamHostAndPorts": [
        {
          "Host": "discount.api",
          "Port": 8002
        }
      ],
      "UpStreamPathTemplate": "/Discount/{controller}/{action}/{productName}",
      "UpStreamHttpMethod": [ "GET", "DELETE" ]
    },
    // Ordering.Api
    {
      "DownStreamPathTemplate": "/api/v1/{controller}/{action}/{userName}",
      "DownStreamScheme": "http",
      "DownStreamHostAndPorts": [
        {
          "Host": "ordering.api",
          "Port": 8004
        }
      ],
      "UpStreamPathTemplate": "/Ordering/{controller}/{action}/{userName}",
      "UpStreamHttpMethod": [ "GET" ]
    }
  ],
  "GlobalConfiguration": {
    "BaseUrl": "http://localhost:5010"
  }
}

================================================
FILE: ApiGateways/OcelotApiGateway/ocelot.Local.json
================================================
// BFF: Backend For Frontend
{
  "Routes": [
    // Catalog.Api
    {
      "DownStreamPathTemplate": "/api/v1/{controller}/{action}",
      "DownStreamScheme": "http",
      "DownStreamHostAndPorts": [
        {
          "Host": "localhost",
          "Port": 8000
        }
      ],
      "UpStreamPathTemplate": "/Catalog/{controller}/{action}",
      "UpStreamHttpMethod": [ "GET", "POST", "PUT" ],
      "FileCacheOptions": {
        "TtlSeconds": 30
      }
    },
    {
      "DownStreamPathTemplate": "/api/v1/{controller}/{action}/{idOrNameOrCategory}",
      "DownStreamScheme": "http",
      "DownStreamHostAndPorts": [
        {
          "Host": "localhost",
          "Port": 8000
        }
      ],
      "UpStreamPathTemplate": "/Catalog/{controller}/{action}/{idOrNameOrCategory}",
      "UpStreamHttpMethod": [ "GET", "DELETE" ]
    },
    // Basket.Api
    {
      "DownStreamPathTemplate": "/api/v1/{controller}/{action}",
      "DownStreamScheme": "http",
      "DownStreamHostAndPorts": [
        {
          "Host": "localhost",
          "Port": 8001
        }
      ],
      "UpStreamPathTemplate": "/Basket/{controller}/{action}",
      "UpStreamHttpMethod": [ "POST" ],
      "RateLimitOptions": {
        "ClientWhiteList": [],
        "EnableRateLimiting": true,
        "Period": "5s",
        "PeriodTimeSpan": 1,
        "Limit": 1
      }
    },
    {
      "DownStreamPathTemplate": "/api/v1/{controller}/{action}/{userName}",
      "DownStreamScheme": "http",
      "DownStreamHostAndPorts": [
        {
          "Host": "localhost",
          "Port": 8001
        }
      ],
      "UpStreamPathTemplate": "/Basket/{controller}/{action}/{userName}",
      "UpStreamHttpMethod": [ "GET", "DELETE" ]
    },
    // Discount.Api
    {
      "DownStreamPathTemplate": "/api/v1/{controller}/{action}",
      "DownStreamScheme": "http",
      "DownStreamHostAndPorts": [
        {
          "Host": "localhost",
          "Port": 8002
        }
      ],
      "UpStreamPathTemplate": "/Discount/{controller}/{action}",
      "UpStreamHttpMethod": [ "POST", "PUT" ]
    },
    {
      "DownStreamPathTemplate": "/api/v1/{controller}/{action}/{productName}",
      "DownStreamScheme": "http",
      "DownStreamHostAndPorts": [
        {
          "Host": "localhost",
          "Port": 8002
        }
      ],
      "UpStreamPathTemplate": "/Discount/{controller}/{action}/{productName}",
      "UpStreamHttpMethod": [ "GET", "DELETE" ]
    },
    // Ordering.Api
    {
      "DownStreamPathTemplate": "/api/v1/{controller}/{action}/{userName}",
      "DownStreamScheme": "http",
      "DownStreamHostAndPorts": [
        {
          "Host": "localhost",
          "Port": 8004
        }
      ],
      "UpStreamPathTemplate": "/Ordering/{controller}/{action}/{userName}",
      "UpStreamHttpMethod": [ "GET" ]
    }
  ],
  "GlobalConfiguration": {
    "BaseUrl": "http://localhost:5010"
  }
}

================================================
FILE: ApiGateways/OcelotApiGateway/ocelot.json
================================================


================================================
FILE: ApiGateways/OnlineShop.Aggregator/OnlineShop.Aggregator/Controllers/ShoppingController.cs
================================================
using Microsoft.AspNetCore.Mvc;
using OnlineShop.Aggregator.DTOs;
using OnlineShop.Aggregator.Services;
using System.Net;

namespace OnlineShop.Aggregator.Controllers;

[ApiController]
[Route("api/v1/[controller]/[action]")]
public class ShoppingController(
    ICatalogService _catalogService,
    IBasketService _basketService,
    IOrderService _orderService
    ) : ControllerBase
{
    [HttpGet("{userName}")]
    [ProducesResponseType(typeof(ShoppingDTO), (int)HttpStatusCode.OK)]
    public async Task<ActionResult<ShoppingDTO>> GetByUserName(string userName)
    {
        var basket = await _basketService.GetBasket(userName);
        foreach (var basketItem in basket.Items)
        {
            var product = await _catalogService.GetCatalog(basketItem.ProductId);

            basketItem.ProductName = product.Name;
            basketItem.Category = product.Category;
            basketItem.Summary = product.Summary;
            basketItem.Description = product.Description;
            basketItem.ImageFile = product.ImageFile;
        }

        var orders = await _orderService.GetOrderByUserName(userName);

        var shoppingDTO = new ShoppingDTO
        {
            UserName = userName,
            BasketWithProduct = basket,
            Orders = orders 
        };

        return Ok(shoppingDTO);
    }
}


================================================
FILE: ApiGateways/OnlineShop.Aggregator/OnlineShop.Aggregator/DTOs/BasketDTO.cs
================================================
namespace OnlineShop.Aggregator.DTOs;

public class BasketDTO
{
    public string UserName { get; set; } = string.Empty;
    public List<BasketItemExtendedDTO> Items { get; set; } = [];
    public decimal TotalPrice { get; set; }
}


================================================
FILE: ApiGateways/OnlineShop.Aggregator/OnlineShop.Aggregator/DTOs/BasketItemExtendedDTO.cs
================================================
namespace OnlineShop.Aggregator.DTOs;

public class BasketItemExtendedDTO
{
    public int Quantity { get; set; }
    public string Color { get; set; } = string.Empty;
    public decimal Price { get; set; }
    public string ProductId { get; set; } = string.Empty;
    public string ProductName { get; set; } = string.Empty;

    // additional data
    public string Category { get; set; } = string.Empty;
    public string Summary { get; set; } = string.Empty;
    public string Description { get; set; } = string.Empty;
    public string ImageFile { get; set; } = string.Empty;
}


================================================
FILE: ApiGateways/OnlineShop.Aggregator/OnlineShop.Aggregator/DTOs/CatalogDTO.cs
================================================
namespace OnlineShop.Aggregator.DTOs;

public class CatalogDTO
{
    public string Id { get; set; } = string.Empty;
    public string Name { get; set; } = string.Empty;
    public string Category { get; set; } = string.Empty;
    public string Summary { get; set; } = string.Empty;
    public string Description { get; set; } = string.Empty;
    public string ImageFile { get; set; } = string.Empty;
    public decimal Price { get; set; }
}


================================================
FILE: ApiGateways/OnlineShop.Aggregator/OnlineShop.Aggregator/DTOs/OrderResponseDTO.cs
================================================
namespace OnlineShop.Aggregator.DTOs;

public class OrderResponseDTO
{
    public string UserName { get; set; } = string.Empty;
    public decimal TotalPrice { get; set; }

    public string FirstName { get; set; } = string.Empty;
    public string LastName { get; set; } = string.Empty;
    public string EmailAddress { get; set; } = string.Empty;
    public string Country { get; set; } = string.Empty;
    public string City { get; set; } = string.Empty;

    public string BankName { get; set; } = string.Empty;
    public string RefCode { get; set; } = string.Empty;
    public int PaymentMethod { get; set; }
}


================================================
FILE: ApiGateways/OnlineShop.Aggregator/OnlineShop.Aggregator/DTOs/ShoppingDTO.cs
================================================
namespace OnlineShop.Aggregator.DTOs;

public class ShoppingDTO
{
    public string UserName { get; set; } = string.Empty;
    public required BasketDTO BasketWithProduct { get; set; }
    public IEnumerable<OrderResponseDTO> Orders { get; set; } = [];
}


================================================
FILE: ApiGateways/OnlineShop.Aggregator/OnlineShop.Aggregator/Dockerfile
================================================
#See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging.

FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
USER app
WORKDIR /app
EXPOSE 8080

FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
ARG BUILD_CONFIGURATION=Release
WORKDIR /src
COPY ["ApiGateways/OnlineShop.Aggregator/OnlineShop.Aggregator/OnlineShop.Aggregator.csproj", "ApiGateways/OnlineShop.Aggregator/OnlineShop.Aggregator/"]
RUN dotnet restore "./ApiGateways/OnlineShop.Aggregator/OnlineShop.Aggregator/./OnlineShop.Aggregator.csproj"
COPY . .
WORKDIR "/src/ApiGateways/OnlineShop.Aggregator/OnlineShop.Aggregator"
RUN dotnet build "./OnlineShop.Aggregator.csproj" -c $BUILD_CONFIGURATION -o /app/build

FROM build AS publish
ARG BUILD_CONFIGURATION=Release
RUN dotnet publish "./OnlineShop.Aggregator.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "OnlineShop.Aggregator.dll"]

================================================
FILE: ApiGateways/OnlineShop.Aggregator/OnlineShop.Aggregator/Extensions/HttpClientExtensions.cs
================================================
using System.Text.Json;

namespace OnlineShop.Aggregator.Extensions;

public static class HttpClientExtensions
{
    public static async Task<T> ReadContentAs<T>(this HttpResponseMessage response)
    {
        if (!response.IsSuccessStatusCode)
            throw new ApplicationException($"Something went wrong when calling api, {response.ReasonPhrase}");

        var dataAsString = await response.Content.ReadAsStringAsync();

        return JsonSerializer.Deserialize<T>(dataAsString)!;
    }
}


================================================
FILE: ApiGateways/OnlineShop.Aggregator/OnlineShop.Aggregator/OnlineShop.Aggregator.csproj
================================================
<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
    <InvariantGlobalization>true</InvariantGlobalization>
    <DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
    <DockerfileContext>..\..\..</DockerfileContext>
    <DockerComposeProjectPath>..\..\..\docker-compose.dcproj</DockerComposeProjectPath>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.19.5" />
    <PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
  </ItemGroup>

</Project>


================================================
FILE: ApiGateways/OnlineShop.Aggregator/OnlineShop.Aggregator/OnlineShop.Aggregator.http
================================================
@OnlineShop.Aggregator_HostAddress = http://localhost:5140

GET {{OnlineShop.Aggregator_HostAddress}}/weatherforecast/
Accept: application/json

###


================================================
FILE: ApiGateways/OnlineShop.Aggregator/OnlineShop.Aggregator/Program.cs
================================================
using OnlineShop.Aggregator.Services;
using System.Text.Json;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();

builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

builder.Services.AddOptions<JsonSerializerOptions>()
    .Configure<IServiceProvider>((options, serviceProvider) =>
    {
        options.PropertyNameCaseInsensitive = true;
    });

builder.Services.AddHttpClient<ICatalogService, CatalogService>(c =>
{
    c.BaseAddress = new Uri(builder.Configuration.GetValue<string>("ApiSettings:CatalogUrl") ?? "");
});
builder.Services.AddHttpClient<IBasketService, BasketService>(c =>
{
    c.BaseAddress = new Uri(builder.Configuration.GetValue<string>("ApiSettings:BasketUrl") ?? "");
});
builder.Services.AddHttpClient<IOrderService, OrderService>(c =>
{
    c.BaseAddress = new Uri(builder.Configuration.GetValue<string>("ApiSettings:OrderingUrl") ?? "");
});

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.MapControllers();

app.Run();


================================================
FILE: ApiGateways/OnlineShop.Aggregator/OnlineShop.Aggregator/Properties/launchSettings.json
================================================
{
  "profiles": {
    "OnlineShop.Aggregator": {
      "commandName": "Project",
      "launchBrowser": true,
      "launchUrl": "swagger",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      },
      "dotnetRunMessages": true,
      "applicationUrl": "http://localhost:5005"
    },
    "IIS Express": {
      "commandName": "IISExpress",
      "launchBrowser": true,
      "launchUrl": "swagger",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    },
    "Docker": {
      "commandName": "Docker",
      "launchBrowser": true,
      "launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/swagger",
      "environmentVariables": {
        "ASPNETCORE_HTTP_PORTS": "8005"
      },
      "publishAllPorts": true
    }
  },
  "$schema": "http://json.schemastore.org/launchsettings.json",
  "iisSettings": {
    "windowsAuthentication": false,
    "anonymousAuthentication": true,
    "iisExpress": {
      "applicationUrl": "http://localhost:49114",
      "sslPort": 0
    }
  }
}

================================================
FILE: ApiGateways/OnlineShop.Aggregator/OnlineShop.Aggregator/Services/BasketService.cs
================================================
using OnlineShop.Aggregator.DTOs;
using OnlineShop.Aggregator.Extensions;

namespace OnlineShop.Aggregator.Services;

public class BasketService(HttpClient _client) : IBasketService
{
    public async Task<BasketDTO> GetBasket(string userName)
    {
        var response = await _client.GetAsync($"/api/v1/Order/GetByUserName/{userName}");
        return await response.ReadContentAs<BasketDTO>();
    }
}


================================================
FILE: ApiGateways/OnlineShop.Aggregator/OnlineShop.Aggregator/Services/CatalogService.cs
================================================
using OnlineShop.Aggregator.DTOs;
using OnlineShop.Aggregator.Extensions;

namespace OnlineShop.Aggregator.Services;

public class CatalogService(HttpClient _client) : ICatalogService
{
    public async Task<IEnumerable<CatalogDTO>> GetCatalog()
    {
        var response = await _client.GetAsync("/api/v1/Product/GetAll");
        return await response.ReadContentAs<List<CatalogDTO>>();
    }

    public async Task<CatalogDTO> GetCatalog(string id)
    {
        var response = await _client.GetAsync($"/api/v1/Product/GetById/{id}");
        return await response.ReadContentAs<CatalogDTO>();
    }

    public async Task<IEnumerable<CatalogDTO>> GetCatalogByCategory(string category)
    {
        var response = await _client.GetAsync($"/api/v1/Product/GetByCategory/{category}");
        return await response.ReadContentAs<List<CatalogDTO>>();
    }
}


================================================
FILE: ApiGateways/OnlineShop.Aggregator/OnlineShop.Aggregator/Services/IBasketService.cs
================================================
using OnlineShop.Aggregator.DTOs;

namespace OnlineShop.Aggregator.Services;

public interface IBasketService
{
    Task<BasketDTO> GetBasket(string userName);
}


================================================
FILE: ApiGateways/OnlineShop.Aggregator/OnlineShop.Aggregator/Services/ICatalogService.cs
================================================
using OnlineShop.Aggregator.DTOs;

namespace OnlineShop.Aggregator.Services;

public interface ICatalogService
{
    Task<IEnumerable<CatalogDTO>> GetCatalog();
    Task<CatalogDTO> GetCatalog(string id);
    Task<IEnumerable<CatalogDTO>> GetCatalogByCategory(string category);
}


================================================
FILE: ApiGateways/OnlineShop.Aggregator/OnlineShop.Aggregator/Services/IOrderService.cs
================================================
using OnlineShop.Aggregator.DTOs;

namespace OnlineShop.Aggregator.Services;

public interface IOrderService
{
    Task<IEnumerable<OrderResponseDTO>> GetOrderByUserName(string userName);
}


================================================
FILE: ApiGateways/OnlineShop.Aggregator/OnlineShop.Aggregator/Services/OrderService.cs
================================================
using OnlineShop.Aggregator.DTOs;
using OnlineShop.Aggregator.Extensions;

namespace OnlineShop.Aggregator.Services;

public class OrderService(HttpClient _client) : IOrderService
{
    public async Task<IEnumerable<OrderResponseDTO>> GetOrderByUserName(string userName)
    {
        var response = await _client.GetAsync($"/api/v1/Order/GetOrdersByUserName/{userName}");
        return await response.ReadContentAs<List<OrderResponseDTO>>();
    }
}


================================================
FILE: ApiGateways/OnlineShop.Aggregator/OnlineShop.Aggregator/appsettings.Development.json
================================================
{
  "ApiSettings": {
    "CatalogUrl": "http://localhost:8000",
    "BasketUrl": "http://localhost:8001",
    "OrderingUrl": "http://localhost:8004"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  }
}


================================================
FILE: ApiGateways/OnlineShop.Aggregator/OnlineShop.Aggregator/appsettings.json
================================================
{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*"
}


================================================
FILE: BuildingBlocks/EventBus.Messages/Common/EventBusConstant.cs
================================================
namespace EventBus.Messages.Common;

public class EventBusConstant
{
    public const string BasketCheckoutQueue = "BasketCheckout-queue";
}


================================================
FILE: BuildingBlocks/EventBus.Messages/EventBus.Messages.csproj
================================================
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

</Project>


================================================
FILE: BuildingBlocks/EventBus.Messages/Events/BasketCheckoutEvent.cs
================================================
namespace EventBus.Messages.Events;

public class BasketCheckoutEvent : IntegrationBaseEvent
{
    public string UserName { get; set; } = string.Empty;
    public decimal TotalPrice { get; set; }

    public string FirstName { get; set; } = string.Empty;
    public string LastName { get; set; } = string.Empty;
    public string EmailAddress { get; set; } = string.Empty;
    public string Country { get; set; } = string.Empty;
    public string City { get; set; } = string.Empty;

    public string BankName { get; set; } = string.Empty;
    public string RefCode { get; set; } = string.Empty;
    public int PaymentMethod { get; set; }
}


================================================
FILE: BuildingBlocks/EventBus.Messages/Events/IntegrationBaseEvent.cs
================================================
namespace EventBus.Messages.Events;

public class IntegrationBaseEvent
{
    public IntegrationBaseEvent()
    {
        Id = Guid.NewGuid();
        CreatedAt = DateTime.Now;
    }

    public IntegrationBaseEvent(Guid id, DateTime createdAt)
    {
        Id = id;
        CreatedAt = createdAt;
    }

    public Guid Id { get; private set; }
    public DateTime CreatedAt { get; private set; }
}


================================================
FILE: OnlineShop.sln
================================================

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.7.34221.43
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Services", "Services", "{087760BA-AF35-40D8-8779-01B3C48D3EF4}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Catalog", "Catalog", "{653AE14C-8DD7-4E9C-96B5-D6B99C1D0CF7}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Catalog.Api", "Services\Catalog\Catalog.Api\Catalog.Api.csproj", "{A6F2D049-4B6E-4805-889F-49D113927DA6}"
EndProject
Project("{E53339B2-1760-4266-BCC7-CA923CBCF16C}") = "docker-compose", "docker-compose.dcproj", "{9ED1D254-4DE6-4229-B3B8-A60383414787}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Basket", "Basket", "{9830C312-7C6A-4AAE-9700-AF8E2BCF942D}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Basket.Api", "Services\Basket\Basket.Api\Basket.Api.csproj", "{820840D7-0105-4611-B956-235D6EE15191}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Discount", "Discount", "{4166A6E7-178A-4FDE-B7BD-33C5833F9472}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Discount.Api", "Services\Discount\Discount.Api\Discount.Api.csproj", "{C8BD72CC-5DDA-4A81-8A5B-FB411D1707ED}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Discount.Grpc", "Services\Discount\Discount.Grpc\Discount.Grpc.csproj", "{DAD4D4A1-9AEB-46CF-A143-D19C1EB9C36D}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Ordering", "Ordering", "{69172560-B5A3-488A-A715-2754C6FA6C5D}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ordering.Api", "Services\Ordering\Ordering.Api\Ordering.Api.csproj", "{F26D75D9-B050-4F78-8911-65780DF78BA5}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ordering.Domain", "Services\Ordering\Ordering.Domain\Ordering.Domain.csproj", "{334B2EC6-F84D-47F2-83C3-7F4FECAA1163}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ordering.Application", "Services\Ordering\Ordering.Application\Ordering.Application.csproj", "{5547B022-4512-4765-A762-121A77F9D204}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ordering.Infrastructure", "Services\Ordering\Ordering.Infrastructure\Ordering.Infrastructure.csproj", "{884BB166-77C2-4B71-9E97-9739616120B4}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "BuildingBlocks", "BuildingBlocks", "{697BC681-3FB0-437B-9BB9-AF5BA4C929E0}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EventBus.Messages", "BuildingBlocks\EventBus.Messages\EventBus.Messages.csproj", "{2318E480-B8A6-40F4-84E4-55A8162A4969}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ApiGateways", "ApiGateways", "{9B4D3E8A-2363-4DB9-8B9A-CC7803EE3F86}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OcelotApiGateway", "ApiGateways\OcelotApiGateway\OcelotApiGateway.csproj", "{14C156A3-CDE8-4501-A61A-1FF511F6255E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OnlineShop.Aggregator", "ApiGateways\OnlineShop.Aggregator\OnlineShop.Aggregator\OnlineShop.Aggregator.csproj", "{3C7D0E5D-90CE-469B-AC79-1B89EEEFE3B8}"
EndProject
Global
	GlobalSection(SolutionConfigurationPlatforms) = preSolution
		Debug|Any CPU = Debug|Any CPU
		Release|Any CPU = Release|Any CPU
	EndGlobalSection
	GlobalSection(ProjectConfigurationPlatforms) = postSolution
		{A6F2D049-4B6E-4805-889F-49D113927DA6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
		{A6F2D049-4B6E-4805-889F-49D113927DA6}.Debug|Any CPU.Build.0 = Debug|Any CPU
		{A6F2D049-4B6E-4805-889F-49D113927DA6}.Release|Any CPU.ActiveCfg = Release|Any CPU
		{A6F2D049-4B6E-4805-889F-49D113927DA6}.Release|Any CPU.Build.0 = Release|Any CPU
		{9ED1D254-4DE6-4229-B3B8-A60383414787}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
		{9ED1D254-4DE6-4229-B3B8-A60383414787}.Debug|Any CPU.Build.0 = Debug|Any CPU
		{9ED1D254-4DE6-4229-B3B8-A60383414787}.Release|Any CPU.ActiveCfg = Release|Any CPU
		{9ED1D254-4DE6-4229-B3B8-A60383414787}.Release|Any CPU.Build.0 = Release|Any CPU
		{820840D7-0105-4611-B956-235D6EE15191}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
		{820840D7-0105-4611-B956-235D6EE15191}.Debug|Any CPU.Build.0 = Debug|Any CPU
		{820840D7-0105-4611-B956-235D6EE15191}.Release|Any CPU.ActiveCfg = Release|Any CPU
		{820840D7-0105-4611-B956-235D6EE15191}.Release|Any CPU.Build.0 = Release|Any CPU
		{C8BD72CC-5DDA-4A81-8A5B-FB411D1707ED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
		{C8BD72CC-5DDA-4A81-8A5B-FB411D1707ED}.Debug|Any CPU.Build.0 = Debug|Any CPU
		{C8BD72CC-5DDA-4A81-8A5B-FB411D1707ED}.Release|Any CPU.ActiveCfg = Release|Any CPU
		{C8BD72CC-5DDA-4A81-8A5B-FB411D1707ED}.Release|Any CPU.Build.0 = Release|Any CPU
		{DAD4D4A1-9AEB-46CF-A143-D19C1EB9C36D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
		{DAD4D4A1-9AEB-46CF-A143-D19C1EB9C36D}.Debug|Any CPU.Build.0 = Debug|Any CPU
		{DAD4D4A1-9AEB-46CF-A143-D19C1EB9C36D}.Release|Any CPU.ActiveCfg = Release|Any CPU
		{DAD4D4A1-9AEB-46CF-A143-D19C1EB9C36D}.Release|Any CPU.Build.0 = Release|Any CPU
		{F26D75D9-B050-4F78-8911-65780DF78BA5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
		{F26D75D9-B050-4F78-8911-65780DF78BA5}.Debug|Any CPU.Build.0 = Debug|Any CPU
		{F26D75D9-B050-4F78-8911-65780DF78BA5}.Release|Any CPU.ActiveCfg = Release|Any CPU
		{F26D75D9-B050-4F78-8911-65780DF78BA5}.Release|Any CPU.Build.0 = Release|Any CPU
		{334B2EC6-F84D-47F2-83C3-7F4FECAA1163}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
		{334B2EC6-F84D-47F2-83C3-7F4FECAA1163}.Debug|Any CPU.Build.0 = Debug|Any CPU
		{334B2EC6-F84D-47F2-83C3-7F4FECAA1163}.Release|Any CPU.ActiveCfg = Release|Any CPU
		{334B2EC6-F84D-47F2-83C3-7F4FECAA1163}.Release|Any CPU.Build.0 = Release|Any CPU
		{5547B022-4512-4765-A762-121A77F9D204}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
		{5547B022-4512-4765-A762-121A77F9D204}.Debug|Any CPU.Build.0 = Debug|Any CPU
		{5547B022-4512-4765-A762-121A77F9D204}.Release|Any CPU.ActiveCfg = Release|Any CPU
		{5547B022-4512-4765-A762-121A77F9D204}.Release|Any CPU.Build.0 = Release|Any CPU
		{884BB166-77C2-4B71-9E97-9739616120B4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
		{884BB166-77C2-4B71-9E97-9739616120B4}.Debug|Any CPU.Build.0 = Debug|Any CPU
		{884BB166-77C2-4B71-9E97-9739616120B4}.Release|Any CPU.ActiveCfg = Release|Any CPU
		{884BB166-77C2-4B71-9E97-9739616120B4}.Release|Any CPU.Build.0 = Release|Any CPU
		{2318E480-B8A6-40F4-84E4-55A8162A4969}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
		{2318E480-B8A6-40F4-84E4-55A8162A4969}.Debug|Any CPU.Build.0 = Debug|Any CPU
		{2318E480-B8A6-40F4-84E4-55A8162A4969}.Release|Any CPU.ActiveCfg = Release|Any CPU
		{2318E480-B8A6-40F4-84E4-55A8162A4969}.Release|Any CPU.Build.0 = Release|Any CPU
		{14C156A3-CDE8-4501-A61A-1FF511F6255E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
		{14C156A3-CDE8-4501-A61A-1FF511F6255E}.Debug|Any CPU.Build.0 = Debug|Any CPU
		{14C156A3-CDE8-4501-A61A-1FF511F6255E}.Release|Any CPU.ActiveCfg = Release|Any CPU
		{14C156A3-CDE8-4501-A61A-1FF511F6255E}.Release|Any CPU.Build.0 = Release|Any CPU
		{3C7D0E5D-90CE-469B-AC79-1B89EEEFE3B8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
		{3C7D0E5D-90CE-469B-AC79-1B89EEEFE3B8}.Debug|Any CPU.Build.0 = Debug|Any CPU
		{3C7D0E5D-90CE-469B-AC79-1B89EEEFE3B8}.Release|Any CPU.ActiveCfg = Release|Any CPU
		{3C7D0E5D-90CE-469B-AC79-1B89EEEFE3B8}.Release|Any CPU.Build.0 = Release|Any CPU
	EndGlobalSection
	GlobalSection(SolutionProperties) = preSolution
		HideSolutionNode = FALSE
	EndGlobalSection
	GlobalSection(NestedProjects) = preSolution
		{653AE14C-8DD7-4E9C-96B5-D6B99C1D0CF7} = {087760BA-AF35-40D8-8779-01B3C48D3EF4}
		{A6F2D049-4B6E-4805-889F-49D113927DA6} = {653AE14C-8DD7-4E9C-96B5-D6B99C1D0CF7}
		{9830C312-7C6A-4AAE-9700-AF8E2BCF942D} = {087760BA-AF35-40D8-8779-01B3C48D3EF4}
		{820840D7-0105-4611-B956-235D6EE15191} = {9830C312-7C6A-4AAE-9700-AF8E2BCF942D}
		{4166A6E7-178A-4FDE-B7BD-33C5833F9472} = {087760BA-AF35-40D8-8779-01B3C48D3EF4}
		{C8BD72CC-5DDA-4A81-8A5B-FB411D1707ED} = {4166A6E7-178A-4FDE-B7BD-33C5833F9472}
		{DAD4D4A1-9AEB-46CF-A143-D19C1EB9C36D} = {4166A6E7-178A-4FDE-B7BD-33C5833F9472}
		{69172560-B5A3-488A-A715-2754C6FA6C5D} = {087760BA-AF35-40D8-8779-01B3C48D3EF4}
		{F26D75D9-B050-4F78-8911-65780DF78BA5} = {69172560-B5A3-488A-A715-2754C6FA6C5D}
		{334B2EC6-F84D-47F2-83C3-7F4FECAA1163} = {69172560-B5A3-488A-A715-2754C6FA6C5D}
		{5547B022-4512-4765-A762-121A77F9D204} = {69172560-B5A3-488A-A715-2754C6FA6C5D}
		{884BB166-77C2-4B71-9E97-9739616120B4} = {69172560-B5A3-488A-A715-2754C6FA6C5D}
		{2318E480-B8A6-40F4-84E4-55A8162A4969} = {697BC681-3FB0-437B-9BB9-AF5BA4C929E0}
		{14C156A3-CDE8-4501-A61A-1FF511F6255E} = {9B4D3E8A-2363-4DB9-8B9A-CC7803EE3F86}
		{3C7D0E5D-90CE-469B-AC79-1B89EEEFE3B8} = {9B4D3E8A-2363-4DB9-8B9A-CC7803EE3F86}
	EndGlobalSection
	GlobalSection(ExtensibilityGlobals) = postSolution
		SolutionGuid = {A359A298-1C98-4D56-886A-777076E176E4}
	EndGlobalSection
EndGlobal


================================================
FILE: README.md
================================================
# OnlineShop

🚀 **OnlineShop** is a comprehensive and feature-rich template repository for building robust .NET 8 applications.

---

## ⭐ Star This Repository!

---

## 🌟 What’s Inside OnlineShop?

This repository is packed with:

### 🌐 Services
- ➡ **Basket**
- ➡ **Catalog**
- ➡ **Discount**
- ➡ **Ordering**

### 🛑 APIGateways & BuildingBlocks
- ➡ **Clean Architecture** for scalable applications
- ➡ **CQRS pattern** for separating read and write operations
- ➡ **Unit of Work** & **Repository patterns**
- ➡ **EF Core** & **Dapper** for data access

### 🗄️ Database & Caching Support
- ➡ **SQLServer**, **Postgres**, & **MongoDB**
- ➡ **Redis** for high-performance caching

### 🛠 Middleware & Error Handling
- ➡ **BaseResult pattern** for uniform API responses
- ➡ **RabbitMQ** for messaging and background jobs

### 📊 Load Balancing & Aggregator
- ➡ **YARP** for Load Balancing
- ➡ **Ocelot** for API Gateway

### 🚀 API & Authentication
- ➡ **JWT tokens** & **OAuth** for secure authentication and authorization

### 🐳 Docker & DevOps
- ➡ **Docker** support for containerization
- ➡ **pgAdmin** for database management
- ➡ **Portainer** for easy Docker management

### 📋 Swagger & API Management
- ➡ Fully configured **Swagger** with security and examples

### 📌 Additional Tools & Patterns
- ➡ **Custom Exceptions** and **Pagination Handlers**
- ➡ Best practices in **DDD** and **OOP**

---

## 🔗 Explore the Repository

You can find all these features and more in the **OnlineShop** repository on GitHub. Feel free to **explore**, **fork**, and **contribute**!

👉 [OnlineShop on GitHub](https://lnkd.in/d9aruGDU)

---

## 🤝 Get Involved!

Contributions, feedback, and suggestions are highly welcome! Let’s collaborate to make **OnlineShop** even better.

---

## Stay Connected

- **GitHub**: [BehzadDara](https://github.com/BehzadDara)
- **LinkedIn**: [Behzad Dara](https://www.linkedin.com/in/behzaddara/)


================================================
FILE: Services/Basket/Basket.Api/Basket.Api.csproj
================================================
<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
    <InvariantGlobalization>true</InvariantGlobalization>
    <DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
    <DockerfileContext>..\..\..</DockerfileContext>
    <DockerComposeProjectPath>..\..\..\docker-compose.dcproj</DockerComposeProjectPath>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="12.0.1" />
    <PackageReference Include="Grpc.AspNetCore" Version="2.59.0" />
    <PackageReference Include="MassTransit" Version="8.1.2" />
    <PackageReference Include="MassTransit.RabbitMQ" Version="8.1.2" />
    <PackageReference Include="Microsoft.Extensions.Caching.StackExchangeRedis" Version="8.0.0" />
    <PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.19.5" />
    <PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
    <PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
  </ItemGroup>

  <ItemGroup>
    <ProjectReference Include="..\..\..\BuildingBlocks\EventBus.Messages\EventBus.Messages.csproj" />
  </ItemGroup>

  <ItemGroup>
    <Protobuf Include="..\..\Discount\Discount.Grpc\Protos\discount.proto" GrpcServices="Client">
      <Link>Protos\discount.proto</Link>
    </Protobuf>
  </ItemGroup>

</Project>


================================================
FILE: Services/Basket/Basket.Api/Basket.Api.http
================================================
@Basket.Api_HostAddress = http://localhost:5033

GET {{Basket.Api_HostAddress}}/weatherforecast/
Accept: application/json

###


================================================
FILE: Services/Basket/Basket.Api/Controllers/OrderController.cs
================================================
using AutoMapper;
using Basket.Api.Entities;
using Basket.Api.GrpcServices;
using Basket.Api.Repositories;
using EventBus.Messages.Events;
using MassTransit;
using MassTransit.Transports;
using Microsoft.AspNetCore.Mvc;
using System.Net;

namespace Basket.Api.Controllers
{
    [Route("api/v1/[controller]/[action]")]
    [ApiController]
    public class OrderController(
        IOrderRepository _orderRepository, 
        DiscountGrpcService _discountService,
        IMapper _mapper,
        IPublishEndpoint _publishEndpoint
        ) : ControllerBase
    {
        [HttpGet("{userName}")]
        [ProducesResponseType(typeof(Order), (int)HttpStatusCode.OK)]
        public async Task<ActionResult<Order>> GetByUserName(string userName)
        {
            var result = await _orderRepository.GetByUserName(userName);
            return Ok(result);
        }

        [HttpPost]
        [ProducesResponseType(typeof(Order), (int)HttpStatusCode.OK)]
        public async Task<ActionResult<Order>> Update([FromBody] Order order)
        {
            foreach (var orderItem in order.Items)
            {
                var coupon = await _discountService.GetDiscount(orderItem.ProductName);
                orderItem.Price -= coupon.Amount;
            }

            var result = await _orderRepository.Update(order);
            return Ok(result);
        }

        [HttpDelete("{userName}")]
        [ProducesResponseType(typeof(void), (int)HttpStatusCode.OK)]
        public async Task<IActionResult> Delete(string userName)
        {
            await _orderRepository.Delete(userName);
            return Ok();
        }

        [HttpPost]
        [ProducesResponseType((int)HttpStatusCode.Accepted)]
        [ProducesResponseType((int)HttpStatusCode.BadRequest)]
        public async Task<IActionResult> Checkout([FromBody] BasketCheckout basketCheckout)
        {
            var basket = await _orderRepository.GetByUserName(basketCheckout.UserName);
            if (basket is null)
            {
                return BadRequest();
            }

            var eventMessage = _mapper.Map<BasketCheckoutEvent>(basketCheckout);
            eventMessage.TotalPrice = basket.TotalPrice;

            await _publishEndpoint.Publish(eventMessage);

            await _orderRepository.Delete(basketCheckout.UserName);

            return Accepted();
        }
    }
}


================================================
FILE: Services/Basket/Basket.Api/Dockerfile
================================================
#See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging.

FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
USER app
WORKDIR /app
EXPOSE 8080

FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
ARG BUILD_CONFIGURATION=Release
WORKDIR /src
COPY ["Services/Basket/Basket.Api/Basket.Api.csproj", "Services/Basket/Basket.Api/"]
COPY ["BuildingBlocks/EventBus.Messages/EventBus.Messages.csproj", "BuildingBlocks/EventBus.Messages/"]
RUN dotnet restore "./Services/Basket/Basket.Api/./Basket.Api.csproj"
COPY . .
WORKDIR "/src/Services/Basket/Basket.Api"
RUN dotnet build "./Basket.Api.csproj" -c $BUILD_CONFIGURATION -o /app/build

FROM build AS publish
ARG BUILD_CONFIGURATION=Release
RUN dotnet publish "./Basket.Api.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "Basket.Api.dll"]

================================================
FILE: Services/Basket/Basket.Api/Entities/BasketCheckout.cs
================================================
namespace Basket.Api.Entities;

public class BasketCheckout
{
    public string UserName { get; set; } = string.Empty;
    public decimal TotalPrice { get; set; }

    public string FirstName { get; set; } = string.Empty;
    public string LastName { get; set; } = string.Empty;
    public string EmailAddress { get; set; } = string.Empty;
    public string Country { get; set; } = string.Empty;
    public string City { get; set; } = string.Empty;

    public string BankName { get; set; } = string.Empty;
    public string RefCode { get; set; } = string.Empty;
    public int PaymentMethod { get; set; }
}


================================================
FILE: Services/Basket/Basket.Api/Entities/Order.cs
================================================
namespace Basket.Api.Entities;

public class Order(string userName)
{
    public string UserName { get; set; } = userName;
    public List<OrderItem> Items { get; set; } = [];
    public decimal TotalPrice 
    { 
        get 
        {
            return Items.Sum(x => x.Quantity * x.Price);
        } 
    }
}


================================================
FILE: Services/Basket/Basket.Api/Entities/OrderItem.cs
================================================
namespace Basket.Api.Entities;

public class OrderItem
{
    public int Quantity { get; set; }
    public string Color { get; set; } = string.Empty;
    public decimal Price { get; set; }
    public string ProductId { get; set; } = string.Empty;
    public string ProductName { get; set; } = string.Empty;
}


================================================
FILE: Services/Basket/Basket.Api/GrpcServices/DiscountGrpcService.cs
================================================
using Discount.Grpc.Protos;

namespace Basket.Api.GrpcServices;

public class DiscountGrpcService(DiscountProtoService.DiscountProtoServiceClient _discountProtoService)
{
    public async Task<CouponModel> GetDiscount(string ProductName)
    {
        var discountRequest = new GetDiscountRequest { ProductName = ProductName };
        return await _discountProtoService.GetDiscountAsync(discountRequest);
    }
}


================================================
FILE: Services/Basket/Basket.Api/Mapper/BasketProfile.cs
================================================
using AutoMapper;
using Basket.Api.Entities;
using EventBus.Messages.Events;

namespace Basket.Api.Mapper;

public class BasketProfile : Profile
{
    public BasketProfile()
    {
        CreateMap<BasketCheckout, BasketCheckoutEvent>().ReverseMap();
    }
}


================================================
FILE: Services/Basket/Basket.Api/Program.cs
================================================
using Basket.Api.GrpcServices;
using Basket.Api.Repositories;
using Discount.Grpc.Protos;
using MassTransit;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddStackExchangeRedisCache(options =>
{
    options.Configuration = builder.Configuration.GetValue<string>("CacheSettings:ConnectionString");
});

builder.Services.AddControllers();

builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

builder.Services.AddGrpcClient<DiscountProtoService.DiscountProtoServiceClient>(options =>
{
    options.Address = new Uri(builder.Configuration.GetValue<string>("GrpcSettings:DiscountUrl") ?? "");
});
builder.Services.AddScoped<DiscountGrpcService>();
builder.Services.AddScoped<IOrderRepository, OrderRepository>();

builder.Services.AddMassTransit(config =>
{
    config.UsingRabbitMq((context, conf) =>
    {
        conf.Host(builder.Configuration.GetValue<string>("EventBusSettings:HostAddress"));
    });
});

builder.Services.AddAutoMapper(typeof(Program));

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.MapControllers();

app.Run();

================================================
FILE: Services/Basket/Basket.Api/Properties/launchSettings.json
================================================
{
  "profiles": {
    "Basket.Api": {
      "commandName": "Project",
      "launchBrowser": true,
      "launchUrl": "swagger",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      },
      "dotnetRunMessages": true,
      "applicationUrl": "http://localhost:5001"
    },
    "IIS Express": {
      "commandName": "IISExpress",
      "launchBrowser": true,
      "launchUrl": "swagger",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    },
    "Docker": {
      "commandName": "Docker",
      "launchBrowser": true,
      "launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/swagger",
      "environmentVariables": {
        "ASPNETCORE_HTTP_PORTS": "8001"
      },
      "publishAllPorts": true
    }
  },
  "$schema": "http://json.schemastore.org/launchsettings.json",
  "iisSettings": {
    "windowsAuthentication": false,
    "anonymousAuthentication": true,
    "iisExpress": {
      "applicationUrl": "http://localhost:19262",
      "sslPort": 0
    }
  }
}

================================================
FILE: Services/Basket/Basket.Api/Repositories/IOrderRepository.cs
================================================
using Basket.Api.Entities;

namespace Basket.Api.Repositories;

public interface IOrderRepository
{
    Task<Order> GetByUserName(string userName);
    Task<Order> Update(Order order);
    Task Delete(string userName);
}


================================================
FILE: Services/Basket/Basket.Api/Repositories/OrderRepository.cs
================================================
using Basket.Api.Entities;
using Microsoft.Extensions.Caching.Distributed;
using Newtonsoft.Json;

namespace Basket.Api.Repositories;

public class OrderRepository(IDistributedCache _redisCache) : IOrderRepository
{
    public async Task<Order> GetByUserName(string userName)
    {
        var result = await _redisCache.GetStringAsync(userName);
        if (string.IsNullOrEmpty(result))
        {
            return new Order(userName);
        }

        var order = JsonConvert.DeserializeObject<Order>(result);
        if (order is null)
        {
            return new Order(userName);
        }

        return order;
    }

    public async Task<Order> Update(Order order)
    {
        await _redisCache.SetStringAsync(order.UserName, JsonConvert.SerializeObject(order));
        return await GetByUserName(order.UserName);
    }
    public async Task Delete(string userName)
    {
        await _redisCache.RemoveAsync(userName);
    }
}


================================================
FILE: Services/Basket/Basket.Api/appsettings.Development.json
================================================
{
  "CacheSettings": {
    "ConnectionString": "localhost:6379"
  },
  "GrpcSettings": {
    "DiscountUrl": "http://localhost:5003"
  },
  "EventBusSettings": {
    "HostAddress": "amqp://guest:guest@localhost:5672"
  },
    "Logging": {
      "LogLevel": {
        "Default": "Information",
        "Microsoft.AspNetCore": "Warning"
      }
    }
  }


================================================
FILE: Services/Basket/Basket.Api/appsettings.json
================================================
{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*"
}


================================================
FILE: Services/Catalog/Catalog.Api/Catalog.Api.csproj
================================================
<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
    <InvariantGlobalization>true</InvariantGlobalization>
    <DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
    <DockerfileContext>..\..\..</DockerfileContext>
    <DockerComposeProjectPath>..\..\..\docker-compose.dcproj</DockerComposeProjectPath>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.19.5" />
    <PackageReference Include="MongoDB.Driver" Version="2.22.0" />
    <PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
  </ItemGroup>

</Project>


================================================
FILE: Services/Catalog/Catalog.Api/Catalog.Api.http
================================================
@Catalog.Api_HostAddress = http://localhost:5049

GET {{Catalog.Api_HostAddress}}/weatherforecast/
Accept: application/json

###


================================================
FILE: Services/Catalog/Catalog.Api/Controllers/ProductController.cs
================================================
using Catalog.Api.Entities;
using Catalog.Api.Repositories;
using Microsoft.AspNetCore.Mvc;
using System.Net;

namespace Catalog.Api.Controllers
{
    [Route("api/v1/[controller]/[action]")]
    [ApiController]
    public class ProductController(IProductRepository _productRepository, ILogger<ProductController> _logger) : ControllerBase
    {
        [HttpGet]
        [ProducesResponseType(typeof(IEnumerable<Product>), (int)HttpStatusCode.OK)]
        public async Task<ActionResult<IEnumerable<Product>>> GetAll()
        {
            var result = await _productRepository.GetAll();
            return Ok(result);
        }

        [HttpGet("{id:length(24)}")]
        [ProducesResponseType((int)HttpStatusCode.NotFound)]
        [ProducesResponseType(typeof(Product), (int)HttpStatusCode.OK)]
        public async Task<ActionResult<Product>> GetById(string id)
        {
            var result = await _productRepository.GetById(id);
            if (result is null)
            {
                _logger.LogError($"product with id: {id} not found.");
                return NotFound();
            }
            return Ok(result);
        }

        [HttpGet("{name}")]
        [ProducesResponseType((int)HttpStatusCode.NotFound)]
        [ProducesResponseType(typeof(Product), (int)HttpStatusCode.OK)]
        public async Task<ActionResult<Product>> GetByName(string name)
        {
            var result = await _productRepository.GetByName(name);
            if (result is null)
            {
                _logger.LogError($"product with name: {name} not found.");
                return NotFound();
            }
            return Ok(result);
        }

        [HttpGet("{category}")]
        [ProducesResponseType(typeof(Product), (int)HttpStatusCode.OK)]
        public async Task<ActionResult<IEnumerable<Product>>> GetByCategory(string category)
        {
            var result = await _productRepository.GetByCategory(category);
            return Ok(result);
        }

        [HttpPost]
        [ProducesResponseType(typeof(Product), (int)HttpStatusCode.OK)]
        public async Task<ActionResult<IEnumerable<Product>>> Create([FromBody] Product product)
        {
            await _productRepository.Create(product);
            return CreatedAtRoute("GetProduct", new { id = product.Id}, product);
        }

        [HttpPut]
        [ProducesResponseType(typeof(Product), (int)HttpStatusCode.OK)]
        public async Task<ActionResult<IEnumerable<Product>>> Update([FromBody] Product product)
        {
            var result = await _productRepository.Update(product);
            return Ok(result);
        }

        [HttpDelete("{id:length(24)}")]
        [ProducesResponseType(typeof(Product), (int)HttpStatusCode.OK)]
        public async Task<ActionResult<IEnumerable<Product>>> Delete(string id)
        {
            var result = await _productRepository.Delete(id);
            return Ok(result);
        }
    }
}


================================================
FILE: Services/Catalog/Catalog.Api/Data/CatalogContext.cs
================================================
using Catalog.Api.Entities;
using MongoDB.Driver;

namespace Catalog.Api.Data;

public class CatalogContext : ICatalogContext
{
    public CatalogContext(IConfiguration configuration)
    {
        var client = new MongoClient(configuration.GetValue<string>("DatabaseSettings:ConnectionString"));
        var database = client.GetDatabase(configuration.GetValue<string>("DatabaseSettings:DatabaseName"));
        Products = database.GetCollection<Product>(configuration.GetValue<string>("DatabaseSettings:CollectionName"));
        CatalogContextSeed.SeedData(Products);
    }

    public IMongoCollection<Product> Products { get; }
}


================================================
FILE: Services/Catalog/Catalog.Api/Data/CatalogContextSeed.cs
================================================
using Catalog.Api.Entities;
using MongoDB.Driver;

namespace Catalog.Api.Data;

public class CatalogContextSeed
{
    public static void SeedData(IMongoCollection<Product> productCollection)
    {
        var existProduct = productCollection.Find(x => true).Any();
        if (!existProduct)
        {
            productCollection.InsertManyAsync(GetSeedData());
        }
    }

    private static List<Product> GetSeedData()
    {
        return
            [
                new()
                {
                    Id = "602d2149e773f2a3990b47f5",
                    Name = "IPhone X",
                    Summary = "This phone is the company's biggest change to its flagship smartphone in years. It includes a borderless.",
                    Description = "Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ut, tenetur natus doloremque laborum quos iste ipsum rerum obcaecati impedit odit illo dolorum ab tempora nihil dicta earum fugiat. Temporibus, voluptatibus. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ut, tenetur natus doloremque laborum quos iste ipsum rerum obcaecati impedit odit illo dolorum ab tempora nihil dicta earum fugiat. Temporibus, voluptatibus.",
                    ImageFile = "product-1.png",
                    Price = 950.00M,
                    Category = "Smart Phone"
                },
                new()
                {
                    Id = "602d2149e773f2a3990b47f6",
                    Name = "Samsung 10",
                    Summary = "This phone is the company's biggest change to its flagship smartphone in years. It includes a borderless.",
                    Description = "Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ut, tenetur natus doloremque laborum quos iste ipsum rerum obcaecati impedit odit illo dolorum ab tempora nihil dicta earum fugiat. Temporibus, voluptatibus. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ut, tenetur natus doloremque laborum quos iste ipsum rerum obcaecati impedit odit illo dolorum ab tempora nihil dicta earum fugiat. Temporibus, voluptatibus.",
                    ImageFile = "product-2.png",
                    Price = 840.00M,
                    Category = "Smart Phone"
                },
                new()
                {
                    Id = "602d2149e773f2a3990b47f7",
                    Name = "Huawei Plus",
                    Summary = "This phone is the company's biggest change to its flagship smartphone in years. It includes a borderless.",
                    Description = "Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ut, tenetur natus doloremque laborum quos iste ipsum rerum obcaecati impedit odit illo dolorum ab tempora nihil dicta earum fugiat. Temporibus, voluptatibus. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ut, tenetur natus doloremque laborum quos iste ipsum rerum obcaecati impedit odit illo dolorum ab tempora nihil dicta earum fugiat. Temporibus, voluptatibus.",
                    ImageFile = "product-3.png",
                    Price = 650.00M,
                    Category = "White Appliances"
                },
                new()
                {
                    Id = "602d2149e773f2a3990b47f8",
                    Name = "Xiaomi Mi 9",
                    Summary = "This phone is the company's biggest change to its flagship smartphone in years. It includes a borderless.",
                    Description = "Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ut, tenetur natus doloremque laborum quos iste ipsum rerum obcaecati impedit odit illo dolorum ab tempora nihil dicta earum fugiat. Temporibus, voluptatibus. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ut, tenetur natus doloremque laborum quos iste ipsum rerum obcaecati impedit odit illo dolorum ab tempora nihil dicta earum fugiat. Temporibus, voluptatibus.",
                    ImageFile = "product-4.png",
                    Price = 470.00M,
                    Category = "White Appliances"
                },
                new()
                {
                    Id = "602d2149e773f2a3990b47f9",
                    Name = "HTC U11+ Plus",
                    Summary = "This phone is the company's biggest change to its flagship smartphone in years. It includes a borderless.",
                    Description = "Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ut, tenetur natus doloremque laborum quos iste ipsum rerum obcaecati impedit odit illo dolorum ab tempora nihil dicta earum fugiat. Temporibus, voluptatibus. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ut, tenetur natus doloremque laborum quos iste ipsum rerum obcaecati impedit odit illo dolorum ab tempora nihil dicta earum fugiat. Temporibus, voluptatibus.",
                    ImageFile = "product-5.png",
                    Price = 380.00M,
                    Category = "Smart Phone"
                },
                new()
                {
                    Id = "602d2149e773f2a3990b47fa",
                    Name = "LG G7 ThinQ",
                    Summary = "This phone is the company's biggest change to its flagship smartphone in years. It includes a borderless.",
                    Description = "Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ut, tenetur natus doloremque laborum quos iste ipsum rerum obcaecati impedit odit illo dolorum ab tempora nihil dicta earum fugiat. Temporibus, voluptatibus. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ut, tenetur natus doloremque laborum quos iste ipsum rerum obcaecati impedit odit illo dolorum ab tempora nihil dicta earum fugiat. Temporibus, voluptatibus.",
                    ImageFile = "product-6.png",
                    Price = 240.00M,
                    Category = "Home Kitchen"
                }
            ];
    }
}


================================================
FILE: Services/Catalog/Catalog.Api/Data/ICatalogContext.cs
================================================
using Catalog.Api.Entities;
using MongoDB.Driver;

namespace Catalog.Api.Data;

public interface ICatalogContext
{
    IMongoCollection<Product> Products { get; }
}


================================================
FILE: Services/Catalog/Catalog.Api/Dockerfile
================================================
#See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging.

FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
USER app
WORKDIR /app
EXPOSE 8080

FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
ARG BUILD_CONFIGURATION=Release
WORKDIR /src
COPY ["Services/Catalog/Catalog.Api/Catalog.Api.csproj", "Services/Catalog/Catalog.Api/"]
RUN dotnet restore "./Services/Catalog/Catalog.Api/./Catalog.Api.csproj"
COPY . .
WORKDIR "/src/Services/Catalog/Catalog.Api"
RUN dotnet build "./Catalog.Api.csproj" -c $BUILD_CONFIGURATION -o /app/build

FROM build AS publish
ARG BUILD_CONFIGURATION=Release
RUN dotnet publish "./Catalog.Api.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "Catalog.Api.dll"]

================================================
FILE: Services/Catalog/Catalog.Api/Entities/Product.cs
================================================
using MongoDB.Bson;
using MongoDB.Bson.Serialization.Attributes;

namespace Catalog.Api.Entities;

public class Product
{
    [BsonId]
    [BsonRepresentation(BsonType.ObjectId)]
    public string Id { get; set; } = string.Empty;
    [BsonElement("Name")]
    public string Name { get; set; } = string.Empty;
    public string Category { get; set; } = string.Empty;
    public string Summary { get; set; } = string.Empty;
    public string Description { get; set; } = string.Empty;
    public string ImageFile { get; set; } = string.Empty;
    public decimal Price { get; set; }
}


================================================
FILE: Services/Catalog/Catalog.Api/Products.Json
================================================
[
  {
    "Name": "Asus Laptop",
    "Category": "Computers",
    "Summary": "Summary",
    "Description": "Description",
    "ImageFile": "ImageFile",
    "Price": "100"
  },
  {
    "Name": "HP Laptop",
    "Category": "Computers",
    "Summary": "Summary",
    "Description": "Description",
    "ImageFile": "ImageFile",
    "Price": "200"
  }
]

================================================
FILE: Services/Catalog/Catalog.Api/Program.cs
================================================
using Catalog.Api.Data;
using Catalog.Api.Repositories;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();

builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

builder.Services.AddScoped<ICatalogContext, CatalogContext>();
builder.Services.AddScoped<IProductRepository, ProductRepository>();

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.MapControllers();

app.Run();


================================================
FILE: Services/Catalog/Catalog.Api/Properties/launchSettings.json
================================================
{
  "profiles": {
    "Catalog.Api": {
      "commandName": "Project",
      "launchBrowser": true,
      "launchUrl": "swagger",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      },
      "dotnetRunMessages": true,
      "applicationUrl": "http://localhost:5000"
    },
    "IIS Express": {
      "commandName": "IISExpress",
      "launchBrowser": true,
      "launchUrl": "swagger",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    },
    "Docker": {
      "commandName": "Docker",
      "launchBrowser": true,
      "launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/swagger",
      "environmentVariables": {
        "ASPNETCORE_HTTP_PORTS": "8000"
      },
      "publishAllPorts": true
    }
  },
  "$schema": "http://json.schemastore.org/launchsettings.json",
  "iisSettings": {
    "windowsAuthentication": false,
    "anonymousAuthentication": true,
    "iisExpress": {
      "applicationUrl": "http://localhost:57789",
      "sslPort": 0
    }
  }
}

================================================
FILE: Services/Catalog/Catalog.Api/Repositories/IProductRepository.cs
================================================
using Catalog.Api.Entities;

namespace Catalog.Api.Repositories;

public interface IProductRepository
{
    Task<IEnumerable<Product>> GetAll();
    Task<Product> GetById(string id);
    Task<Product> GetByName(string name);
    Task<IEnumerable<Product>> GetByCategory(string category);
    Task Create(Product product);
    Task<bool> Update(Product product);
    Task<bool> Delete(string id);
}


================================================
FILE: Services/Catalog/Catalog.Api/Repositories/ProductRepository.cs
================================================
using Catalog.Api.Data;
using Catalog.Api.Entities;
using MongoDB.Driver;

namespace Catalog.Api.Repositories;

public class ProductRepository(ICatalogContext _catalogContext) : IProductRepository
{
    public async Task<IEnumerable<Product>> GetAll()
    {
        return await _catalogContext.Products.Find(x => true).ToListAsync();
    }
    public async Task<Product> GetById(string id)
    {
        return await _catalogContext.Products.Find(x => x.Id == id).FirstOrDefaultAsync();
    }
    public async Task<Product> GetByName(string name)
    {
        return await _catalogContext.Products.Find(x => x.Name == name).FirstOrDefaultAsync();
    }
    public async Task<IEnumerable<Product>> GetByCategory(string category)
    {
        return await _catalogContext.Products.Find(x => x.Category == category).ToListAsync();
    }
    public async Task Create(Product product)
    {
        await _catalogContext.Products.InsertOneAsync(product);
    }
    public async Task<bool> Update(Product product)
    {
        var result = await _catalogContext.Products.ReplaceOneAsync(x => x.Id == product.Id, product);
        return result.IsAcknowledged && result.ModifiedCount > 0;
    }
    public async Task<bool> Delete(string id)
    {
        var result = await _catalogContext.Products.DeleteOneAsync(x => x.Id == id);
        return result.IsAcknowledged && result.DeletedCount > 0;
    }
} 


================================================
FILE: Services/Catalog/Catalog.Api/appsettings.Development.json
================================================
{
  "DatabaseSettings": {
    "ConnectionString": "localhost://catalogdb:27017",
    "DatabaseName": "CatalogDB",
    "CollectionName": "Products"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  }
}


================================================
FILE: Services/Catalog/Catalog.Api/appsettings.json
================================================
{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*"
}


================================================
FILE: Services/Discount/Discount.Api/Controllers/CouponController.cs
================================================
using Discount.Api.Entities;
using Discount.Api.Repositories;
using Microsoft.AspNetCore.Mvc;
using System.Net;

namespace Discount.Api.Controllers
{
    [Route("api/v1/[controller]/[action]")]
    [ApiController]
    public class CouponController(ICouponRepository _couponRepository) : ControllerBase
    {
        [HttpGet("{productName}")]
        [ProducesResponseType(typeof(Coupon), (int)HttpStatusCode.OK)]
        public async Task<ActionResult<Coupon>> GetByProductName(string productName)
        {
            var result = await _couponRepository.GetByProductName(productName);
            return Ok(result);
        }

        [HttpPost]
        [ProducesResponseType(typeof(Coupon), (int)HttpStatusCode.OK)]
        public async Task<ActionResult<Coupon>> Create([FromBody] Coupon coupon)
        {
            await _couponRepository.Create(coupon);
            return await GetByProductName(coupon.ProductName);
        }

        [HttpPut]
        [ProducesResponseType(typeof(Coupon), (int)HttpStatusCode.OK)]
        public async Task<ActionResult<Coupon>> Update([FromBody] Coupon coupon)
        {
            await _couponRepository.Update(coupon);
            return await GetByProductName(coupon.ProductName);
        }

        [HttpDelete("{productName}")]
        [ProducesResponseType(typeof(bool), (int)HttpStatusCode.OK)]
        public async Task<ActionResult<Coupon>> Delete(string productName)
        {
            var result = await _couponRepository.Delete(productName);
            return Ok(result);
        }
    }
}


================================================
FILE: Services/Discount/Discount.Api/Discount.Api.csproj
================================================
<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
    <InvariantGlobalization>true</InvariantGlobalization>
    <DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
    <DockerfileContext>..\..\..</DockerfileContext>
    <DockerComposeProjectPath>..\..\..\docker-compose.dcproj</DockerComposeProjectPath>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Dapper" Version="2.1.24" />
    <PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.19.5" />
    <PackageReference Include="Npgsql" Version="8.0.1" />
    <PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
  </ItemGroup>

</Project>


================================================
FILE: Services/Discount/Discount.Api/Discount.Api.http
================================================
@Discount.Api_HostAddress = http://localhost:5297

GET {{Discount.Api_HostAddress}}/weatherforecast/
Accept: application/json

###


================================================
FILE: Services/Discount/Discount.Api/Dockerfile
================================================
#See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging.

FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
USER app
WORKDIR /app
EXPOSE 8080

FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
ARG BUILD_CONFIGURATION=Release
WORKDIR /src
COPY ["Services/Discount/Discount.Api/Discount.Api.csproj", "Services/Discount/Discount.Api/"]
RUN dotnet restore "./Services/Discount/Discount.Api/./Discount.Api.csproj"
COPY . .
WORKDIR "/src/Services/Discount/Discount.Api"
RUN dotnet build "./Discount.Api.csproj" -c $BUILD_CONFIGURATION -o /app/build

FROM build AS publish
ARG BUILD_CONFIGURATION=Release
RUN dotnet publish "./Discount.Api.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "Discount.Api.dll"]

================================================
FILE: Services/Discount/Discount.Api/Entities/Coupon.cs
================================================
namespace Discount.Api.Entities;

public class Coupon
{
    public int Id { get; set; }
    public string ProductName { get; set; } = string.Empty;
    public string Description { get; set; } = string.Empty;
    public int Amount { get; set; }
}


================================================
FILE: Services/Discount/Discount.Api/Extensions/HostExtensions.cs
================================================
using Npgsql;

namespace Discount.Api.Extensions;

public static class HostExtensions
{
    public static IHost MigrateDatabase<TContext>(this IHost host, int retry = 0)
    {
        using var scope = host.Services.CreateScope();
        var services = scope.ServiceProvider;
        var configuration = services.GetRequiredService<IConfiguration>();
        var logger = services.GetRequiredService<ILogger<TContext>>();

        try
        {
            logger.LogInformation("migrating postgresql database");

            using var connection = new NpgsqlConnection
                (configuration.GetValue<string>("DatabaseSettings:ConnectionString"));
            connection.Open();

            using var command = new NpgsqlCommand
            {
                Connection = connection
            };

            command.CommandText = @"create table if not exists Coupon 
                (Id serial primary key,
                ProductName varchar(200) not null,
                Description text,
                Amount int)";
            command.ExecuteNonQuery();

            /*command.CommandText = @"insert into Coupon(ProductName, Description, Amount) values 
                ('IPhone X', 'iphone discount', 150),
                ('Samsung 10', 'samsung discount', 150)";
            command.ExecuteNonQuery();*/

            logger.LogInformation("migration has been completed!");
        }
        catch (Exception ex)
        {
            logger.LogError($"an error has been occured: {ex.Message}");

            if (retry < 50)
            {
                Thread.Sleep(2000);
                host.MigrateDatabase<TContext>(retry + 1);
            }
        }

        return host;
    }
}


================================================
FILE: Services/Discount/Discount.Api/Program.cs
================================================
using Discount.Api.Extensions;
using Discount.Api.Repositories;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();

builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

builder.Services.AddScoped<ICouponRepository, CouponRepository>();

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.MapControllers();

app.MigrateDatabase<Program>();

app.Run();


================================================
FILE: Services/Discount/Discount.Api/Properties/launchSettings.json
================================================
{
  "profiles": {
    "Discount.Api": {
      "commandName": "Project",
      "launchBrowser": true,
      "launchUrl": "swagger",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      },
      "dotnetRunMessages": true,
      "applicationUrl": "http://localhost:5002"
    },
    "IIS Express": {
      "commandName": "IISExpress",
      "launchBrowser": true,
      "launchUrl": "swagger",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    },
    "Docker": {
      "commandName": "Docker",
      "launchBrowser": true,
      "launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/swagger",
      "environmentVariables": {
        "ASPNETCORE_HTTP_PORTS": "8080"
      },
      "publishAllPorts": true
    }
  },
  "$schema": "http://json.schemastore.org/launchsettings.json",
  "iisSettings": {
    "windowsAuthentication": false,
    "anonymousAuthentication": true,
    "iisExpress": {
      "applicationUrl": "http://localhost:18137",
      "sslPort": 0
    }
  }
}

================================================
FILE: Services/Discount/Discount.Api/Repositories/CouponRepository.cs
================================================
using Dapper;
using Discount.Api.Entities;
using Npgsql;

namespace Discount.Api.Repositories;

public class CouponRepository(IConfiguration _configuration) : ICouponRepository
{
    public async Task<Coupon> GetByProductName(string productName)
    {
        using var connection = new NpgsqlConnection
            (_configuration.GetValue<string>("DatabaseSettings:ConnectionString"));

        var coupon = await connection.QueryFirstOrDefaultAsync<Coupon>
            ($"select * from Coupon where ProductName = '{productName}'");
        if (coupon is null)
        {
            return new Coupon
            {
                ProductName = productName,
                Description = "No discount",
                Amount = 0
            };
        }

        return coupon;
    }

    public async Task<bool> Create(Coupon coupon)
    {
        using var connection = new NpgsqlConnection
            (_configuration.GetValue<string>("DatabaseSettings:ConnectionString"));

        var affected = await connection.ExecuteAsync
            ($"insert into Coupon(ProductName, Description, Amount) " +
            $"values('{coupon.ProductName}', '{coupon.Description}', {coupon.Amount})");

        return affected > 0;
    }

    public async Task<bool> Update(Coupon coupon)
    {
        using var connection = new NpgsqlConnection
            (_configuration.GetValue<string>("DatabaseSettings:ConnectionString"));

        var affected = await connection.ExecuteAsync
            ($"update Coupon " +
            $"set ProductName = '{coupon.ProductName}', Description = '{coupon.Description}', Amount = {coupon.Amount} " +
            $"where Id = {coupon.Id}");

        return affected > 0;
    }

    public async Task<bool> Delete(string productName)
    {
        using var connection = new NpgsqlConnection
            (_configuration.GetValue<string>("DatabaseSettings:ConnectionString"));

        var affected = await connection.ExecuteAsync
            ($"delete from Coupon where ProductName = {productName}");

        return affected > 0;
    }
}


================================================
FILE: Services/Discount/Discount.Api/Repositories/ICouponRepository.cs
================================================
using Discount.Api.Entities;

namespace Discount.Api.Repositories;

public interface ICouponRepository
{
    Task<Coupon> GetByProductName(string productName);
    Task<bool> Create(Coupon coupon);
    Task<bool> Update(Coupon coupon);
    Task<bool> Delete(string productName);
}


================================================
FILE: Services/Discount/Discount.Api/appsettings.Development.json
================================================
{
  "DatabaseSettings": {
    "ConnectionString": "Server=localhost;port=5432;Database=discountdb;User Id=admin;Password=admin1234;"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  }
}


================================================
FILE: Services/Discount/Discount.Api/appsettings.json
================================================
{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*"
}


================================================
FILE: Services/Discount/Discount.Grpc/Discount.Grpc.csproj
================================================
<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
    <DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
    <DockerfileContext>..\..\..</DockerfileContext>
    <DockerComposeProjectPath>..\..\..\docker-compose.dcproj</DockerComposeProjectPath>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="12.0.1" />
    <PackageReference Include="Grpc.AspNetCore" Version="2.59.0" />
	  <PackageReference Include="Dapper" Version="2.1.24" />
	  <PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.19.5" />
	  <PackageReference Include="Npgsql" Version="8.0.1" />
  </ItemGroup>

  <ItemGroup>
    <Protobuf Include="Protos\discount.proto" GrpcServices="Server" />
  </ItemGroup>

</Project>


================================================
FILE: Services/Discount/Discount.Grpc/Dockerfile
================================================
#See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging.

FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
USER app
WORKDIR /app
EXPOSE 8080

FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
ARG BUILD_CONFIGURATION=Release
WORKDIR /src
COPY ["Services/Discount/Discount.Grpc/Discount.Grpc.csproj", "Services/Discount/Discount.Grpc/"]
RUN dotnet restore "./Services/Discount/Discount.Grpc/./Discount.Grpc.csproj"
COPY . .
WORKDIR "/src/Services/Discount/Discount.Grpc"
RUN dotnet build "./Discount.Grpc.csproj" -c $BUILD_CONFIGURATION -o /app/build

FROM build AS publish
ARG BUILD_CONFIGURATION=Release
RUN dotnet publish "./Discount.Grpc.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "Discount.Grpc.dll"]

================================================
FILE: Services/Discount/Discount.Grpc/Entities/Coupon.cs
================================================
namespace Discount.Grpc.Entities;

public class Coupon
{
    public int Id { get; set; }
    public string ProductName { get; set; } = string.Empty;
    public string Description { get; set; } = string.Empty;
    public int Amount { get; set; }
}


================================================
FILE: Services/Discount/Discount.Grpc/Extensions/HostExtensions.cs
================================================
using Npgsql;

namespace Discount.Grpc.Extensions;

public static class HostExtensions
{
    public static IHost MigrateDatabase<TContext>(this IHost host, int retry = 0)
    {
        using var scope = host.Services.CreateScope();
        var services = scope.ServiceProvider;
        var configuration = services.GetRequiredService<IConfiguration>();
        var logger = services.GetRequiredService<ILogger<TContext>>();

        try
        {
            logger.LogInformation("migrating postgresql database");

            using var connection = new NpgsqlConnection
                (configuration.GetValue<string>("DatabaseSettings:ConnectionString"));
            connection.Open();

            using var command = new NpgsqlCommand
            {
                Connection = connection
            };

            command.CommandText = @"create table if not exists Coupon 
                (Id serial primary key,
                ProductName varchar(200) not null,
                Description text,
                Amount int)";
            command.ExecuteNonQuery();

            /*command.CommandText = @"insert into Coupon(ProductName, Description, Amount) values 
                ('IPhone X', 'iphone discount', 150),
                ('Samsung 10', 'samsung discount', 150)";
            command.ExecuteNonQuery();*/

            logger.LogInformation("migration has been completed!");
        }
        catch (Exception ex)
        {
            logger.LogError($"an error has been occured: {ex.Message}");

            if (retry < 50)
            {
                Thread.Sleep(2000);
                host.MigrateDatabase<TContext>(retry + 1);
            }
        }

        return host;
    }
}


================================================
FILE: Services/Discount/Discount.Grpc/Mapper/DiscountProfile.cs
================================================
using AutoMapper;
using Discount.Grpc.Entities;
using Discount.Grpc.Protos;

namespace Discount.Grpc.Mapper;

public class DiscountProfile : Profile
{
    public DiscountProfile()
    {
        CreateMap<Coupon, CouponModel>().ReverseMap();
    }
}


================================================
FILE: Services/Discount/Discount.Grpc/Program.cs
================================================
using Discount.Grpc.Extensions;
using Discount.Grpc.Repositories;
using Discount.Grpc.Services;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddGrpc();
builder.Services.AddAutoMapper(typeof(Program));
builder.Services.AddScoped<ICouponRepository, CouponRepository>();

var app = builder.Build();

app.MapGrpcService<DiscountService>();

app.MigrateDatabase<Program>();

app.Run();


================================================
FILE: Services/Discount/Discount.Grpc/Properties/launchSettings.json
================================================
{
  "profiles": {
    "Discount.Grpc": {
      "commandName": "Project",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      },
      "dotnetRunMessages": true,
      "applicationUrl": "http://localhost:5003"
    },
    "Docker": {
      "commandName": "Docker",
      "launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}",
      "environmentVariables": {
        "ASPNETCORE_HTTP_PORTS": "8003"
      },
      "publishAllPorts": true
    }
  },
  "$schema": "http://json.schemastore.org/launchsettings.json"
}

================================================
FILE: Services/Discount/Discount.Grpc/Protos/discount.proto
================================================
syntax = "proto3";

option csharp_namespace = "Discount.Grpc.Protos";

service DiscountProtoService {
  rpc GetDiscount (GetDiscountRequest) returns (CouponModel);
  rpc CreateDiscount (CreateDiscountRequest) returns (CouponModel);
  rpc UpdateDiscount (UpdateDiscountRequest) returns (CouponModel);
  rpc DeleteDiscount (DeleteDiscountRequest) returns (DeleteDiscountResponse);
}

message CouponModel {
	int32 Id = 1;
	string ProductName = 2;
	string Description = 3;
	int32 Amount = 4;
}

message GetDiscountRequest {
  string ProductName = 1;
}

message CreateDiscountRequest {
  CouponModel Coupon = 1;
}

message UpdateDiscountRequest {
  CouponModel Coupon = 1;
}

message DeleteDiscountRequest {
  string ProductName = 1;
}

message DeleteDiscountResponse {
  bool Success = 1;
}

================================================
FILE: Services/Discount/Discount.Grpc/Repositories/CouponRepository.cs
================================================
using Dapper;
using Discount.Grpc.Entities;
using Npgsql;

namespace Discount.Grpc.Repositories;

public class CouponRepository(IConfiguration _configuration) : ICouponRepository
{
    public async Task<Coupon> GetByProductName(string productName)
    {
        using var connection = new NpgsqlConnection
            (_configuration.GetValue<string>("DatabaseSettings:ConnectionString"));

        var coupon = await connection.QueryFirstOrDefaultAsync<Coupon>
            ($"select * from Coupon where ProductName = '{productName}'");
        if (coupon is null)
        {
            return new Coupon
            {
                ProductName = productName,
                Description = "No discount",
                Amount = 0
            };
        }

        return coupon;
    }

    public async Task<bool> Create(Coupon coupon)
    {
        using var connection = new NpgsqlConnection
            (_configuration.GetValue<string>("DatabaseSettings:ConnectionString"));

        var affected = await connection.ExecuteAsync
            ($"insert into Coupon(ProductName, Description, Amount) " +
            $"values('{coupon.ProductName}', '{coupon.Description}', {coupon.Amount})");

        return affected > 0;
    }

    public async Task<bool> Update(Coupon coupon)
    {
        using var connection = new NpgsqlConnection
            (_configuration.GetValue<string>("DatabaseSettings:ConnectionString"));

        var affected = await connection.ExecuteAsync
            ($"update Coupon " +
            $"set ProductName = '{coupon.ProductName}', Description = '{coupon.Description}', Amount = {coupon.Amount} " +
            $"where Id = {coupon.Id}");

        return affected > 0;
    }

    public async Task<bool> Delete(string productName)
    {
        using var connection = new NpgsqlConnection
            (_configuration.GetValue<string>("DatabaseSettings:ConnectionString"));

        var affected = await connection.ExecuteAsync
            ($"delete from Coupon where ProductName = {productName}");

        return affected > 0;
    }
}


================================================
FILE: Services/Discount/Discount.Grpc/Repositories/ICouponRepository.cs
================================================
using Discount.Grpc.Entities;

namespace Discount.Grpc.Repositories;

public interface ICouponRepository
{
    Task<Coupon> GetByProductName(string productName);
    Task<bool> Create(Coupon coupon);
    Task<bool> Update(Coupon coupon);
    Task<bool> Delete(string productName);
}


================================================
FILE: Services/Discount/Discount.Grpc/Services/DiscountService.cs
================================================
using AutoMapper;
using Discount.Grpc.Entities;
using Discount.Grpc.Protos;
using Discount.Grpc.Repositories;
using Grpc.Core;

namespace Discount.Grpc.Services;

public class DiscountService(ICouponRepository _couponRepository, IMapper _mapper, ILogger<DiscountService> _logger) : DiscountProtoService.DiscountProtoServiceBase
{
    public async override Task<CouponModel> GetDiscount(GetDiscountRequest request, ServerCallContext context)
    {
        var coupon = await _couponRepository.GetByProductName(request.ProductName);

        _logger.LogInformation($"Get discount with product name {request.ProductName}");

        return _mapper.Map<CouponModel>(coupon);
    }

    public async override Task<CouponModel> CreateDiscount(CreateDiscountRequest request, ServerCallContext context)
    {
        var coupon = _mapper.Map<Coupon>(request.Coupon);
        await _couponRepository.Create(coupon);

        _logger.LogInformation($"Create discount with product name {coupon.ProductName}");

        return _mapper.Map<CouponModel>(coupon);
    }

    public async override Task<CouponModel> UpdateDiscount(UpdateDiscountRequest request, ServerCallContext context)
    {
        var coupon = _mapper.Map<Coupon>(request.Coupon);
        await _couponRepository.Update(coupon);

        _logger.LogInformation($"Update discount with product name {coupon.ProductName}");

        return _mapper.Map<CouponModel>(coupon);
    }

    public async override Task<DeleteDiscountResponse> DeleteDiscount(DeleteDiscountRequest request, ServerCallContext context)
    {
        var result = await _couponRepository.Delete(request.ProductName);

        _logger.LogInformation($"Delete discount with product name {request.ProductName}");

        return new DeleteDiscountResponse
        {
            Success = result,
        };
    }
}


================================================
FILE: Services/Discount/Discount.Grpc/appsettings.Development.json
================================================
{
  "DatabaseSettings": {
    "ConnectionString": "Server=localhost;port=5432;Database=discountdb;User Id=admin;Password=admin1234;"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  }
}


================================================
FILE: Services/Discount/Discount.Grpc/appsettings.json
================================================
{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*",
  "Kestrel": {
    "EndpointDefaults": {
      "Protocols": "Http2"
    }
  }
}


================================================
FILE: Services/Ordering/Ordering.Api/Controllers/OrderController.cs
================================================
using MediatR;
using Microsoft.AspNetCore.Mvc;
using Ordering.Application.Features.Orders.Commands.CreateOrder;
using Ordering.Application.Features.Orders.Commands.DeleteOrder;
using Ordering.Application.Features.Orders.Commands.UpdateOrder;
using Ordering.Application.Features.Orders.Queries.GetOrdersList;
using System.Net;

namespace Ordering.Api.Controllers;

[ApiController]
[Route("api/v1/[controller]/[action]")]
public class OrderController(IMediator _mediator) : ControllerBase
{
    [HttpGet("{userName}")]
    [ProducesResponseType(typeof(IEnumerable<OrderViewModel>), (int)HttpStatusCode.OK)]
    public async Task<ActionResult<IEnumerable<OrderViewModel>>> GetOrdersByUserName(string userName)
    {
        var result = await _mediator.Send(new GetOrdersListQuery(userName));
        return Ok(result);
    }

    [HttpPost]
    [ProducesResponseType(typeof(int), (int)HttpStatusCode.OK)]
    public async Task<ActionResult<int>> CreateOrder([FromBody] CreateOrderCommand command)
    {
        var result = await _mediator.Send(command);
        return Ok(result);
    }

    [HttpPut]
    [ProducesResponseType(typeof(int), (int)HttpStatusCode.NoContent)]
    [ProducesResponseType(typeof(int), (int)HttpStatusCode.NotFound)]
    public async Task<ActionResult> UpdateOrder([FromBody] UpdateOrderCommand command)
    {
        await _mediator.Send(command);
        return NoContent();
    }

    [HttpDelete("{id}")]
    [ProducesResponseType(typeof(int), (int)HttpStatusCode.NoContent)]
    [ProducesResponseType(typeof(int), (int)HttpStatusCode.NotFound)]
    public async Task<ActionResult> DeleteOrder(int id)
    {
        await _mediator.Send(new DeleteOrderCommand(id));
        return NoContent();
    }
}


================================================
FILE: Services/Ordering/Ordering.Api/Dockerfile
================================================
#See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging.

FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
USER app
WORKDIR /app
EXPOSE 8080

FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
ARG BUILD_CONFIGURATION=Release
WORKDIR /src
COPY ["Services/Ordering/Ordering.Api/Ordering.Api.csproj", "Services/Ordering/Ordering.Api/"]
COPY ["BuildingBlocks/EventBus.Messages/EventBus.Messages.csproj", "BuildingBlocks/EventBus.Messages/"]
COPY ["Services/Ordering/Ordering.Infrastructure/Ordering.Infrastructure.csproj", "Services/Ordering/Ordering.Infrastructure/"]
COPY ["Services/Ordering/Ordering.Application/Ordering.Application.csproj", "Services/Ordering/Ordering.Application/"]
COPY ["Services/Ordering/Ordering.Domain/Ordering.Domain.csproj", "Services/Ordering/Ordering.Domain/"]
RUN dotnet restore "./Services/Ordering/Ordering.Api/./Ordering.Api.csproj"
COPY . .
WORKDIR "/src/Services/Ordering/Ordering.Api"
RUN dotnet build "./Ordering.Api.csproj" -c $BUILD_CONFIGURATION -o /app/build

FROM build AS publish
ARG BUILD_CONFIGURATION=Release
RUN dotnet publish "./Ordering.Api.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "Ordering.Api.dll"]

================================================
FILE: Services/Ordering/Ordering.Api/EventBusConsumer/BasketCheckoutConsumer.cs
================================================
using AutoMapper;
using EventBus.Messages.Events;
using MassTransit;
using MediatR;
using Ordering.Application.Features.Orders.Commands.CreateOrder;

namespace Ordering.Api.EventBusConsumer;

public class BasketCheckoutConsumer(
    IMapper _mapper, 
    IMediator _mediator, 
    ILogger<BasketCheckoutConsumer> _logger
    ) : IConsumer<BasketCheckoutEvent>
{
    public async Task Consume(ConsumeContext<BasketCheckoutEvent> context)
    {
        var createOrderCommand = _mapper.Map<CreateOrderCommand>(context.Message);
        var result = await _mediator.Send(createOrderCommand);
        _logger.LogInformation($"Checkout basket consumed by Order service with result Id = {result}");
    }
}


================================================
FILE: Services/Ordering/Ordering.Api/HostExtensions.cs
================================================
using Microsoft.EntityFrameworkCore;

namespace Ordering.Api;

public static class HostExtensions
{
    public static IHost MigrateDatabase<TContext>(this IHost host,
        Action<TContext, IServiceProvider> seeder,
        int? retry = 0) 
        where TContext : DbContext
    {
        var retryForAvailability = retry!.Value;

        using var scope = host.Services.CreateScope();
        var services = scope.ServiceProvider;
        var logger = services.GetRequiredService<ILogger<TContext>>();
        var context = services.GetService<TContext>();

        try
        {
            logger.LogInformation("migrating started for sql server");
            InvokeSeeder(seeder, context, services);
            logger.LogInformation("migrating finished for sql server");
        }
        catch (Exception ex)
        {
            logger.LogError($"migrating errored for sql server, {ex.Message}");
            if (retryForAvailability < 50)
            {
                Thread.Sleep(2000);
                MigrateDatabase(host, seeder, retryForAvailability + 1);
            }
            throw;
        }

        return host;
    }

    private static void InvokeSeeder<TContext>(
        Action<TContext, IServiceProvider> seeder,
        TContext context, 
        IServiceProvider services) 
        where TContext : DbContext
    {
        context.Database.Migrate();
        seeder(context, services);
    }
}


================================================
FILE: Services/Ordering/Ordering.Api/Mapper/CheckoutProfile.cs
================================================
using AutoMapper;
using EventBus.Messages.Events;
using Ordering.Application.Features.Orders.Commands.CreateOrder;

namespace Ordering.Api.Mapping;

public class CheckoutProfile : Profile
{
    public CheckoutProfile()
    {
        CreateMap<BasketCheckoutEvent, CreateOrderCommand>().ReverseMap();
    }
}


================================================
FILE: Services/Ordering/Ordering.Api/Ordering.Api.csproj
================================================
<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
    <InvariantGlobalization>false</InvariantGlobalization>
    <DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
    <DockerfileContext>..\..\..</DockerfileContext>
    <DockerComposeProjectPath>..\..\..\docker-compose.dcproj</DockerComposeProjectPath>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="12.0.1" />
    <PackageReference Include="MassTransit" Version="8.1.2" />
    <PackageReference Include="MassTransit.RabbitMQ" Version="8.1.2" />
	<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.0" />
	<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.19.5" />
    <PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
  </ItemGroup>

  <ItemGroup>
    <ProjectReference Include="..\..\..\BuildingBlocks\EventBus.Messages\EventBus.Messages.csproj" />
    <ProjectReference Include="..\Ordering.Infrastructure\Ordering.Infrastructure.csproj" />
  </ItemGroup>

</Project>


================================================
FILE: Services/Ordering/Ordering.Api/Ordering.Api.http
================================================
@Ordering.Api_HostAddress = http://localhost:5116

GET {{Ordering.Api_HostAddress}}/weatherforecast/
Accept: application/json

###


================================================
FILE: Services/Ordering/Ordering.Api/Program.cs
================================================
using EventBus.Messages.Common;
using MassTransit;
using Ordering.Api;
using Ordering.Api.EventBusConsumer;
using Ordering.Application;
using Ordering.Infrastructure.Persistence;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();

builder.Services.AddApplicationServices();
builder.Services.AddInfrastructureServices(builder.Configuration);

builder.Services.AddMassTransit(config =>
{
    config.AddConsumer<BasketCheckoutConsumer>();

    config.UsingRabbitMq((context, conf) =>
    {
        conf.Host(builder.Configuration.GetValue<string>("EventBusSettings:HostAddress"));
        conf.ReceiveEndpoint(EventBusConstant.BasketCheckoutQueue, c =>
        {
            c.ConfigureConsumer<BasketCheckoutConsumer>(context);
        });
    });
});

builder.Services.AddAutoMapper(typeof(Program));
builder.Services.AddScoped<BasketCheckoutConsumer>();

builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.MapControllers();

app.MigrateDatabase<OrderDBContext>((context, services) =>
{
    var logger = services.GetService<ILogger<OrderDBContextSeed>>();
    OrderDBContextSeed.SeedAsync(context, logger).Wait();
});

app.Run();


================================================
FILE: Services/Ordering/Ordering.Api/Properties/launchSettings.json
================================================
{
  "profiles": {
    "Ordering.Api": {
      "commandName": "Project",
      "launchBrowser": true,
      "launchUrl": "swagger",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      },
      "dotnetRunMessages": true,
      "applicationUrl": "http://localhost:5004"
    },
    "IIS Express": {
      "commandName": "IISExpress",
      "launchBrowser": true,
      "launchUrl": "swagger",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    },
    "Docker": {
      "commandName": "Docker",
      "launchBrowser": true,
      "launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/swagger",
      "environmentVariables": {
        "ASPNETCORE_HTTP_PORTS": "8004"
      },
      "publishAllPorts": true
    }
  },
  "$schema": "http://json.schemastore.org/launchsettings.json",
  "iisSettings": {
    "windowsAuthentication": false,
    "anonymousAuthentication": true,
    "iisExpress": {
      "applicationUrl": "http://localhost:54058",
      "sslPort": 0
    }
  }
}

================================================
FILE: Services/Ordering/Ordering.Api/appsettings.Development.json
================================================
{
  "ConnectionStrings": {
    "OrderingConnectionString": "Server=localhost; Database=orderdb; User Id=sa; Password=Admin1234; TrustServerCertificate=True;"
  },
  "EventBusSettings": {
    "HostAddress": "amqp://guest:guest@localhost:5672"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  }
}


================================================
FILE: Services/Ordering/Ordering.Api/appsettings.json
================================================
{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*"
}


================================================
FILE: Services/Ordering/Ordering.Application/ApplicationServiceRegistration.cs
================================================
using FluentValidation;
using MediatR;
using Microsoft.Extensions.DependencyInjection;
using Ordering.Application.Behaviors;
using System.Reflection;

namespace Ordering.Application;

public static class ApplicationServiceRegistration
{
    public static IServiceCollection AddApplicationServices(this IServiceCollection services)
    {
        services.AddAutoMapper(Assembly.GetExecutingAssembly());
        services.AddValidatorsFromAssembly(Assembly.GetExecutingAssembly());
        services.AddMediatR(cfg => cfg.RegisterServicesFromAssembly(Assembly.GetExecutingAssembly()));

        services.AddTransient(typeof(IPipelineBehavior<,>), typeof(UnhandledExceptionBehavior<,>));
        services.AddTransient(typeof(IPipelineBehavior<,>), typeof(ValidationBehavior<,>));

        return services;
    }
}


================================================
FILE: Services/Ordering/Ordering.Application/Behaviors/UnhandledExceptionBehavior.cs
================================================
using FluentValidation;
using MediatR;
using Microsoft.Extensions.Logging;

namespace Ordering.Application.Behaviors;

public class UnhandledExceptionBehavior<TRequest, TResponse>(ILogger<TRequest> _logger)
    : IPipelineBehavior<TRequest, TResponse> where TRequest : IRequest<TResponse>
{
    public async Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next, CancellationToken cancellationToken)
    {
        try
        {
            return await next();
        }
        catch (Exception ex)
        {
            var requestName = typeof(TRequest).Name;
            _logger.LogError(ex, $"Application unhandled exception for request {requestName}");
            throw;
        }
    }
}


================================================
FILE: Services/Ordering/Ordering.Application/Behaviors/ValidationBehavior.cs
================================================
using FluentValidation;
using MediatR;


namespace Ordering.Application.Behaviors;

public class ValidationBehavior<TRequest, TResponse>(IEnumerable<IValidator<TRequest>> _validators) 
    : IPipelineBehavior<TRequest, TResponse> where TRequest : IRequest<TResponse>
{
    public async Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next, CancellationToken cancellationToken)
    {
        if (_validators.Any())
        {
            var content = new ValidationContext<TRequest>(request);

            var validationResults = await Task.WhenAll(
                _validators.Select(x => x.ValidateAsync(content, cancellationToken)));

            var failures = validationResults.SelectMany(x => x.Errors).Where(x => x != null).ToList();
            if (failures.Count != 0)
            {
                throw new Exceptions.ValidationException(failures);
            }
        }

        return await next();
    }
}


================================================
FILE: Services/Ordering/Ordering.Application/Contracts/Infrastructure/IEmailService.cs
================================================
using Ordering.Application.Models;

namespace Ordering.Application.Contracts.Infrastructure;

public interface IEmailService
{
    Task<bool> SendEmailAsync(Email email);
}


================================================
FILE: Services/Ordering/Ordering.Application/Contracts/Persistence/IAsyncRepository.cs
================================================
using Ordering.Domain.Common;
using System.Linq.Expressions;

namespace Ordering.Application.Contracts.Persistence;

public interface IAsyncRepository<T> where T : EntityBase
{
    Task<IReadOnlyList<T>> GetAllAsync();
    Task<IReadOnlyList<T>> GetAsync(Expression<Func<T, bool>> predicate);
    Task<IReadOnlyList<T>> GetAsync(Expression<Func<T, bool>>? predicate = null,
        Func<IQueryable<T>, IOrderedQueryable<T>>? orderBy = null,
        string? includeString = null,
        bool disableTracking = true);
    Task<IReadOnlyList<T>> GetAsync(Expression<Func<T, bool>>? predicate = null,
        Func<IQueryable<T>, IOrderedQueryable<T>>? orderBy = null,
        List<Expression<Func<T, object>>>? includes = null,
        bool disableTracking = true);
    Task<T?> GetByIdAsync(int id);
    Task<T> CreateAsync(T entity);
    Task UpdateAsync(T entity);
    Task DeleteAsync(T entity);
}


================================================
FILE: Services/Ordering/Ordering.Application/Contracts/Persistence/IOrderRepository.cs
================================================
using Ordering.Domain.Entities;

namespace Ordering.Application.Contracts.Persistence;

public interface IOrderRepository : IAsyncRepository<Order>
{
    Task<IEnumerable<Order>> GetOrdersByUserName(string userName);
}


================================================
FILE: Services/Ordering/Ordering.Application/Exceptions/NotFoundException.cs
================================================
namespace Ordering.Application.Exceptions;

public class NotFoundException(string name, object key) 
    : ApplicationException($"Entity with name \"{name}\" and key \"{key}\" was not found")
{
}


================================================
FILE: Services/Ordering/Ordering.Application/Exceptions/ValidationException.cs
================================================
using FluentValidation.Results;

namespace Ordering.Application.Exceptions;

public class ValidationException : ApplicationException
{
    public ValidationException()
        : base("one or more validation errors has occured")
    {
        
    }

    public ValidationException(IEnumerable<ValidationFailure> failures) : this()
    {
        Errors = failures.GroupBy(x => x.PropertyName, x => x.ErrorMessage)
            .ToDictionary(x => x.Key, x => x.ToList());
    }

    public IDictionary<string, List<string>> Errors { get; set; } = new Dictionary<string, List<string>>();
}


================================================
FILE: Services/Ordering/Ordering.Application/Features/Orders/Commands/CreateOrder/CreateOrderCommand.cs
================================================
using MediatR;

namespace Ordering.Application.Features.Orders.Commands.CreateOrder;

public sealed record CreateOrderCommand(
        string UserName,
        decimal TotalPrice,
        string FirstName,
        string LastName,
        string EmailAddress,
        string Country,
        string City,
        string BankName,
        string RefCode,
        int PaymentMethod
    ) : IRequest<int>;

================================================
FILE: Services/Ordering/Ordering.Application/Features/Orders/Commands/CreateOrder/CreateOrderCommandHandler.cs
================================================
using AutoMapper;
using MediatR;
using Microsoft.Extensions.Logging;
using Ordering.Application.Contracts.Infrastructure;
using Ordering.Application.Contracts.Persistence;
using Ordering.Application.Models;
using Ordering.Domain.Entities;

namespace Ordering.Application.Features.Orders.Commands.CreateOrder;

public class CreateOrderCommandHandler(IOrderRepository _orderRepository,
                                       IMapper _mapper,
                                       IEmailService _emailService,
                                       ILogger<CreateOrderCommandHandler> _logger) : IRequestHandler<CreateOrderCommand, int>
{
    public async Task<int> Handle(CreateOrderCommand request, CancellationToken cancellationToken)
    {
        var entity = _mapper.Map<Order>(request);
        var result = await _orderRepository.CreateAsync(entity);

        _logger.LogInformation($"order by Id {result.Id} created");
        await SendMail(result);

        return result.Id;
    }

    private async Task SendMail(Order order)
    {
        try
        {
            await _emailService.SendEmailAsync(new Email
            {
                To = "Test@Test.com",
                Subject = "order added",
                Body = "email Body"
            });
        }
        catch (Exception ex)
        {
            _logger.LogError($"email has not been sent, {ex.Message}");
        }
    }
}


================================================
FILE: Services/Ordering/Ordering.Application/Features/Orders/Commands/CreateOrder/CreateOrderCommandValidator.cs
================================================
using FluentValidation;

namespace Ordering.Application.Features.Orders.Commands.CreateOrder;

public class CreateOrderCommandValidator : AbstractValidator<CreateOrderCommand>
{
    public CreateOrderCommandValidator()
    {
        RuleFor(x => x.UserName)
            .NotNull().WithMessage("UserName is required")
            .NotEmpty().WithMessage("UserName can not be empty")
            .MinimumLength(3).WithMessage("UserName must be longer");

        RuleFor(x => x.EmailAddress)
            .NotEmpty().WithMessage("Email is required");

        RuleFor(x => x.TotalPrice)
            .NotEmpty().WithMessage("TotalPrice is required")
            .GreaterThan(0).WithMessage("TotalPrice must be greater than zero");
    }
}


================================================
FILE: Services/Ordering/Ordering.Application/Features/Orders/Commands/DeleteOrder/DeleteOrderCommand.cs
================================================
using MediatR;

namespace Ordering.Application.Features.Orders.Commands.DeleteOrder;

public sealed record DeleteOrderCommand(int Id) : IRequest;

================================================
FILE: Services/Ordering/Ordering.Application/Features/Orders/Commands/DeleteOrder/DeleteOrderCommandHandler.cs
================================================
using MediatR;
using Microsoft.Extensions.Logging;
using Ordering.Application.Contracts.Persistence;
using Ordering.Application.Exceptions;
using Ordering.Domain.Entities;

namespace Ordering.Application.Features.Orders.Commands.DeleteOrder
{
    public class DeleteOrderCommandHandler(IOrderRepository _orderRepository,
                                           ILogger<DeleteOrderCommandHandler> _logger) : IRequestHandler<DeleteOrderCommand>
    {
        public async Task Handle(DeleteOrderCommand request, CancellationToken cancellationToken)
        {
            var order = await _orderRepository.GetByIdAsync(request.Id);
            if (order is null)
            {
                _logger.LogError($"order with id {request.Id} does not exist");
                throw new NotFoundException(nameof(Order), request.Id);
            }

            await _orderRepository.DeleteAsync(order);

            _logger.LogInformation($"order by Id {order.Id} deleted");
        }
    }
}


================================================
FILE: Services/Ordering/Ordering.Application/Features/Orders/Commands/UpdateOrder/UpdateOrderCommand.cs
================================================
using MediatR;

namespace Ordering.Application.Features.Orders.Commands.UpdateOrder;

public sealed record UpdateOrderCommand(
        int Id,
        string UserName,
        decimal TotalPrice,
        string FirstName,
        string LastName,
        string EmailAddress,
        string Country,
        string City,
        string BankName,
        string RefCode,
        int PaymentMethod
    ) : IRequest;

================================================
FILE: Services/Ordering/Ordering.Application/Features/Orders/Commands/UpdateOrder/UpdateOrderCommandHandler.cs
================================================
using AutoMapper;
using MediatR;
using Microsoft.Extensions.Logging;
using Ordering.Application.Contracts.Persistence;
using Ordering.Application.Exceptions;
using Ordering.Domain.Entities;

namespace Ordering.Application.Features.Orders.Commands.UpdateOrder;

public class UpdateOrderCommandHandler(IOrderRepository _orderRepository,
                                       IMapper _mapper,
                                       ILogger<UpdateOrderCommandHandler> _logger) : IRequestHandler<UpdateOrderCommand>
{
    public async Task Handle(UpdateOrderCommand request, CancellationToken cancellationToken)
    {
        var order = await _orderRepository.GetByIdAsync(request.Id);
        if (order is null)
        {
            _logger.LogError($"order with id {request.Id} does not exist");
            throw new NotFoundException(nameof(Order), request.Id);
        }

        _mapper.Map(request, order);

        await _orderRepository.UpdateAsync(order);

        _logger.LogInformation($"order by Id {order.Id} updated");
    }
}


================================================
FILE: Services/Ordering/Ordering.Application/Features/Orders/Commands/UpdateOrder/UpdateOrderCommandValidator.cs
================================================
using FluentValidation;

namespace Ordering.Application.Features.Orders.Commands.UpdateOrder;

public class UpdateOrderCommandValidator : AbstractValidator<UpdateOrderCommand>
{
    public UpdateOrderCommandValidator()
    {
        RuleFor(x => x.UserName)
            .NotNull().WithMessage("UserName is required")
            .NotEmpty().WithMessage("UserName can not be empty")
            .MinimumLength(3).WithMessage("UserName must be longer");

        RuleFor(x => x.EmailAddress)
            .NotEmpty().WithMessage("Email is required");

        RuleFor(x => x.TotalPrice)
            .NotEmpty().WithMessage("TotalPrice is required")
            .GreaterThan(0).WithMessage("TotalPrice must be greater than zero");
    }
}


================================================
FILE: Services/Ordering/Ordering.Application/Features/Orders/Queries/GetOrdersList/GetOrdersListQuery.cs
================================================
using MediatR;

namespace Ordering.Application.Features.Orders.Queries.GetOrdersList;

public sealed record GetOrdersListQuery(string UserName) : IRequest<List<OrderViewModel>>;


================================================
FILE: Services/Ordering/Ordering.Application/Features/Orders/Queries/GetOrdersList/GetOrdersListQueryHandler.cs
================================================
using AutoMapper;
using MediatR;
using Ordering.Application.Contracts.Persistence;

namespace Ordering.Application.Features.Orders.Queries.GetOrdersList;

public class GetOrdersListQueryHandler(IOrderRepository _orderRepository, IMapper _mapper) : IRequestHandler<GetOrdersListQuery, List<OrderViewModel>>
{
    public async Task<List<OrderViewModel>> Handle(GetOrdersListQuery request, CancellationToken cancellationToken)
    {
        var result = await _orderRepository.GetOrdersByUserName(request.UserName);
        return _mapper.Map<List<OrderViewModel>>(result);
    }
}


================================================
FILE: Services/Ordering/Ordering.Application/Features/Orders/Queries/GetOrdersList/OrderViewModel.cs
================================================
namespace Ordering.Application.Features.Orders.Queries.GetOrdersList;

public class OrderViewModel
{
    public int Id { get; set; }
    public string UserName { get; set; } = string.Empty;
    public decimal TotalPrice { get; set; }

    public string FirstName { get; set; } = string.Empty;
    public string LastName { get; set; } = string.Empty;
    public string EmailAddress { get; set; } = string.Empty;
    public string Country { get; set; } = string.Empty;
    public string City { get; set; } = string.Empty;

    public string BankName { get; set; } = string.Empty;
    public string RefCode { get; set; } = string.Empty;
    public int PaymentMethod { get; set; }
}


================================================
FILE: Services/Ordering/Ordering.Application/Mappings/MappingProfile.cs
================================================
using AutoMapper;
using Ordering.Application.Features.Orders.Commands.CreateOrder;
using Ordering.Application.Features.Orders.Commands.UpdateOrder;
using Ordering.Application.Features.Orders.Queries.GetOrdersList;
using Ordering.Domain.Entities;

namespace Ordering.Application.Mappings;

public class MappingProfile : Profile
{
    public MappingProfile()
    {
        CreateMap<Order, OrderViewModel>().ReverseMap();
        CreateMap<CreateOrderCommand, Order>().ReverseMap();
        CreateMap<UpdateOrderCommand, Order>().ReverseMap();
    }
}


================================================
FILE: Services/Ordering/Ordering.Application/Models/Email.cs
================================================
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Ordering.Application.Models;

public class Email
{
    public string To { get; set; } = string.Empty;
    public string Subject { get; set; } = string.Empty;
    public string Body { get; set; } = string.Empty;
}


================================================
FILE: Services/Ordering/Ordering.Application/Models/EmailSetting.cs
================================================
namespace Ordering.Application.Models;

public class EmailSetting
{
    public string From { get; set; } = string.Empty;
    public string DisplayName { get; set; } = string.Empty;
    public string UserName { get; set; } = string.Empty;
    public string Password { get; set; } = string.Empty;
}


================================================
FILE: Services/Ordering/Ordering.Application/Ordering.Application.csproj
================================================
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

  <ItemGroup>
    <ProjectReference Include="..\Ordering.Domain\Ordering.Domain.csproj" />
  </ItemGroup>

  <ItemGroup>
    <PackageReference Include="AutoMapper" Version="12.0.1" />
    <PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="12.0.1" />
    <PackageReference Include="FluentValidation" Version="11.8.1" />
    <PackageReference Include="FluentValidation.DependencyInjectionExtensions" Version="11.8.1" />
    <PackageReference Include="MediatR" Version="12.2.0" />
    <PackageReference Include="MediatR.Extensions.Microsoft.DependencyInjection" Version="11.1.0" />
    <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.0" />
  </ItemGroup>

</Project>


================================================
FILE: Services/Ordering/Ordering.Domain/Common/EntityBase.cs
================================================
namespace Ordering.Domain.Common;

public abstract class EntityBase
{
    public int Id { get; set; }
    public string CreatedBy { get; set; } = string.Empty;
    public DateTime CreatedAt { get; set; }
    public string UpdatedBy { get; set; } = string.Empty;
    public DateTime? UpdatedAt { get; set; }
}


================================================
FILE: Services/Ordering/Ordering.Domain/Common/ValueObject.cs
================================================
namespace Ordering.Domain.Common;

public abstract class ValueObject
{
    protected static bool EqualOperator(ValueObject left, ValueObject right)
    {
        if (left is null ^ right is null)
        {
            return false;
        }
        return ReferenceEquals(left, right) || left.Equals(right);
    }

    protected static bool NotEqualOperator(ValueObject left, ValueObject right)
    {
        return !(EqualOperator(left, right));
    }

    protected abstract IEnumerable<object> GetEqualityComponents();

    public override bool Equals(object obj)
    {
        if (obj == null || obj.GetType() != GetType())
        {
            return false;
        }

        var other = (ValueObject)obj;

        return this.GetEqualityComponents().SequenceEqual(other.GetEqualityComponents());
    }

    public override int GetHashCode()
    {
        return GetEqualityComponents()
            .Select(x => x != null ? x.GetHashCode() : 0)
            .Aggregate((x, y) => x ^ y);
    }
}


================================================
FILE: Services/Ordering/Ordering.Domain/Entities/Order.cs
================================================
using Ordering.Domain.Common;

namespace Ordering.Domain.Entities;

public class Order : EntityBase
{
    public string UserName { get; set; } = string.Empty;
    public decimal TotalPrice { get; set; }

    public string FirstName { get; set; } = string.Empty;
    public string LastName { get; set; } = string.Empty;
    public string EmailAddress { get; set; } = string.Empty;
    public string Country { get; set; } = string.Empty;
    public string City { get; set; } = string.Empty;

    public string BankName { get; set; } = string.Empty;
    public string RefCode { get; set; } = string.Empty;
    public int PaymentMethod { get; set; }
}


================================================
FILE: Services/Ordering/Ordering.Domain/Ordering.Domain.csproj
================================================
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

</Project>


================================================
FILE: Services/Ordering/Ordering.Infrastructure/InfrastructureServiceRegistration.cs
================================================
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Ordering.Application.Contracts.Infrastructure;
using Ordering.Application.Contracts.Persistence;
using Ordering.Infrastructure.Persistence;
using Ordering.Infrastructure.Proxies;
using Ordering.Infrastructure.Repositories;

namespace Ordering.Application;

public static class InfrastructureServiceRegistration
{
    public static IServiceCollection AddInfrastructureServices(this IServiceCollection services, 
        IConfiguration configuration)
    {
        services.AddDbContext<OrderDBContext>(options =>
        {
            options.UseSqlServer(configuration.GetConnectionString("OrderingConnectionString"), builder =>
            {
                builder.EnableRetryOnFailure(3, TimeSpan.FromSeconds(5), null);
            });
        });

        services.AddScoped(typeof(IAsyncRepository<>), typeof(RepositoryBase<>));
        services.AddScoped<IOrderRepository, OrderRepository>();
        services.AddScoped<IEmailService, EmailService>();

        return services;
    }
}


================================================
FILE: Services/Ordering/Ordering.Infrastructure/Migrations/20231211200458_Init.Designer.cs
================================================
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Ordering.Infrastructure.Persistence;

#nullable disable

namespace Ordering.Infrastructure.Migrations
{
    [DbContext(typeof(OrderDBContext))]
    [Migration("20231211200458_Init")]
    partial class Init
    {
        /// <inheritdoc />
        protected override void BuildTargetModel(ModelBuilder modelBuilder)
        {
#pragma warning disable 612, 618
            modelBuilder
                .HasAnnotation("ProductVersion", "8.0.0")
                .HasAnnotation("Relational:MaxIdentifierLength", 128);

            SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);

            modelBuilder.Entity("Ordering.Domain.Entities.Order", b =>
                {
                    b.Property<int>("Id")
                        .ValueGeneratedOnAdd()
                        .HasColumnType("int");

                    SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));

                    b.Property<string>("BankName")
                        .IsRequired()
                        .HasColumnType("nvarchar(max)");

                    b.Property<string>("City")
                        .IsRequired()
                        .HasColumnType("nvarchar(max)");

                    b.Property<string>("Country")
                        .IsRequired()
                        .HasColumnType("nvarchar(max)");

                    b.Property<DateTime>("CreatedAt")
                        .HasColumnType("datetime2");

                    b.Property<string>("CreatedBy")
                        .IsRequired()
                        .HasColumnType("nvarchar(max)");

                    b.Property<string>("EmailAddress")
                        .IsRequired()
                        .HasColumnType("nvarchar(max)");

                    b.Property<string>("FirstName")
                        .IsRequired()
                        .HasColumnType("nvarchar(max)");

                    b.Property<string>("LastName")
                        .IsRequired()
                        .HasColumnType("nvarchar(max)");

                    b.Property<int>("PaymentMethod")
                        .HasColumnType("int");

                    b.Property<string>("RefCode")
                        .IsRequired()
                        .HasColumnType("nvarchar(max)");

                    b.Property<decimal>("TotalPrice")
                        .HasColumnType("decimal(18,4)");

                    b.Property<DateTime?>("UpdatedAt")
                        .HasColumnType("datetime2");

                    b.Property<string>("UpdatedBy")
                        .IsRequired()
                        .HasColumnType("nvarchar(max)");

                    b.Property<string>("UserName")
                        .IsRequired()
                        .HasColumnType("nvarchar(max)");

                    b.HasKey("Id");

                    b.ToTable("Orders");
                });
#pragma warning restore 612, 618
        }
    }
}


================================================
FILE: Services/Ordering/Ordering.Infrastructure/Migrations/20231211200458_Init.cs
================================================
using System;
using Microsoft.EntityFrameworkCore.Migrations;

#nullable disable

namespace Ordering.Infrastructure.Migrations
{
    /// <inheritdoc />
    public partial class Init : Migration
    {
        /// <inheritdoc />
        protected override void Up(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.CreateTable(
                name: "Orders",
                columns: table => new
                {
                    Id = table.Column<int>(type: "int", nullable: false)
                        .Annotation("SqlServer:Identity", "1, 1"),
                    UserName = table.Column<string>(type: "nvarchar(max)", nullable: false),
                    TotalPrice = table.Column<decimal>(type: "decimal(18,4)", nullable: false),
                    FirstName = table.Column<string>(type: "nvarchar(max)", nullable: false),
                    LastName = table.Column<string>(type: "nvarchar(max)", nullable: false),
                    EmailAddress = table.Column<string>(type: "nvarchar(max)", nullable: false),
                    Country = table.Column<string>(type: "nvarchar(max)", nullable: false),
                    City = table.Column<string>(type: "nvarchar(max)", nullable: false),
                    BankName = table.Column<string>(type: "nvarchar(max)", nullable: false),
                    RefCode = table.Column<string>(type: "nvarchar(max)", nullable: false),
                    PaymentMethod = table.Column<int>(type: "int", nullable: false),
                    CreatedBy = table.Column<string>(type: "nvarchar(max)", nullable: false),
                    CreatedAt = table.Column<DateTime>(type: "datetime2", nullable: false),
                    UpdatedBy = table.Column<string>(type: "nvarchar(max)", nullable: false),
                    UpdatedAt = table.Column<DateTime>(type: "datetime2", nullable: true)
                },
                constraints: table =>
                {
                    table.PrimaryKey("PK_Orders", x => x.Id);
                });
        }

        /// <inheritdoc />
        protected override void Down(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.DropTable(
                name: "Orders");
        }
    }
}


================================================
FILE: Services/Ordering/Ordering.Infrastructure/Migrations/OrderDBContextModelSnapshot.cs
================================================
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Ordering.Infrastructure.Persistence;

#nullable disable

namespace Ordering.Infrastructure.Migrations
{
    [DbContext(typeof(OrderDBContext))]
    partial class OrderDBContextModelSnapshot : ModelSnapshot
    {
        protected override void BuildModel(ModelBuilder modelBuilder)
        {
#pragma warning disable 612, 618
            modelBuilder
                .HasAnnotation("ProductVersion", "8.0.0")
                .HasAnnotation("Relational:MaxIdentifierLength", 128);

            SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);

            modelBuilder.Entity("Ordering.Domain.Entities.Order", b =>
                {
                    b.Property<int>("Id")
                        .ValueGeneratedOnAdd()
                        .HasColumnType("int");

                    SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));

                    b.Property<string>("BankName")
                        .IsRequired()
                        .HasColumnType("nvarchar(max)");

                    b.Property<string>("City")
                        .IsRequired()
                        .HasColumnType("nvarchar(max)");

                    b.Property<string>("Country")
                        .IsRequired()
                        .HasColumnType("nvarchar(max)");

                    b.Property<DateTime>("CreatedAt")
                        .HasColumnType("datetime2");

                    b.Property<string>("CreatedBy")
                        .IsRequired()
                        .HasColumnType("nvarchar(max)");

                    b.Property<string>("EmailAddress")
                        .IsRequired()
                        .HasColumnType("nvarchar(max)");

                    b.Property<string>("FirstName")
                        .IsRequired()
                        .HasColumnType("nvarchar(max)");

                    b.Property<string>("LastName")
                        .IsRequired()
                        .HasColumnType("nvarchar(max)");

                    b.Property<int>("PaymentMethod")
                        .HasColumnType("int");

                    b.Property<string>("RefCode")
                        .IsRequired()
                        .HasColumnType("nvarchar(max)");

                    b.Property<decimal>("TotalPrice")
                        .HasColumnType("decimal(18,4)");

                    b.Property<DateTime?>("UpdatedAt")
                        .HasColumnType("datetime2");

                    b.Property<string>("UpdatedBy")
                        .IsRequired()
                        .HasColumnType("nvarchar(max)");

                    b.Property<string>("UserName")
                        .IsRequired()
                        .HasColumnType("nvarchar(max)");

                    b.HasKey("Id");

                    b.ToTable("Orders");
                });
#pragma warning restore 612, 618
        }
    }
}


================================================
FILE: Services/Ordering/Ordering.Infrastructure/Ordering.Infrastructure.csproj
================================================
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.0" />
	<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.0" />
	<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="8.0.0" />
  </ItemGroup>

  <ItemGroup>
    <ProjectReference Include="..\Ordering.Application\Ordering.Application.csproj" />
  </ItemGroup>

</Project>


================================================
FILE: Services/Ordering/Ordering.Infrastructure/Persistence/OrderDBContext.cs
================================================
using Microsoft.EntityFrameworkCore;
using Ordering.Domain.Common;
using Ordering.Domain.Entities;
using System.Reflection;

namespace Ordering.Infrastructure.Persistence;

public class OrderDBContext(DbContextOptions<OrderDBContext> options) : DbContext(options)
{
    public DbSet<Order> Orders { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Order>()
            .Property(x => x.TotalPrice)
            .HasColumnType("decimal(18,4)");
    }

    public override Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
    {
        foreach (var entry in ChangeTracker.Entries<EntityBase>())
        {
            switch (entry.State)
            {
                case EntityState.Added:
                    entry.Entity.CreatedAt = DateTime.UtcNow;
                    entry.Entity.CreatedBy = "Admin1";
                    break;
                case EntityState.Modified:
                    entry.Entity.UpdatedAt = DateTime.UtcNow;
                    entry.Entity.UpdatedBy = "Admin2";
                    break;
            }
        }

        return base.SaveChangesAsync(cancellationToken);
    }
}


================================================
FILE: Services/Ordering/Ordering.Infrastructure/Persistence/OrderDBContextSeed.cs
================================================
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Ordering.Domain.Entities;

namespace Ordering.Infrastructure.Persistence;

public class OrderDBContextSeed
{
    public static async Task SeedAsync(OrderDBContext orderDBContext, ILogger<OrderDBContextSeed> logger)
    {
        if (!await orderDBContext.Orders.AnyAsync())
        {
            await orderDBContext.Orders.AddRangeAsync(GetPreconfiguredOrders());
            await orderDBContext.SaveChangesAsync();

            logger.LogInformation("data seed section configured");
        }
    }

    private static IEnumerable<Order> GetPreconfiguredOrders()
    {
        return new List<Order>
        {
            new() {
                UserName = "U1",
                FirstName = "F1",
                LastName = "D1",
                EmailAddress = "E1@e.com",
                Country = "Co1",
                City = "ci1",
                TotalPrice = 10000
            },
            new() {
                UserName = "U2",
                FirstName = "F2",
                LastName = "D2",
                EmailAddress = "E2@e.com",
                Country = "Co2",
                City = "ci2",
                TotalPrice = 20000
            }
        };
    }
}


================================================
FILE: Services/Ordering/Ordering.Infrastructure/Proxies/EmailService.cs
================================================
using Ordering.Application.Contracts.Infrastructure;
using Ordering.Application.Models;

namespace Ordering.Infrastructure.Proxies;

public class EmailService : IEmailService
{
    public Task<bool> SendEmailAsync(Email email)
    {
        return Task.FromResult(true);
    }
}


================================================
FILE: Services/Ordering/Ordering.Infrastructure/Repositories/OrderRepository.cs
================================================
using Microsoft.EntityFrameworkCore;
using Ordering.Application.Contracts.Persistence;
using Ordering.Domain.Entities;
using Ordering.Infrastructure.Persistence;

namespace Ordering.Infrastructure.Repositories;

public class OrderRepository(OrderDBContext orderDBContext) 
    : RepositoryBase<Order>(orderDBContext), IOrderRepository
{
    public async Task<IEnumerable<Order>> GetOrdersByUserName(string userName)
    {
        return await _dbSet.Where(x => x.UserName == userName).ToListAsync();
    }
}


================================================
FILE: Services/Ordering/Ordering.Infrastructure/Repositories/RepositoryBase.cs
================================================
using Microsoft.EntityFrameworkCore;
using Ordering.Application.Contracts.Persistence;
using Ordering.Domain.Common;
using Ordering.Infrastructure.Persistence;
using System.Linq.Expressions;

namespace Ordering.Infrastructure.Repositories;

public class RepositoryBase<T>(OrderDBContext _orderDBContext) : IAsyncRepository<T> where T : EntityBase
{
    protected readonly DbSet<T> _dbSet = _orderDBContext.Set<T>();

    public async Task<IReadOnlyList<T>> GetAllAsync()
    {
        return await _dbSet.ToListAsync();
    }

    public async Task<IReadOnlyList<T>> GetAsync(Expression<Func<T, bool>> predicate)
    {
        return await _dbSet.Where(predicate).ToListAsync();
    }

    public async Task<IReadOnlyList<T>> GetAsync(Expression<Func<T, bool>>? predicate = null, Func<IQueryable<T>, IOrderedQueryable<T>>? orderBy = null, string? includeString = null, bool disableTracking = true)
    {
        IQueryable<T> query = _dbSet;

        if (disableTracking)
        {
            query = query.AsNoTracking();   
        }

        if (!string.IsNullOrWhiteSpace(includeString))
        {
            query = query.Include(includeString);
        }

        if (predicate != null)
        {
            query = query.Where(predicate);
        }

        if (orderBy != null)
        {
            query = orderBy(query);
        }

        return await query.ToListAsync();
    }

    public async Task<IReadOnlyList<T>> GetAsync(Expression<Func<T, bool>>? predicate = null, Func<IQueryable<T>, IOrderedQueryable<T>>? orderBy = null, List<Expression<Func<T, object>>>? includes = null, bool disableTracking = true)
    {
        IQueryable<T> query = _dbSet;

        if (disableTracking)
        {
            query = query.AsNoTracking();
        }

        if (includes != null)
        {
            query = includes.Aggregate(query, (current, include) => current.Include(include));
        }

        if (predicate != null)
        {
            query = query.Where(predicate);
        }

        if (orderBy != null)
        {
            query = orderBy(query);
        }

        return await query.ToListAsync();
    }

    public virtual async Task<T?> GetByIdAsync(int id)
    {
        return await _dbSet.FindAsync(id);
    }

    public async Task<T> CreateAsync(T entity)
    {
        await _dbSet.AddAsync(entity);
        await _orderDBContext.SaveChangesAsync();
        return entity;
    }

    public async Task UpdateAsync(T entity)
    {
        _orderDBContext.Entry(entity).State = EntityState.Modified;
        await _orderDBContext.SaveChangesAsync();
    }

    public async Task DeleteAsync(T entity)
    {
        _dbSet.Remove(entity);
        await _orderDBContext.SaveChangesAsync();
    }
}


================================================
FILE: docker-compose.dcproj
================================================
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" Sdk="Microsoft.Docker.Sdk">
  <PropertyGroup Label="Globals">
    <ProjectVersion>2.1</ProjectVersion>
    <DockerTargetOS>Linux</DockerTargetOS>
    <DockerPublishLocally>False</DockerPublishLocally>
    <ProjectGuid>9ed1d254-4de6-4229-b3b8-a60383414787</ProjectGuid>
    <DockerLaunchAction>LaunchBrowser</DockerLaunchAction>
    <DockerServiceUrl>{Scheme}://localhost:{ServicePort}/swagger</DockerServiceUrl>
    <DockerServiceName>catalog.api</DockerServiceName>
  </PropertyGroup>
  <ItemGroup>
    <None Remove=".github\**" />
  </ItemGroup>
  <ItemGroup>
    <None Include="docker-compose.override.yml">
      <DependentUpon>docker-compose.yml</DependentUpon>
    </None>
    <None Include="docker-compose.yml" />
    <None Include=".dockerignore" />
  </ItemGroup>
</Project>

================================================
FILE: docker-compose.override.yml
================================================
version: '3.4'

services:

  catalogdb:
    container_name: catalogdb
    restart: always
    volumes:
      - ./mongo_data:/data/db
    ports:
      - 27017:27017

  basketdb:
    container_name: basketdb
    restart: always
    ports:
      - 6379:6379

  discountdb:
    container_name: discountdb
    environment:
      - POSTGRES_USER=admin
      - POSTGRES_PASSWORD=admin1234
      - POSTGRES_DB=discountdb
    restart: always
    ports:
      - 5432:5432
    volumes:
      - postgres_data:/var/lib/postgresql/data/

  orderdb:
    container_name: orderdb
    environment:
      - SA_PASSWORD=Admin1234
      - ACCEPT_EULA=Y
    restart: always
    ports:
      - 1433:1433

  mongoclient:
    container_name: mongoclient
    restart: always
    ports:
      - 5040:3000

  pgadmin:
    container_name: pgadmin
    environment:
      - PGADMIN_DEFAULT_EMAIL=admin@aspnetrun.com
      - PGADMIN_DEFAULT_PASSWORD=admin1234
    restart: always
    ports:
      - 5050:80
    volumes:
      - pgadmin_data:/root/.pgadmin

  portainer:
    container_name: portainer
    restart: always
    ports:
      - 9000:9000
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - portainer_data:/data

  rabbitmq:
    container_name: rabbitmq
    restart: always
    ports:
      - 5672:5672
      - 15672:15672

  catalog.api:
    container_name: catalog.api
    environment:
      - ASPNETCORE_ENVIRONMENT=Development
      - ASPNETCORE_HTTP_PORTS=8000
      - DatabaseSettings:ConnectionString=mongodb://catalogdb:27017
    depends_on:
      - catalogdb
    ports:
      - 8000:8000

  basket.api:
    container_name: basket.api
    environment:
      - ASPNETCORE_ENVIRONMENT=Development
      - ASPNETCORE_HTTP_PORTS=8001
      - CacheSettings:ConnectionString=basketdb:6379
      - GrpcSettings:DiscountUrl=http://discount.grpc:8003
      - EventBusSettings:HostAddress=amqp://guest:guest@rabbitmq:5672
    depends_on:
      - basketdb
      - rabbitmq
    ports:
      - 8001:8001

  discount.api:
    container_name: discount.api
    environment:
      - ASPNETCORE_ENVIRONMENT=Development
      - ASPNETCORE_HTTP_PORTS=8002
      - DatabaseSettings:ConnectionString=Server=discountdb;Port=5432;Database=discountdb;User Id=admin;Password=admin1234
    depends_on:
      - discountdb
    ports:
      - 8002:8002

  discount.grpc:
    container_name: discount.grpc
    environment:
      - ASPNETCORE_ENVIRONMENT=Development
      - ASPNETCORE_HTTP_PORTS=8003
      - DatabaseSettings:ConnectionString=Server=discountdb;Port=5432;Database=discountdb;User Id=admin;Password=admin1234
    ports:
      - 8003:8003

  ordering.api:
    container_name: ordering.api
    environment:
      - ASPNETCORE_ENVIRONMENT=Development
      - ASPNETCORE_HTTP_PORTS=8004
      - ConnectionStrings:OrderingConnectionString=Server=orderdb;Database=orderdb;User Id=sa;Password=Admin1234;TrustServerCertificate=True;
      # Connect orderdb in SSMS using IpConfig -> Ethernet adapter vEthernet (WSL) -> Ip V4
      - EventBusSettings:HostAddress=amqp://guest:guest@rabbitmq:5672
    depends_on:
      - orderdb
      - rabbitmq
    ports:
      - 8004:8004

  ocelotapigateway:
    container_name: ocelotapigateway
    environment:
      - ASPNETCORE_ENVIRONMENT=Development
      - ASPNETCORE_HTTP_PORTS=8010
    depends_on:
      - catalog.api
      - basket.api
      - discount.api
      - ordering.api
    ports:
      - 8010:8010

  onlineshop.aggregator:
    container_name: onlineshop.aggregator
    environment:
      - ASPNETCORE_ENVIRONMENT=Development
      - ASPNETCORE_HTTP_PORTS=8005
      - ApiSettings:CatalogUrl=http://catalog.api:8000
      - ApiSettings:BasketUrl=http://basket.api:8001
      - ApiSettings:OrderingUrl=http://ordering.api:8004
    depends_on:
      - catalog.api
      - basket.api
      - ordering.api
    ports:
      - 8005:8005



================================================
FILE: docker-compose.yml
================================================
version: '3.4'

services:
  catalogdb:
    image: mongo

  basketdb:
    image: redis:alpine

  discountdb:
    image: postgres

  orderdb:
    image: mcr.microsoft.com/mssql/server

  mongoclient:
    image: mongoclient/mongoclient

  pgadmin:
    image: dpage/pgadmin4
    
  portainer:
    image: portainer/portainer-ce

  rabbitmq:
    image: rabbitmq:3-management-alpine

  catalog.api:
    image: ${DOCKER_REGISTRY-}catalogapi
    build:
      context: .
      dockerfile: Services/Catalog/Catalog.Api/Dockerfile

  basket.api:
    image: ${DOCKER_REGISTRY-}basketapi
    build:
      context: .
      dockerfile: Services/Basket/Basket.Api/Dockerfile

  discount.api:
    image: ${DOCKER_REGISTRY-}discountapi
    build:
      context: .
      dockerfile: Services/Discount/Discount.Api/Dockerfile

  discount.grpc:
    image: ${DOCKER_REGISTRY-}discountgrpc
    build:
      context: .
      dockerfile: Services/Discount/Discount.Grpc/Dockerfile

  ordering.api:
    image: ${DOCKER_REGISTRY-}orderingapi
    build:
      context: .
      dockerfile: Services/Ordering/Ordering.Api/Dockerfile

  ocelotapigateway:
    image: ${DOCKER_REGISTRY-}ocelotapigateway
    build:
      context: .
      dockerfile: ApiGateways/OcelotApiGateway/Dockerfile

  onlineshop.aggregator:
    image: ${DOCKER_REGISTRY-}onlineshopaggregator
    build:
      context: .
      dockerfile: ApiGateways/OnlineShop.Aggregator/OnlineShop.Aggregator/Dockerfile

volumes:
  portainer_data:
  postgres_data:
  pgadmin_data:




================================================
FILE: launchSettings.json
================================================
{
  "profiles": {
    "Docker Compose": {
      "commandName": "DockerCompose",
      "commandVersion": "1.0",
      "serviceActions": {
        "catalog.api": "StartDebugging",
        "basket.api": "StartDebugging",
        "discount.api": "StartDebugging",
        "discount.grpc": "StartDebugging",
        "ordering.api": "StartDebugging",
        "ocelotapigateway": "StartDebugging",
        "onlineshop.aggregator": "StartDebugging"
      }
    }
  }
}

================================================
FILE: mongo_data/WiredTiger
================================================
WiredTiger
WiredTiger 11.2.0: (November 10, 2022)


================================================
FILE: mongo_data/WiredTiger.turtle
================================================
WiredTiger version string
WiredTiger 11.2.0: (November 10, 2022)
WiredTiger version
major=11,minor=2,patch=0
file:WiredTiger.wt
access_pattern_hint=none,allocation_size=4KB,app_metadata=,assert=(commit_timestamp=none,durable_timestamp=none,read_timestamp=none,write_timestamp=off),block_allocation=best,block_compressor=,cache_resident=false,checksum=on,collator=,columns=,dictionary=0,encryption=(keyid=,name=),format=btree,huffman_key=,huffman_value=,id=0,ignore_in_memory_cache_size=false,internal_item_max=0,internal_key_max=0,internal_key_truncate=true,internal_page_max=4KB,key_format=S,key_gap=10,leaf_item_max=0,leaf_key_max=0,leaf_page_max=32KB,leaf_value_max=0,log=(enabled=true),memory_page_image_max=0,memory_page_max=5MB,os_cache_dirty_max=0,os_cache_max=0,prefix_compression=false,prefix_compression_min=4,readonly=false,split_deepen_min_child=0,split_deepen_per_child=0,split_pct=90,tiered_object=false,tiered_storage=(auth_token=,bucket=,bucket_prefix=,cache_directory=,local_retention=300,name=,object_target_size=0),value_format=S,verbose=[],version=(major=1,minor=1),write_timestamp_usage=none,checkpoint=(WiredTigerCheckpoint.1611=(addr="018081e4ae54ed9b8181e46b1ff6018281e4991a01b5808080e2afc0e23fc0",order=1611,time=1702853401,size=28672,newest_start_durable_ts=0,oldest_start_ts=0,newest_txn=146,newest_stop_durable_ts=0,newest_stop_ts=-1,newest_stop_txn=-11,prepare=0,write_gen=4768,run_write_gen=4377)),checkpoint_backup_info=,checkpoint_lsn=(75,120320)


================================================
FILE: mongo_data/journal/WiredTigerLog.0000000075
================================================
[File too large to display: 100.0 MB]

================================================
FILE: mongo_data/journal/WiredTigerPreplog.0000000001
================================================
[File too large to display: 100.0 MB]

================================================
FILE: mongo_data/journal/WiredTigerPreplog.0000000002
================================================
[File too large to display: 100.0 MB]
Download .txt
gitextract__0w2wh4p/

├── .dockerignore
├── .gitattributes
├── .gitignore
├── ApiGateways/
│   ├── OcelotApiGateway/
│   │   ├── Dockerfile
│   │   ├── OcelotApiGateway.csproj
│   │   ├── Program.cs
│   │   ├── Properties/
│   │   │   └── launchSettings.json
│   │   ├── appsettings.Development.json
│   │   ├── appsettings.json
│   │   ├── ocelot.Development.json
│   │   ├── ocelot.Local.json
│   │   └── ocelot.json
│   └── OnlineShop.Aggregator/
│       └── OnlineShop.Aggregator/
│           ├── Controllers/
│           │   └── ShoppingController.cs
│           ├── DTOs/
│           │   ├── BasketDTO.cs
│           │   ├── BasketItemExtendedDTO.cs
│           │   ├── CatalogDTO.cs
│           │   ├── OrderResponseDTO.cs
│           │   └── ShoppingDTO.cs
│           ├── Dockerfile
│           ├── Extensions/
│           │   └── HttpClientExtensions.cs
│           ├── OnlineShop.Aggregator.csproj
│           ├── OnlineShop.Aggregator.http
│           ├── Program.cs
│           ├── Properties/
│           │   └── launchSettings.json
│           ├── Services/
│           │   ├── BasketService.cs
│           │   ├── CatalogService.cs
│           │   ├── IBasketService.cs
│           │   ├── ICatalogService.cs
│           │   ├── IOrderService.cs
│           │   └── OrderService.cs
│           ├── appsettings.Development.json
│           └── appsettings.json
├── BuildingBlocks/
│   └── EventBus.Messages/
│       ├── Common/
│       │   └── EventBusConstant.cs
│       ├── EventBus.Messages.csproj
│       └── Events/
│           ├── BasketCheckoutEvent.cs
│           └── IntegrationBaseEvent.cs
├── OnlineShop.sln
├── README.md
├── Services/
│   ├── Basket/
│   │   └── Basket.Api/
│   │       ├── Basket.Api.csproj
│   │       ├── Basket.Api.http
│   │       ├── Controllers/
│   │       │   └── OrderController.cs
│   │       ├── Dockerfile
│   │       ├── Entities/
│   │       │   ├── BasketCheckout.cs
│   │       │   ├── Order.cs
│   │       │   └── OrderItem.cs
│   │       ├── GrpcServices/
│   │       │   └── DiscountGrpcService.cs
│   │       ├── Mapper/
│   │       │   └── BasketProfile.cs
│   │       ├── Program.cs
│   │       ├── Properties/
│   │       │   └── launchSettings.json
│   │       ├── Repositories/
│   │       │   ├── IOrderRepository.cs
│   │       │   └── OrderRepository.cs
│   │       ├── appsettings.Development.json
│   │       └── appsettings.json
│   ├── Catalog/
│   │   └── Catalog.Api/
│   │       ├── Catalog.Api.csproj
│   │       ├── Catalog.Api.http
│   │       ├── Controllers/
│   │       │   └── ProductController.cs
│   │       ├── Data/
│   │       │   ├── CatalogContext.cs
│   │       │   ├── CatalogContextSeed.cs
│   │       │   └── ICatalogContext.cs
│   │       ├── Dockerfile
│   │       ├── Entities/
│   │       │   └── Product.cs
│   │       ├── Products.Json
│   │       ├── Program.cs
│   │       ├── Properties/
│   │       │   └── launchSettings.json
│   │       ├── Repositories/
│   │       │   ├── IProductRepository.cs
│   │       │   └── ProductRepository.cs
│   │       ├── appsettings.Development.json
│   │       └── appsettings.json
│   ├── Discount/
│   │   ├── Discount.Api/
│   │   │   ├── Controllers/
│   │   │   │   └── CouponController.cs
│   │   │   ├── Discount.Api.csproj
│   │   │   ├── Discount.Api.http
│   │   │   ├── Dockerfile
│   │   │   ├── Entities/
│   │   │   │   └── Coupon.cs
│   │   │   ├── Extensions/
│   │   │   │   └── HostExtensions.cs
│   │   │   ├── Program.cs
│   │   │   ├── Properties/
│   │   │   │   └── launchSettings.json
│   │   │   ├── Repositories/
│   │   │   │   ├── CouponRepository.cs
│   │   │   │   └── ICouponRepository.cs
│   │   │   ├── appsettings.Development.json
│   │   │   └── appsettings.json
│   │   └── Discount.Grpc/
│   │       ├── Discount.Grpc.csproj
│   │       ├── Dockerfile
│   │       ├── Entities/
│   │       │   └── Coupon.cs
│   │       ├── Extensions/
│   │       │   └── HostExtensions.cs
│   │       ├── Mapper/
│   │       │   └── DiscountProfile.cs
│   │       ├── Program.cs
│   │       ├── Properties/
│   │       │   └── launchSettings.json
│   │       ├── Protos/
│   │       │   └── discount.proto
│   │       ├── Repositories/
│   │       │   ├── CouponRepository.cs
│   │       │   └── ICouponRepository.cs
│   │       ├── Services/
│   │       │   └── DiscountService.cs
│   │       ├── appsettings.Development.json
│   │       └── appsettings.json
│   └── Ordering/
│       ├── Ordering.Api/
│       │   ├── Controllers/
│       │   │   └── OrderController.cs
│       │   ├── Dockerfile
│       │   ├── EventBusConsumer/
│       │   │   └── BasketCheckoutConsumer.cs
│       │   ├── HostExtensions.cs
│       │   ├── Mapper/
│       │   │   └── CheckoutProfile.cs
│       │   ├── Ordering.Api.csproj
│       │   ├── Ordering.Api.http
│       │   ├── Program.cs
│       │   ├── Properties/
│       │   │   └── launchSettings.json
│       │   ├── appsettings.Development.json
│       │   └── appsettings.json
│       ├── Ordering.Application/
│       │   ├── ApplicationServiceRegistration.cs
│       │   ├── Behaviors/
│       │   │   ├── UnhandledExceptionBehavior.cs
│       │   │   └── ValidationBehavior.cs
│       │   ├── Contracts/
│       │   │   ├── Infrastructure/
│       │   │   │   └── IEmailService.cs
│       │   │   └── Persistence/
│       │   │       ├── IAsyncRepository.cs
│       │   │       └── IOrderRepository.cs
│       │   ├── Exceptions/
│       │   │   ├── NotFoundException.cs
│       │   │   └── ValidationException.cs
│       │   ├── Features/
│       │   │   └── Orders/
│       │   │       ├── Commands/
│       │   │       │   ├── CreateOrder/
│       │   │       │   │   ├── CreateOrderCommand.cs
│       │   │       │   │   ├── CreateOrderCommandHandler.cs
│       │   │       │   │   └── CreateOrderCommandValidator.cs
│       │   │       │   ├── DeleteOrder/
│       │   │       │   │   ├── DeleteOrderCommand.cs
│       │   │       │   │   └── DeleteOrderCommandHandler.cs
│       │   │       │   └── UpdateOrder/
│       │   │       │       ├── UpdateOrderCommand.cs
│       │   │       │       ├── UpdateOrderCommandHandler.cs
│       │   │       │       └── UpdateOrderCommandValidator.cs
│       │   │       └── Queries/
│       │   │           └── GetOrdersList/
│       │   │               ├── GetOrdersListQuery.cs
│       │   │               ├── GetOrdersListQueryHandler.cs
│       │   │               └── OrderViewModel.cs
│       │   ├── Mappings/
│       │   │   └── MappingProfile.cs
│       │   ├── Models/
│       │   │   ├── Email.cs
│       │   │   └── EmailSetting.cs
│       │   └── Ordering.Application.csproj
│       ├── Ordering.Domain/
│       │   ├── Common/
│       │   │   ├── EntityBase.cs
│       │   │   └── ValueObject.cs
│       │   ├── Entities/
│       │   │   └── Order.cs
│       │   └── Ordering.Domain.csproj
│       └── Ordering.Infrastructure/
│           ├── InfrastructureServiceRegistration.cs
│           ├── Migrations/
│           │   ├── 20231211200458_Init.Designer.cs
│           │   ├── 20231211200458_Init.cs
│           │   └── OrderDBContextModelSnapshot.cs
│           ├── Ordering.Infrastructure.csproj
│           ├── Persistence/
│           │   ├── OrderDBContext.cs
│           │   └── OrderDBContextSeed.cs
│           ├── Proxies/
│           │   └── EmailService.cs
│           └── Repositories/
│               ├── OrderRepository.cs
│               └── RepositoryBase.cs
├── docker-compose.dcproj
├── docker-compose.override.yml
├── docker-compose.yml
├── launchSettings.json
└── mongo_data/
    ├── WiredTiger
    ├── WiredTiger.turtle
    ├── WiredTiger.wt
    ├── WiredTigerHS.wt
    ├── _mdb_catalog.wt
    ├── collection-0--2162413245845826319.wt
    ├── collection-2--2162413245845826319.wt
    ├── collection-4--2162413245845826319.wt
    ├── collection-7--2162413245845826319.wt
    ├── diagnostic.data/
    │   ├── metrics.2023-12-05T22-35-19Z-00000
    │   ├── metrics.2023-12-05T22-54-37Z-00000
    │   ├── metrics.2023-12-05T22-56-43Z-00000
    │   ├── metrics.2023-12-05T22-58-50Z-00000
    │   ├── metrics.2023-12-05T23-02-35Z-00000
    │   ├── metrics.2023-12-05T23-04-34Z-00000
    │   ├── metrics.2023-12-06T09-50-37Z-00000
    │   ├── metrics.2023-12-06T11-17-57Z-00000
    │   ├── metrics.2023-12-06T11-45-54Z-00000
    │   ├── metrics.2023-12-06T11-47-38Z-00000
    │   ├── metrics.2023-12-06T11-49-51Z-00000
    │   ├── metrics.2023-12-06T11-51-33Z-00000
    │   ├── metrics.2023-12-06T12-01-34Z-00000
    │   ├── metrics.2023-12-06T12-22-29Z-00000
    │   ├── metrics.2023-12-06T12-25-10Z-00000
    │   ├── metrics.2023-12-06T13-14-10Z-00000
    │   ├── metrics.2023-12-06T22-44-00Z-00000
    │   ├── metrics.2023-12-07T10-00-48Z-00000
    │   ├── metrics.2023-12-07T10-42-49Z-00000
    │   ├── metrics.2023-12-09T20-35-09Z-00000
    │   ├── metrics.2023-12-09T20-52-53Z-00000
    │   ├── metrics.2023-12-09T21-12-07Z-00000
    │   ├── metrics.2023-12-09T21-22-39Z-00000
    │   ├── metrics.2023-12-10T08-52-41Z-00000
    │   ├── metrics.2023-12-10T08-53-11Z-00000
    │   ├── metrics.2023-12-10T09-02-16Z-00000
    │   ├── metrics.2023-12-10T09-03-51Z-00000
    │   ├── metrics.2023-12-10T09-10-11Z-00000
    │   ├── metrics.2023-12-10T09-12-08Z-00000
    │   ├── metrics.2023-12-10T09-12-44Z-00000
    │   ├── metrics.2023-12-10T09-14-28Z-00000
    │   ├── metrics.2023-12-10T09-22-38Z-00000
    │   ├── metrics.2023-12-10T09-24-18Z-00000
    │   ├── metrics.2023-12-10T09-26-25Z-00000
    │   ├── metrics.2023-12-10T09-27-56Z-00000
    │   ├── metrics.2023-12-10T09-31-41Z-00000
    │   ├── metrics.2023-12-10T09-34-53Z-00000
    │   ├── metrics.2023-12-10T10-05-22Z-00000
    │   ├── metrics.2023-12-10T10-06-22Z-00000
    │   ├── metrics.2023-12-10T10-12-00Z-00000
    │   ├── metrics.2023-12-10T10-20-34Z-00000
    │   ├── metrics.2023-12-10T10-27-09Z-00000
    │   ├── metrics.2023-12-10T12-12-15Z-00000
    │   ├── metrics.2023-12-10T13-36-47Z-00000
    │   ├── metrics.2023-12-10T13-43-27Z-00000
    │   ├── metrics.2023-12-10T20-59-24Z-00000
    │   ├── metrics.2023-12-11T12-23-14Z-00000
    │   ├── metrics.2023-12-11T12-30-27Z-00000
    │   ├── metrics.2023-12-11T13-08-05Z-00000
    │   ├── metrics.2023-12-11T14-37-06Z-00000
    │   ├── metrics.2023-12-11T19-48-10Z-00000
    │   ├── metrics.2023-12-11T19-48-31Z-00000
    │   ├── metrics.2023-12-12T08-42-51Z-00000
    │   ├── metrics.2023-12-12T08-46-13Z-00000
    │   ├── metrics.2023-12-12T08-49-01Z-00000
    │   ├── metrics.2023-12-12T09-02-14Z-00000
    │   ├── metrics.2023-12-12T12-16-33Z-00000
    │   ├── metrics.2023-12-12T12-34-54Z-00000
    │   ├── metrics.2023-12-12T12-37-21Z-00000
    │   ├── metrics.2023-12-12T12-40-44Z-00000
    │   ├── metrics.2023-12-12T12-45-56Z-00000
    │   ├── metrics.2023-12-12T13-11-29Z-00000
    │   ├── metrics.2023-12-12T13-14-47Z-00000
    │   ├── metrics.2023-12-12T13-16-13Z-00000
    │   ├── metrics.2023-12-12T13-17-38Z-00000
    │   ├── metrics.2023-12-12T14-53-07Z-00000
    │   ├── metrics.2023-12-13T09-56-35Z-00000
    │   ├── metrics.2023-12-13T10-54-21Z-00000
    │   ├── metrics.2023-12-13T10-56-58Z-00000
    │   ├── metrics.2023-12-13T11-45-51Z-00000
    │   ├── metrics.2023-12-13T11-46-22Z-00000
    │   ├── metrics.2023-12-16T16-22-45Z-00000
    │   ├── metrics.2023-12-17T14-03-32Z-00000
    │   ├── metrics.2023-12-17T15-15-10Z-00000
    │   └── metrics.2023-12-17T20-40-29Z-00000
    ├── index-1--2162413245845826319.wt
    ├── index-3--2162413245845826319.wt
    ├── index-5--2162413245845826319.wt
    ├── index-6--2162413245845826319.wt
    ├── index-8--2162413245845826319.wt
    ├── journal/
    │   ├── WiredTigerLog.0000000075
    │   ├── WiredTigerPreplog.0000000001
    │   └── WiredTigerPreplog.0000000002
    ├── sizeStorer.wt
    └── storage.bson
Download .txt
SYMBOL INDEX (212 symbols across 80 files)

FILE: ApiGateways/OnlineShop.Aggregator/OnlineShop.Aggregator/Controllers/ShoppingController.cs
  class ShoppingController (line 8) | [ApiController]
    method GetByUserName (line 16) | [HttpGet("{userName}")]

FILE: ApiGateways/OnlineShop.Aggregator/OnlineShop.Aggregator/DTOs/BasketDTO.cs
  class BasketDTO (line 3) | public class BasketDTO

FILE: ApiGateways/OnlineShop.Aggregator/OnlineShop.Aggregator/DTOs/BasketItemExtendedDTO.cs
  class BasketItemExtendedDTO (line 3) | public class BasketItemExtendedDTO

FILE: ApiGateways/OnlineShop.Aggregator/OnlineShop.Aggregator/DTOs/CatalogDTO.cs
  class CatalogDTO (line 3) | public class CatalogDTO

FILE: ApiGateways/OnlineShop.Aggregator/OnlineShop.Aggregator/DTOs/OrderResponseDTO.cs
  class OrderResponseDTO (line 3) | public class OrderResponseDTO

FILE: ApiGateways/OnlineShop.Aggregator/OnlineShop.Aggregator/DTOs/ShoppingDTO.cs
  class ShoppingDTO (line 3) | public class ShoppingDTO

FILE: ApiGateways/OnlineShop.Aggregator/OnlineShop.Aggregator/Extensions/HttpClientExtensions.cs
  class HttpClientExtensions (line 5) | public static class HttpClientExtensions
    method ReadContentAs (line 7) | public static async Task<T> ReadContentAs<T>(this HttpResponseMessage ...

FILE: ApiGateways/OnlineShop.Aggregator/OnlineShop.Aggregator/Services/BasketService.cs
  class BasketService (line 6) | public class BasketService(HttpClient _client) : IBasketService
    method GetBasket (line 8) | public async Task<BasketDTO> GetBasket(string userName)

FILE: ApiGateways/OnlineShop.Aggregator/OnlineShop.Aggregator/Services/CatalogService.cs
  class CatalogService (line 6) | public class CatalogService(HttpClient _client) : ICatalogService
    method GetCatalog (line 8) | public async Task<IEnumerable<CatalogDTO>> GetCatalog()
    method GetCatalog (line 14) | public async Task<CatalogDTO> GetCatalog(string id)
    method GetCatalogByCategory (line 20) | public async Task<IEnumerable<CatalogDTO>> GetCatalogByCategory(string...

FILE: ApiGateways/OnlineShop.Aggregator/OnlineShop.Aggregator/Services/IBasketService.cs
  type IBasketService (line 5) | public interface IBasketService
    method GetBasket (line 7) | Task<BasketDTO> GetBasket(string userName);

FILE: ApiGateways/OnlineShop.Aggregator/OnlineShop.Aggregator/Services/ICatalogService.cs
  type ICatalogService (line 5) | public interface ICatalogService
    method GetCatalog (line 7) | Task<IEnumerable<CatalogDTO>> GetCatalog();
    method GetCatalog (line 8) | Task<CatalogDTO> GetCatalog(string id);
    method GetCatalogByCategory (line 9) | Task<IEnumerable<CatalogDTO>> GetCatalogByCategory(string category);

FILE: ApiGateways/OnlineShop.Aggregator/OnlineShop.Aggregator/Services/IOrderService.cs
  type IOrderService (line 5) | public interface IOrderService
    method GetOrderByUserName (line 7) | Task<IEnumerable<OrderResponseDTO>> GetOrderByUserName(string userName);

FILE: ApiGateways/OnlineShop.Aggregator/OnlineShop.Aggregator/Services/OrderService.cs
  class OrderService (line 6) | public class OrderService(HttpClient _client) : IOrderService
    method GetOrderByUserName (line 8) | public async Task<IEnumerable<OrderResponseDTO>> GetOrderByUserName(st...

FILE: BuildingBlocks/EventBus.Messages/Common/EventBusConstant.cs
  class EventBusConstant (line 3) | public class EventBusConstant

FILE: BuildingBlocks/EventBus.Messages/Events/BasketCheckoutEvent.cs
  class BasketCheckoutEvent (line 3) | public class BasketCheckoutEvent : IntegrationBaseEvent

FILE: BuildingBlocks/EventBus.Messages/Events/IntegrationBaseEvent.cs
  class IntegrationBaseEvent (line 3) | public class IntegrationBaseEvent
    method IntegrationBaseEvent (line 5) | public IntegrationBaseEvent()
    method IntegrationBaseEvent (line 11) | public IntegrationBaseEvent(Guid id, DateTime createdAt)

FILE: Services/Basket/Basket.Api/Controllers/OrderController.cs
  class OrderController (line 13) | [Route("api/v1/[controller]/[action]")]
    method GetByUserName (line 22) | [HttpGet("{userName}")]
    method Update (line 30) | [HttpPost]
    method Delete (line 44) | [HttpDelete("{userName}")]
    method Checkout (line 52) | [HttpPost]

FILE: Services/Basket/Basket.Api/Entities/BasketCheckout.cs
  class BasketCheckout (line 3) | public class BasketCheckout

FILE: Services/Basket/Basket.Api/Entities/Order.cs
  class Order (line 3) | public class Order(string userName)

FILE: Services/Basket/Basket.Api/Entities/OrderItem.cs
  class OrderItem (line 3) | public class OrderItem

FILE: Services/Basket/Basket.Api/GrpcServices/DiscountGrpcService.cs
  class DiscountGrpcService (line 5) | public class DiscountGrpcService(DiscountProtoService.DiscountProtoServi...
    method GetDiscount (line 7) | public async Task<CouponModel> GetDiscount(string ProductName)

FILE: Services/Basket/Basket.Api/Mapper/BasketProfile.cs
  class BasketProfile (line 7) | public class BasketProfile : Profile
    method BasketProfile (line 9) | public BasketProfile()

FILE: Services/Basket/Basket.Api/Repositories/IOrderRepository.cs
  type IOrderRepository (line 5) | public interface IOrderRepository
    method GetByUserName (line 7) | Task<Order> GetByUserName(string userName);
    method Update (line 8) | Task<Order> Update(Order order);
    method Delete (line 9) | Task Delete(string userName);

FILE: Services/Basket/Basket.Api/Repositories/OrderRepository.cs
  class OrderRepository (line 7) | public class OrderRepository(IDistributedCache _redisCache) : IOrderRepo...
    method GetByUserName (line 9) | public async Task<Order> GetByUserName(string userName)
    method Update (line 26) | public async Task<Order> Update(Order order)
    method Delete (line 31) | public async Task Delete(string userName)

FILE: Services/Catalog/Catalog.Api/Controllers/ProductController.cs
  class ProductController (line 8) | [Route("api/v1/[controller]/[action]")]
    method GetAll (line 12) | [HttpGet]
    method GetById (line 20) | [HttpGet("{id:length(24)}")]
    method GetByName (line 34) | [HttpGet("{name}")]
    method GetByCategory (line 48) | [HttpGet("{category}")]
    method Create (line 56) | [HttpPost]
    method Update (line 64) | [HttpPut]
    method Delete (line 72) | [HttpDelete("{id:length(24)}")]

FILE: Services/Catalog/Catalog.Api/Data/CatalogContext.cs
  class CatalogContext (line 6) | public class CatalogContext : ICatalogContext
    method CatalogContext (line 8) | public CatalogContext(IConfiguration configuration)

FILE: Services/Catalog/Catalog.Api/Data/CatalogContextSeed.cs
  class CatalogContextSeed (line 6) | public class CatalogContextSeed
    method SeedData (line 8) | public static void SeedData(IMongoCollection<Product> productCollection)
    method GetSeedData (line 17) | private static List<Product> GetSeedData()

FILE: Services/Catalog/Catalog.Api/Data/ICatalogContext.cs
  type ICatalogContext (line 6) | public interface ICatalogContext

FILE: Services/Catalog/Catalog.Api/Entities/Product.cs
  class Product (line 6) | public class Product

FILE: Services/Catalog/Catalog.Api/Repositories/IProductRepository.cs
  type IProductRepository (line 5) | public interface IProductRepository
    method GetAll (line 7) | Task<IEnumerable<Product>> GetAll();
    method GetById (line 8) | Task<Product> GetById(string id);
    method GetByName (line 9) | Task<Product> GetByName(string name);
    method GetByCategory (line 10) | Task<IEnumerable<Product>> GetByCategory(string category);
    method Create (line 11) | Task Create(Product product);
    method Update (line 12) | Task<bool> Update(Product product);
    method Delete (line 13) | Task<bool> Delete(string id);

FILE: Services/Catalog/Catalog.Api/Repositories/ProductRepository.cs
  class ProductRepository (line 7) | public class ProductRepository(ICatalogContext _catalogContext) : IProdu...
    method GetAll (line 9) | public async Task<IEnumerable<Product>> GetAll()
    method GetById (line 13) | public async Task<Product> GetById(string id)
    method GetByName (line 17) | public async Task<Product> GetByName(string name)
    method GetByCategory (line 21) | public async Task<IEnumerable<Product>> GetByCategory(string category)
    method Create (line 25) | public async Task Create(Product product)
    method Update (line 29) | public async Task<bool> Update(Product product)
    method Delete (line 34) | public async Task<bool> Delete(string id)

FILE: Services/Discount/Discount.Api/Controllers/CouponController.cs
  class CouponController (line 8) | [Route("api/v1/[controller]/[action]")]
    method GetByProductName (line 12) | [HttpGet("{productName}")]
    method Create (line 20) | [HttpPost]
    method Update (line 28) | [HttpPut]
    method Delete (line 36) | [HttpDelete("{productName}")]

FILE: Services/Discount/Discount.Api/Entities/Coupon.cs
  class Coupon (line 3) | public class Coupon

FILE: Services/Discount/Discount.Api/Extensions/HostExtensions.cs
  class HostExtensions (line 5) | public static class HostExtensions
    method MigrateDatabase (line 7) | public static IHost MigrateDatabase<TContext>(this IHost host, int ret...

FILE: Services/Discount/Discount.Api/Repositories/CouponRepository.cs
  class CouponRepository (line 7) | public class CouponRepository(IConfiguration _configuration) : ICouponRe...
    method GetByProductName (line 9) | public async Task<Coupon> GetByProductName(string productName)
    method Create (line 29) | public async Task<bool> Create(Coupon coupon)
    method Update (line 41) | public async Task<bool> Update(Coupon coupon)
    method Delete (line 54) | public async Task<bool> Delete(string productName)

FILE: Services/Discount/Discount.Api/Repositories/ICouponRepository.cs
  type ICouponRepository (line 5) | public interface ICouponRepository
    method GetByProductName (line 7) | Task<Coupon> GetByProductName(string productName);
    method Create (line 8) | Task<bool> Create(Coupon coupon);
    method Update (line 9) | Task<bool> Update(Coupon coupon);
    method Delete (line 10) | Task<bool> Delete(string productName);

FILE: Services/Discount/Discount.Grpc/Entities/Coupon.cs
  class Coupon (line 3) | public class Coupon

FILE: Services/Discount/Discount.Grpc/Extensions/HostExtensions.cs
  class HostExtensions (line 5) | public static class HostExtensions
    method MigrateDatabase (line 7) | public static IHost MigrateDatabase<TContext>(this IHost host, int ret...

FILE: Services/Discount/Discount.Grpc/Mapper/DiscountProfile.cs
  class DiscountProfile (line 7) | public class DiscountProfile : Profile
    method DiscountProfile (line 9) | public DiscountProfile()

FILE: Services/Discount/Discount.Grpc/Repositories/CouponRepository.cs
  class CouponRepository (line 7) | public class CouponRepository(IConfiguration _configuration) : ICouponRe...
    method GetByProductName (line 9) | public async Task<Coupon> GetByProductName(string productName)
    method Create (line 29) | public async Task<bool> Create(Coupon coupon)
    method Update (line 41) | public async Task<bool> Update(Coupon coupon)
    method Delete (line 54) | public async Task<bool> Delete(string productName)

FILE: Services/Discount/Discount.Grpc/Repositories/ICouponRepository.cs
  type ICouponRepository (line 5) | public interface ICouponRepository
    method GetByProductName (line 7) | Task<Coupon> GetByProductName(string productName);
    method Create (line 8) | Task<bool> Create(Coupon coupon);
    method Update (line 9) | Task<bool> Update(Coupon coupon);
    method Delete (line 10) | Task<bool> Delete(string productName);

FILE: Services/Discount/Discount.Grpc/Services/DiscountService.cs
  class DiscountService (line 9) | public class DiscountService(ICouponRepository _couponRepository, IMappe...
    method GetDiscount (line 11) | public async override Task<CouponModel> GetDiscount(GetDiscountRequest...
    method CreateDiscount (line 20) | public async override Task<CouponModel> CreateDiscount(CreateDiscountR...
    method UpdateDiscount (line 30) | public async override Task<CouponModel> UpdateDiscount(UpdateDiscountR...
    method DeleteDiscount (line 40) | public async override Task<DeleteDiscountResponse> DeleteDiscount(Dele...

FILE: Services/Ordering/Ordering.Api/Controllers/OrderController.cs
  class OrderController (line 11) | [ApiController]
    method GetOrdersByUserName (line 15) | [HttpGet("{userName}")]
    method CreateOrder (line 23) | [HttpPost]
    method UpdateOrder (line 31) | [HttpPut]
    method DeleteOrder (line 40) | [HttpDelete("{id}")]

FILE: Services/Ordering/Ordering.Api/EventBusConsumer/BasketCheckoutConsumer.cs
  class BasketCheckoutConsumer (line 9) | public class BasketCheckoutConsumer(
    method Consume (line 15) | public async Task Consume(ConsumeContext<BasketCheckoutEvent> context)

FILE: Services/Ordering/Ordering.Api/HostExtensions.cs
  class HostExtensions (line 5) | public static class HostExtensions
    method MigrateDatabase (line 7) | public static IHost MigrateDatabase<TContext>(this IHost host,
    method InvokeSeeder (line 39) | private static void InvokeSeeder<TContext>(

FILE: Services/Ordering/Ordering.Api/Mapper/CheckoutProfile.cs
  class CheckoutProfile (line 7) | public class CheckoutProfile : Profile
    method CheckoutProfile (line 9) | public CheckoutProfile()

FILE: Services/Ordering/Ordering.Application/ApplicationServiceRegistration.cs
  class ApplicationServiceRegistration (line 9) | public static class ApplicationServiceRegistration
    method AddApplicationServices (line 11) | public static IServiceCollection AddApplicationServices(this IServiceC...

FILE: Services/Ordering/Ordering.Application/Behaviors/UnhandledExceptionBehavior.cs
  class UnhandledExceptionBehavior (line 7) | public class UnhandledExceptionBehavior<TRequest, TResponse>(ILogger<TRe...
    method Handle (line 10) | public async Task<TResponse> Handle(TRequest request, RequestHandlerDe...

FILE: Services/Ordering/Ordering.Application/Behaviors/ValidationBehavior.cs
  class ValidationBehavior (line 7) | public class ValidationBehavior<TRequest, TResponse>(IEnumerable<IValida...
    method Handle (line 10) | public async Task<TResponse> Handle(TRequest request, RequestHandlerDe...

FILE: Services/Ordering/Ordering.Application/Contracts/Infrastructure/IEmailService.cs
  type IEmailService (line 5) | public interface IEmailService
    method SendEmailAsync (line 7) | Task<bool> SendEmailAsync(Email email);

FILE: Services/Ordering/Ordering.Application/Contracts/Persistence/IAsyncRepository.cs
  type IAsyncRepository (line 6) | public interface IAsyncRepository<T> where T : EntityBase
    method GetAllAsync (line 8) | Task<IReadOnlyList<T>> GetAllAsync();
    method GetAsync (line 9) | Task<IReadOnlyList<T>> GetAsync(Expression<Func<T, bool>> predicate);
    method GetAsync (line 10) | Task<IReadOnlyList<T>> GetAsync(Expression<Func<T, bool>>? predicate =...
    method GetAsync (line 14) | Task<IReadOnlyList<T>> GetAsync(Expression<Func<T, bool>>? predicate =...
    method GetByIdAsync (line 18) | Task<T?> GetByIdAsync(int id);
    method CreateAsync (line 19) | Task<T> CreateAsync(T entity);
    method UpdateAsync (line 20) | Task UpdateAsync(T entity);
    method DeleteAsync (line 21) | Task DeleteAsync(T entity);

FILE: Services/Ordering/Ordering.Application/Contracts/Persistence/IOrderRepository.cs
  type IOrderRepository (line 5) | public interface IOrderRepository : IAsyncRepository<Order>
    method GetOrdersByUserName (line 7) | Task<IEnumerable<Order>> GetOrdersByUserName(string userName);

FILE: Services/Ordering/Ordering.Application/Exceptions/NotFoundException.cs
  class NotFoundException (line 3) | public class NotFoundException(string name, object key)

FILE: Services/Ordering/Ordering.Application/Exceptions/ValidationException.cs
  class ValidationException (line 5) | public class ValidationException : ApplicationException
    method ValidationException (line 7) | public ValidationException()
    method ValidationException (line 13) | public ValidationException(IEnumerable<ValidationFailure> failures) : ...

FILE: Services/Ordering/Ordering.Application/Features/Orders/Commands/CreateOrder/CreateOrderCommand.cs
  type CreateOrderCommand (line 5) | public sealed record CreateOrderCommand(

FILE: Services/Ordering/Ordering.Application/Features/Orders/Commands/CreateOrder/CreateOrderCommandHandler.cs
  class CreateOrderCommandHandler (line 11) | public class CreateOrderCommandHandler(IOrderRepository _orderRepository,
    method Handle (line 16) | public async Task<int> Handle(CreateOrderCommand request, Cancellation...
    method SendMail (line 27) | private async Task SendMail(Order order)

FILE: Services/Ordering/Ordering.Application/Features/Orders/Commands/CreateOrder/CreateOrderCommandValidator.cs
  class CreateOrderCommandValidator (line 5) | public class CreateOrderCommandValidator : AbstractValidator<CreateOrder...
    method CreateOrderCommandValidator (line 7) | public CreateOrderCommandValidator()

FILE: Services/Ordering/Ordering.Application/Features/Orders/Commands/DeleteOrder/DeleteOrderCommand.cs
  type DeleteOrderCommand (line 5) | public sealed record DeleteOrderCommand(int Id) : IRequest;

FILE: Services/Ordering/Ordering.Application/Features/Orders/Commands/DeleteOrder/DeleteOrderCommandHandler.cs
  class DeleteOrderCommandHandler (line 9) | public class DeleteOrderCommandHandler(IOrderRepository _orderRepository,
    method Handle (line 12) | public async Task Handle(DeleteOrderCommand request, CancellationToken...

FILE: Services/Ordering/Ordering.Application/Features/Orders/Commands/UpdateOrder/UpdateOrderCommand.cs
  type UpdateOrderCommand (line 5) | public sealed record UpdateOrderCommand(

FILE: Services/Ordering/Ordering.Application/Features/Orders/Commands/UpdateOrder/UpdateOrderCommandHandler.cs
  class UpdateOrderCommandHandler (line 10) | public class UpdateOrderCommandHandler(IOrderRepository _orderRepository,
    method Handle (line 14) | public async Task Handle(UpdateOrderCommand request, CancellationToken...

FILE: Services/Ordering/Ordering.Application/Features/Orders/Commands/UpdateOrder/UpdateOrderCommandValidator.cs
  class UpdateOrderCommandValidator (line 5) | public class UpdateOrderCommandValidator : AbstractValidator<UpdateOrder...
    method UpdateOrderCommandValidator (line 7) | public UpdateOrderCommandValidator()

FILE: Services/Ordering/Ordering.Application/Features/Orders/Queries/GetOrdersList/GetOrdersListQuery.cs
  type GetOrdersListQuery (line 5) | public sealed record GetOrdersListQuery(string UserName) : IRequest<List...

FILE: Services/Ordering/Ordering.Application/Features/Orders/Queries/GetOrdersList/GetOrdersListQueryHandler.cs
  class GetOrdersListQueryHandler (line 7) | public class GetOrdersListQueryHandler(IOrderRepository _orderRepository...
    method Handle (line 9) | public async Task<List<OrderViewModel>> Handle(GetOrdersListQuery requ...

FILE: Services/Ordering/Ordering.Application/Features/Orders/Queries/GetOrdersList/OrderViewModel.cs
  class OrderViewModel (line 3) | public class OrderViewModel

FILE: Services/Ordering/Ordering.Application/Mappings/MappingProfile.cs
  class MappingProfile (line 9) | public class MappingProfile : Profile
    method MappingProfile (line 11) | public MappingProfile()

FILE: Services/Ordering/Ordering.Application/Models/Email.cs
  class Email (line 9) | public class Email

FILE: Services/Ordering/Ordering.Application/Models/EmailSetting.cs
  class EmailSetting (line 3) | public class EmailSetting

FILE: Services/Ordering/Ordering.Domain/Common/EntityBase.cs
  class EntityBase (line 3) | public abstract class EntityBase

FILE: Services/Ordering/Ordering.Domain/Common/ValueObject.cs
  class ValueObject (line 3) | public abstract class ValueObject
    method EqualOperator (line 5) | protected static bool EqualOperator(ValueObject left, ValueObject right)
    method NotEqualOperator (line 14) | protected static bool NotEqualOperator(ValueObject left, ValueObject r...
    method GetEqualityComponents (line 19) | protected abstract IEnumerable<object> GetEqualityComponents();
    method Equals (line 21) | public override bool Equals(object obj)
    method GetHashCode (line 33) | public override int GetHashCode()

FILE: Services/Ordering/Ordering.Domain/Entities/Order.cs
  class Order (line 5) | public class Order : EntityBase

FILE: Services/Ordering/Ordering.Infrastructure/InfrastructureServiceRegistration.cs
  class InfrastructureServiceRegistration (line 12) | public static class InfrastructureServiceRegistration
    method AddInfrastructureServices (line 14) | public static IServiceCollection AddInfrastructureServices(this IServi...

FILE: Services/Ordering/Ordering.Infrastructure/Migrations/20231211200458_Init.Designer.cs
  class Init (line 14) | [DbContext(typeof(OrderDBContext))]
    method BuildTargetModel (line 19) | protected override void BuildTargetModel(ModelBuilder modelBuilder)

FILE: Services/Ordering/Ordering.Infrastructure/Migrations/20231211200458_Init.cs
  class Init (line 9) | public partial class Init : Migration
    method Up (line 12) | protected override void Up(MigrationBuilder migrationBuilder)
    method Down (line 42) | protected override void Down(MigrationBuilder migrationBuilder)

FILE: Services/Ordering/Ordering.Infrastructure/Migrations/OrderDBContextModelSnapshot.cs
  class OrderDBContextModelSnapshot (line 13) | [DbContext(typeof(OrderDBContext))]
    method BuildModel (line 16) | protected override void BuildModel(ModelBuilder modelBuilder)

FILE: Services/Ordering/Ordering.Infrastructure/Persistence/OrderDBContext.cs
  class OrderDBContext (line 8) | public class OrderDBContext(DbContextOptions<OrderDBContext> options) : ...
    method OnModelCreating (line 12) | protected override void OnModelCreating(ModelBuilder modelBuilder)
    method SaveChangesAsync (line 19) | public override Task<int> SaveChangesAsync(CancellationToken cancellat...

FILE: Services/Ordering/Ordering.Infrastructure/Persistence/OrderDBContextSeed.cs
  class OrderDBContextSeed (line 7) | public class OrderDBContextSeed
    method SeedAsync (line 9) | public static async Task SeedAsync(OrderDBContext orderDBContext, ILog...
    method GetPreconfiguredOrders (line 20) | private static IEnumerable<Order> GetPreconfiguredOrders()

FILE: Services/Ordering/Ordering.Infrastructure/Proxies/EmailService.cs
  class EmailService (line 6) | public class EmailService : IEmailService
    method SendEmailAsync (line 8) | public Task<bool> SendEmailAsync(Email email)

FILE: Services/Ordering/Ordering.Infrastructure/Repositories/OrderRepository.cs
  class OrderRepository (line 8) | public class OrderRepository(OrderDBContext orderDBContext)
    method GetOrdersByUserName (line 11) | public async Task<IEnumerable<Order>> GetOrdersByUserName(string userN...

FILE: Services/Ordering/Ordering.Infrastructure/Repositories/RepositoryBase.cs
  class RepositoryBase (line 9) | public class RepositoryBase<T>(OrderDBContext _orderDBContext) : IAsyncR...
    method GetAllAsync (line 13) | public async Task<IReadOnlyList<T>> GetAllAsync()
    method GetAsync (line 18) | public async Task<IReadOnlyList<T>> GetAsync(Expression<Func<T, bool>>...
    method GetAsync (line 23) | public async Task<IReadOnlyList<T>> GetAsync(Expression<Func<T, bool>>...
    method GetAsync (line 50) | public async Task<IReadOnlyList<T>> GetAsync(Expression<Func<T, bool>>...
    method GetByIdAsync (line 77) | public virtual async Task<T?> GetByIdAsync(int id)
    method CreateAsync (line 82) | public async Task<T> CreateAsync(T entity)
    method UpdateAsync (line 89) | public async Task UpdateAsync(T entity)
    method DeleteAsync (line 95) | public async Task DeleteAsync(T entity)
Condensed preview — 239 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (159K chars).
[
  {
    "path": ".dockerignore",
    "chars": 393,
    "preview": "**/.classpath\n**/.dockerignore\n**/.env\n**/.git\n**/.gitignore\n**/.project\n**/.settings\n**/.toolstarget\n**/.vs\n**/.vscode\n"
  },
  {
    "path": ".gitattributes",
    "chars": 2518,
    "preview": "###############################################################################\n# Set default behavior to automatically "
  },
  {
    "path": ".gitignore",
    "chars": 6223,
    "preview": "## Ignore Visual Studio temporary files, build results, and\n## files generated by popular Visual Studio add-ons.\n##\n## G"
  },
  {
    "path": "ApiGateways/OcelotApiGateway/Dockerfile",
    "chars": 933,
    "preview": "#See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Do"
  },
  {
    "path": "ApiGateways/OcelotApiGateway/OcelotApiGateway.csproj",
    "chars": 674,
    "preview": "<Project Sdk=\"Microsoft.NET.Sdk.Web\">\n\n  <PropertyGroup>\n    <TargetFramework>net8.0</TargetFramework>\n    <Nullable>ena"
  },
  {
    "path": "ApiGateways/OcelotApiGateway/Program.cs",
    "chars": 530,
    "preview": "using Ocelot.Cache.CacheManager;\nusing Ocelot.DependencyInjection;\nusing Ocelot.Middleware;\n\nvar builder = WebApplicatio"
  },
  {
    "path": "ApiGateways/OcelotApiGateway/Properties/launchSettings.json",
    "chars": 965,
    "preview": "{\n  \"profiles\": {\n    \"OcelotApiGateway\": {\n      \"commandName\": \"Project\",\n      \"launchBrowser\": true,\n      \"environm"
  },
  {
    "path": "ApiGateways/OcelotApiGateway/appsettings.Development.json",
    "chars": 119,
    "preview": "{\n  \"Logging\": {\n    \"LogLevel\": {\n      \"Default\": \"Information\",\n      \"Microsoft.AspNetCore\": \"Warning\"\n    }\n  }\n}\n"
  },
  {
    "path": "ApiGateways/OcelotApiGateway/appsettings.json",
    "chars": 142,
    "preview": "{\n  \"Logging\": {\n    \"LogLevel\": {\n      \"Default\": \"Information\",\n      \"Microsoft.AspNetCore\": \"Warning\"\n    }\n  },\n  "
  },
  {
    "path": "ApiGateways/OcelotApiGateway/ocelot.Development.json",
    "chars": 2936,
    "preview": "// BFF: Backend For Frontend\n{\n  \"Routes\": [\n    // Catalog.Api\n    {\n      \"DownStreamPathTemplate\": \"/api/v1/{controll"
  },
  {
    "path": "ApiGateways/OcelotApiGateway/ocelot.Local.json",
    "chars": 2921,
    "preview": "// BFF: Backend For Frontend\n{\n  \"Routes\": [\n    // Catalog.Api\n    {\n      \"DownStreamPathTemplate\": \"/api/v1/{controll"
  },
  {
    "path": "ApiGateways/OcelotApiGateway/ocelot.json",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "ApiGateways/OnlineShop.Aggregator/OnlineShop.Aggregator/Controllers/ShoppingController.cs",
    "chars": 1333,
    "preview": "using Microsoft.AspNetCore.Mvc;\nusing OnlineShop.Aggregator.DTOs;\nusing OnlineShop.Aggregator.Services;\nusing System.Ne"
  },
  {
    "path": "ApiGateways/OnlineShop.Aggregator/OnlineShop.Aggregator/DTOs/BasketDTO.cs",
    "chars": 233,
    "preview": "namespace OnlineShop.Aggregator.DTOs;\n\npublic class BasketDTO\n{\n    public string UserName { get; set; } = string.Empty"
  },
  {
    "path": "ApiGateways/OnlineShop.Aggregator/OnlineShop.Aggregator/DTOs/BasketItemExtendedDTO.cs",
    "chars": 583,
    "preview": "namespace OnlineShop.Aggregator.DTOs;\n\npublic class BasketItemExtendedDTO\n{\n    public int Quantity { get; set; }\n    p"
  },
  {
    "path": "ApiGateways/OnlineShop.Aggregator/OnlineShop.Aggregator/DTOs/CatalogDTO.cs",
    "chars": 442,
    "preview": "namespace OnlineShop.Aggregator.DTOs;\n\npublic class CatalogDTO\n{\n    public string Id { get; set; } = string.Empty;\n   "
  },
  {
    "path": "ApiGateways/OnlineShop.Aggregator/OnlineShop.Aggregator/DTOs/OrderResponseDTO.cs",
    "chars": 618,
    "preview": "namespace OnlineShop.Aggregator.DTOs;\n\npublic class OrderResponseDTO\n{\n    public string UserName { get; set; } = strin"
  },
  {
    "path": "ApiGateways/OnlineShop.Aggregator/OnlineShop.Aggregator/DTOs/ShoppingDTO.cs",
    "chars": 256,
    "preview": "namespace OnlineShop.Aggregator.DTOs;\n\npublic class ShoppingDTO\n{\n    public string UserName { get; set; } = string.Emp"
  },
  {
    "path": "ApiGateways/OnlineShop.Aggregator/OnlineShop.Aggregator/Dockerfile",
    "chars": 1066,
    "preview": "#See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Do"
  },
  {
    "path": "ApiGateways/OnlineShop.Aggregator/OnlineShop.Aggregator/Extensions/HttpClientExtensions.cs",
    "chars": 500,
    "preview": "using System.Text.Json;\n\nnamespace OnlineShop.Aggregator.Extensions;\n\npublic static class HttpClientExtensions\n{\n    pu"
  },
  {
    "path": "ApiGateways/OnlineShop.Aggregator/OnlineShop.Aggregator/OnlineShop.Aggregator.csproj",
    "chars": 675,
    "preview": "<Project Sdk=\"Microsoft.NET.Sdk.Web\">\n\n  <PropertyGroup>\n    <TargetFramework>net8.0</TargetFramework>\n    <Nullable>ena"
  },
  {
    "path": "ApiGateways/OnlineShop.Aggregator/OnlineShop.Aggregator/OnlineShop.Aggregator.http",
    "chars": 149,
    "preview": "@OnlineShop.Aggregator_HostAddress = http://localhost:5140\n\nGET {{OnlineShop.Aggregator_HostAddress}}/weatherforecast/\nA"
  },
  {
    "path": "ApiGateways/OnlineShop.Aggregator/OnlineShop.Aggregator/Program.cs",
    "chars": 1085,
    "preview": "using OnlineShop.Aggregator.Services;\nusing System.Text.Json;\n\nvar builder = WebApplication.CreateBuilder(args);\n\nbuilde"
  },
  {
    "path": "ApiGateways/OnlineShop.Aggregator/OnlineShop.Aggregator/Properties/launchSettings.json",
    "chars": 1050,
    "preview": "{\n  \"profiles\": {\n    \"OnlineShop.Aggregator\": {\n      \"commandName\": \"Project\",\n      \"launchBrowser\": true,\n      \"lau"
  },
  {
    "path": "ApiGateways/OnlineShop.Aggregator/OnlineShop.Aggregator/Services/BasketService.cs",
    "chars": 407,
    "preview": "using OnlineShop.Aggregator.DTOs;\nusing OnlineShop.Aggregator.Extensions;\n\nnamespace OnlineShop.Aggregator.Services;\n\np"
  },
  {
    "path": "ApiGateways/OnlineShop.Aggregator/OnlineShop.Aggregator/Services/CatalogService.cs",
    "chars": 862,
    "preview": "using OnlineShop.Aggregator.DTOs;\nusing OnlineShop.Aggregator.Extensions;\n\nnamespace OnlineShop.Aggregator.Services;\n\np"
  },
  {
    "path": "ApiGateways/OnlineShop.Aggregator/OnlineShop.Aggregator/Services/IBasketService.cs",
    "chars": 163,
    "preview": "using OnlineShop.Aggregator.DTOs;\n\nnamespace OnlineShop.Aggregator.Services;\n\npublic interface IBasketService\n{\n    Tas"
  },
  {
    "path": "ApiGateways/OnlineShop.Aggregator/OnlineShop.Aggregator/Services/ICatalogService.cs",
    "chars": 281,
    "preview": "using OnlineShop.Aggregator.DTOs;\n\nnamespace OnlineShop.Aggregator.Services;\n\npublic interface ICatalogService\n{\n    Ta"
  },
  {
    "path": "ApiGateways/OnlineShop.Aggregator/OnlineShop.Aggregator/Services/IOrderService.cs",
    "chars": 191,
    "preview": "using OnlineShop.Aggregator.DTOs;\n\nnamespace OnlineShop.Aggregator.Services;\n\npublic interface IOrderService\n{\n    Task"
  },
  {
    "path": "ApiGateways/OnlineShop.Aggregator/OnlineShop.Aggregator/Services/OrderService.cs",
    "chars": 453,
    "preview": "using OnlineShop.Aggregator.DTOs;\nusing OnlineShop.Aggregator.Extensions;\n\nnamespace OnlineShop.Aggregator.Services;\n\np"
  },
  {
    "path": "ApiGateways/OnlineShop.Aggregator/OnlineShop.Aggregator/appsettings.Development.json",
    "chars": 271,
    "preview": "{\n  \"ApiSettings\": {\n    \"CatalogUrl\": \"http://localhost:8000\",\n    \"BasketUrl\": \"http://localhost:8001\",\n    \"OrderingU"
  },
  {
    "path": "ApiGateways/OnlineShop.Aggregator/OnlineShop.Aggregator/appsettings.json",
    "chars": 142,
    "preview": "{\n  \"Logging\": {\n    \"LogLevel\": {\n      \"Default\": \"Information\",\n      \"Microsoft.AspNetCore\": \"Warning\"\n    }\n  },\n  "
  },
  {
    "path": "BuildingBlocks/EventBus.Messages/Common/EventBusConstant.cs",
    "chars": 142,
    "preview": "namespace EventBus.Messages.Common;\n\npublic class EventBusConstant\n{\n    public const string BasketCheckoutQueue = \"Bas"
  },
  {
    "path": "BuildingBlocks/EventBus.Messages/EventBus.Messages.csproj",
    "chars": 207,
    "preview": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>net8.0</TargetFramework>\n    <ImplicitUsings>"
  },
  {
    "path": "BuildingBlocks/EventBus.Messages/Events/BasketCheckoutEvent.cs",
    "chars": 642,
    "preview": "namespace EventBus.Messages.Events;\n\npublic class BasketCheckoutEvent : IntegrationBaseEvent\n{\n    public string UserNa"
  },
  {
    "path": "BuildingBlocks/EventBus.Messages/Events/IntegrationBaseEvent.cs",
    "chars": 401,
    "preview": "namespace EventBus.Messages.Events;\n\npublic class IntegrationBaseEvent\n{\n    public IntegrationBaseEvent()\n    {\n      "
  },
  {
    "path": "OnlineShop.sln",
    "chars": 8946,
    "preview": "\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 17\nVisualStudioVersion = 17.7.3422"
  },
  {
    "path": "README.md",
    "chars": 1918,
    "preview": "# OnlineShop\n\n🚀 **OnlineShop** is a comprehensive and feature-rich template repository for building robust .NET 8 applic"
  },
  {
    "path": "Services/Basket/Basket.Api/Basket.Api.csproj",
    "chars": 1466,
    "preview": "<Project Sdk=\"Microsoft.NET.Sdk.Web\">\n\n  <PropertyGroup>\n    <TargetFramework>net8.0</TargetFramework>\n    <Nullable>ena"
  },
  {
    "path": "Services/Basket/Basket.Api/Basket.Api.http",
    "chars": 127,
    "preview": "@Basket.Api_HostAddress = http://localhost:5033\n\nGET {{Basket.Api_HostAddress}}/weatherforecast/\nAccept: application/jso"
  },
  {
    "path": "Services/Basket/Basket.Api/Controllers/OrderController.cs",
    "chars": 2383,
    "preview": "using AutoMapper;\nusing Basket.Api.Entities;\nusing Basket.Api.GrpcServices;\nusing Basket.Api.Repositories;\nusing EventB"
  },
  {
    "path": "Services/Basket/Basket.Api/Dockerfile",
    "chars": 999,
    "preview": "#See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Do"
  },
  {
    "path": "Services/Basket/Basket.Api/Entities/BasketCheckout.cs",
    "chars": 609,
    "preview": "namespace Basket.Api.Entities;\n\npublic class BasketCheckout\n{\n    public string UserName { get; set; } = string.Empty;\n"
  },
  {
    "path": "Services/Basket/Basket.Api/Entities/Order.cs",
    "chars": 314,
    "preview": "namespace Basket.Api.Entities;\n\npublic class Order(string userName)\n{\n    public string UserName { get; set; } = userNa"
  },
  {
    "path": "Services/Basket/Basket.Api/Entities/OrderItem.cs",
    "chars": 309,
    "preview": "namespace Basket.Api.Entities;\n\npublic class OrderItem\n{\n    public int Quantity { get; set; }\n    public string Color "
  },
  {
    "path": "Services/Basket/Basket.Api/GrpcServices/DiscountGrpcService.cs",
    "chars": 415,
    "preview": "using Discount.Grpc.Protos;\n\nnamespace Basket.Api.GrpcServices;\n\npublic class DiscountGrpcService(DiscountProtoService."
  },
  {
    "path": "Services/Basket/Basket.Api/Mapper/BasketProfile.cs",
    "chars": 260,
    "preview": "using AutoMapper;\nusing Basket.Api.Entities;\nusing EventBus.Messages.Events;\n\nnamespace Basket.Api.Mapper;\n\npublic clas"
  },
  {
    "path": "Services/Basket/Basket.Api/Program.cs",
    "chars": 1156,
    "preview": "using Basket.Api.GrpcServices;\nusing Basket.Api.Repositories;\nusing Discount.Grpc.Protos;\nusing MassTransit;\n\nvar builde"
  },
  {
    "path": "Services/Basket/Basket.Api/Properties/launchSettings.json",
    "chars": 1039,
    "preview": "{\n  \"profiles\": {\n    \"Basket.Api\": {\n      \"commandName\": \"Project\",\n      \"launchBrowser\": true,\n      \"launchUrl\": \"s"
  },
  {
    "path": "Services/Basket/Basket.Api/Repositories/IOrderRepository.cs",
    "chars": 222,
    "preview": "using Basket.Api.Entities;\n\nnamespace Basket.Api.Repositories;\n\npublic interface IOrderRepository\n{\n    Task<Order> Get"
  },
  {
    "path": "Services/Basket/Basket.Api/Repositories/OrderRepository.cs",
    "chars": 950,
    "preview": "using Basket.Api.Entities;\nusing Microsoft.Extensions.Caching.Distributed;\nusing Newtonsoft.Json;\n\nnamespace Basket.Api"
  },
  {
    "path": "Services/Basket/Basket.Api/appsettings.Development.json",
    "chars": 352,
    "preview": "{\n  \"CacheSettings\": {\n    \"ConnectionString\": \"localhost:6379\"\n  },\n  \"GrpcSettings\": {\n    \"DiscountUrl\": \"http://loca"
  },
  {
    "path": "Services/Basket/Basket.Api/appsettings.json",
    "chars": 142,
    "preview": "{\n  \"Logging\": {\n    \"LogLevel\": {\n      \"Default\": \"Information\",\n      \"Microsoft.AspNetCore\": \"Warning\"\n    }\n  },\n  "
  },
  {
    "path": "Services/Catalog/Catalog.Api/Catalog.Api.csproj",
    "chars": 742,
    "preview": "<Project Sdk=\"Microsoft.NET.Sdk.Web\">\n\n  <PropertyGroup>\n    <TargetFramework>net8.0</TargetFramework>\n    <Nullable>ena"
  },
  {
    "path": "Services/Catalog/Catalog.Api/Catalog.Api.http",
    "chars": 129,
    "preview": "@Catalog.Api_HostAddress = http://localhost:5049\n\nGET {{Catalog.Api_HostAddress}}/weatherforecast/\nAccept: application/j"
  },
  {
    "path": "Services/Catalog/Catalog.Api/Controllers/ProductController.cs",
    "chars": 2960,
    "preview": "using Catalog.Api.Entities;\nusing Catalog.Api.Repositories;\nusing Microsoft.AspNetCore.Mvc;\nusing System.Net;\n\nnamespac"
  },
  {
    "path": "Services/Catalog/Catalog.Api/Data/CatalogContext.cs",
    "chars": 636,
    "preview": "using Catalog.Api.Entities;\nusing MongoDB.Driver;\n\nnamespace Catalog.Api.Data;\n\npublic class CatalogContext : ICatalogC"
  },
  {
    "path": "Services/Catalog/Catalog.Api/Data/CatalogContextSeed.cs",
    "chars": 5853,
    "preview": "using Catalog.Api.Entities;\nusing MongoDB.Driver;\n\nnamespace Catalog.Api.Data;\n\npublic class CatalogContextSeed\n{\n    p"
  },
  {
    "path": "Services/Catalog/Catalog.Api/Data/ICatalogContext.cs",
    "chars": 166,
    "preview": "using Catalog.Api.Entities;\nusing MongoDB.Driver;\n\nnamespace Catalog.Api.Data;\n\npublic interface ICatalogContext\n{\n    "
  },
  {
    "path": "Services/Catalog/Catalog.Api/Dockerfile",
    "chars": 908,
    "preview": "#See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Do"
  },
  {
    "path": "Services/Catalog/Catalog.Api/Entities/Product.cs",
    "chars": 582,
    "preview": "using MongoDB.Bson;\nusing MongoDB.Bson.Serialization.Attributes;\n\nnamespace Catalog.Api.Entities;\n\npublic class Product"
  },
  {
    "path": "Services/Catalog/Catalog.Api/Products.Json",
    "chars": 348,
    "preview": "[\n  {\n    \"Name\": \"Asus Laptop\",\n    \"Category\": \"Computers\",\n    \"Summary\": \"Summary\",\n    \"Description\": \"Description\""
  },
  {
    "path": "Services/Catalog/Catalog.Api/Program.cs",
    "chars": 506,
    "preview": "using Catalog.Api.Data;\nusing Catalog.Api.Repositories;\n\nvar builder = WebApplication.CreateBuilder(args);\n\nbuilder.Serv"
  },
  {
    "path": "Services/Catalog/Catalog.Api/Properties/launchSettings.json",
    "chars": 1040,
    "preview": "{\n  \"profiles\": {\n    \"Catalog.Api\": {\n      \"commandName\": \"Project\",\n      \"launchBrowser\": true,\n      \"launchUrl\": \""
  },
  {
    "path": "Services/Catalog/Catalog.Api/Repositories/IProductRepository.cs",
    "chars": 399,
    "preview": "using Catalog.Api.Entities;\n\nnamespace Catalog.Api.Repositories;\n\npublic interface IProductRepository\n{\n    Task<IEnume"
  },
  {
    "path": "Services/Catalog/Catalog.Api/Repositories/ProductRepository.cs",
    "chars": 1404,
    "preview": "using Catalog.Api.Data;\nusing Catalog.Api.Entities;\nusing MongoDB.Driver;\n\nnamespace Catalog.Api.Repositories;\n\npublic "
  },
  {
    "path": "Services/Catalog/Catalog.Api/appsettings.Development.json",
    "chars": 269,
    "preview": "{\n  \"DatabaseSettings\": {\n    \"ConnectionString\": \"localhost://catalogdb:27017\",\n    \"DatabaseName\": \"CatalogDB\",\n    \"C"
  },
  {
    "path": "Services/Catalog/Catalog.Api/appsettings.json",
    "chars": 142,
    "preview": "{\n  \"Logging\": {\n    \"LogLevel\": {\n      \"Default\": \"Information\",\n      \"Microsoft.AspNetCore\": \"Warning\"\n    }\n  },\n  "
  },
  {
    "path": "Services/Discount/Discount.Api/Controllers/CouponController.cs",
    "chars": 1556,
    "preview": "using Discount.Api.Entities;\nusing Discount.Api.Repositories;\nusing Microsoft.AspNetCore.Mvc;\nusing System.Net;\n\nnamesp"
  },
  {
    "path": "Services/Discount/Discount.Api/Discount.Api.csproj",
    "chars": 792,
    "preview": "<Project Sdk=\"Microsoft.NET.Sdk.Web\">\n\n  <PropertyGroup>\n    <TargetFramework>net8.0</TargetFramework>\n    <Nullable>ena"
  },
  {
    "path": "Services/Discount/Discount.Api/Discount.Api.http",
    "chars": 131,
    "preview": "@Discount.Api_HostAddress = http://localhost:5297\n\nGET {{Discount.Api_HostAddress}}/weatherforecast/\nAccept: application"
  },
  {
    "path": "Services/Discount/Discount.Api/Dockerfile",
    "chars": 921,
    "preview": "#See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Do"
  },
  {
    "path": "Services/Discount/Discount.Api/Entities/Coupon.cs",
    "chars": 247,
    "preview": "namespace Discount.Api.Entities;\n\npublic class Coupon\n{\n    public int Id { get; set; }\n    public string ProductName {"
  },
  {
    "path": "Services/Discount/Discount.Api/Extensions/HostExtensions.cs",
    "chars": 1712,
    "preview": "using Npgsql;\n\nnamespace Discount.Api.Extensions;\n\npublic static class HostExtensions\n{\n    public static IHost Migrate"
  },
  {
    "path": "Services/Discount/Discount.Api/Program.cs",
    "chars": 482,
    "preview": "using Discount.Api.Extensions;\nusing Discount.Api.Repositories;\n\nvar builder = WebApplication.CreateBuilder(args);\n\nbuil"
  },
  {
    "path": "Services/Discount/Discount.Api/Properties/launchSettings.json",
    "chars": 1041,
    "preview": "{\n  \"profiles\": {\n    \"Discount.Api\": {\n      \"commandName\": \"Project\",\n      \"launchBrowser\": true,\n      \"launchUrl\": "
  },
  {
    "path": "Services/Discount/Discount.Api/Repositories/CouponRepository.cs",
    "chars": 2072,
    "preview": "using Dapper;\nusing Discount.Api.Entities;\nusing Npgsql;\n\nnamespace Discount.Api.Repositories;\n\npublic class CouponRepo"
  },
  {
    "path": "Services/Discount/Discount.Api/Repositories/ICouponRepository.cs",
    "chars": 282,
    "preview": "using Discount.Api.Entities;\n\nnamespace Discount.Api.Repositories;\n\npublic interface ICouponRepository\n{\n    Task<Coupo"
  },
  {
    "path": "Services/Discount/Discount.Api/appsettings.Development.json",
    "chars": 255,
    "preview": "{\n  \"DatabaseSettings\": {\n    \"ConnectionString\": \"Server=localhost;port=5432;Database=discountdb;User Id=admin;Password"
  },
  {
    "path": "Services/Discount/Discount.Api/appsettings.json",
    "chars": 142,
    "preview": "{\n  \"Logging\": {\n    \"LogLevel\": {\n      \"Default\": \"Information\",\n      \"Microsoft.AspNetCore\": \"Warning\"\n    }\n  },\n  "
  },
  {
    "path": "Services/Discount/Discount.Grpc/Discount.Grpc.csproj",
    "chars": 931,
    "preview": "<Project Sdk=\"Microsoft.NET.Sdk.Web\">\n\n  <PropertyGroup>\n    <TargetFramework>net8.0</TargetFramework>\n    <Nullable>en"
  },
  {
    "path": "Services/Discount/Discount.Grpc/Dockerfile",
    "chars": 930,
    "preview": "#See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Do"
  },
  {
    "path": "Services/Discount/Discount.Grpc/Entities/Coupon.cs",
    "chars": 248,
    "preview": "namespace Discount.Grpc.Entities;\n\npublic class Coupon\n{\n    public int Id { get; set; }\n    public string ProductName "
  },
  {
    "path": "Services/Discount/Discount.Grpc/Extensions/HostExtensions.cs",
    "chars": 1713,
    "preview": "using Npgsql;\n\nnamespace Discount.Grpc.Extensions;\n\npublic static class HostExtensions\n{\n    public static IHost Migrat"
  },
  {
    "path": "Services/Discount/Discount.Grpc/Mapper/DiscountProfile.cs",
    "chars": 250,
    "preview": "using AutoMapper;\nusing Discount.Grpc.Entities;\nusing Discount.Grpc.Protos;\n\nnamespace Discount.Grpc.Mapper;\n\npublic cl"
  },
  {
    "path": "Services/Discount/Discount.Grpc/Program.cs",
    "chars": 405,
    "preview": "using Discount.Grpc.Extensions;\nusing Discount.Grpc.Repositories;\nusing Discount.Grpc.Services;\n\nvar builder = WebApplic"
  },
  {
    "path": "Services/Discount/Discount.Grpc/Properties/launchSettings.json",
    "chars": 544,
    "preview": "{\n  \"profiles\": {\n    \"Discount.Grpc\": {\n      \"commandName\": \"Project\",\n      \"environmentVariables\": {\n        \"ASPNET"
  },
  {
    "path": "Services/Discount/Discount.Grpc/Protos/discount.proto",
    "chars": 786,
    "preview": "syntax = \"proto3\";\n\noption csharp_namespace = \"Discount.Grpc.Protos\";\n\nservice DiscountProtoService {\n  rpc GetDiscount "
  },
  {
    "path": "Services/Discount/Discount.Grpc/Repositories/CouponRepository.cs",
    "chars": 2074,
    "preview": "using Dapper;\nusing Discount.Grpc.Entities;\nusing Npgsql;\n\nnamespace Discount.Grpc.Repositories;\n\npublic class CouponRe"
  },
  {
    "path": "Services/Discount/Discount.Grpc/Repositories/ICouponRepository.cs",
    "chars": 284,
    "preview": "using Discount.Grpc.Entities;\n\nnamespace Discount.Grpc.Repositories;\n\npublic interface ICouponRepository\n{\n    Task<Cou"
  },
  {
    "path": "Services/Discount/Discount.Grpc/Services/DiscountService.cs",
    "chars": 1838,
    "preview": "using AutoMapper;\nusing Discount.Grpc.Entities;\nusing Discount.Grpc.Protos;\nusing Discount.Grpc.Repositories;\nusing Grp"
  },
  {
    "path": "Services/Discount/Discount.Grpc/appsettings.Development.json",
    "chars": 255,
    "preview": "{\n  \"DatabaseSettings\": {\n    \"ConnectionString\": \"Server=localhost;port=5432;Database=discountdb;User Id=admin;Password"
  },
  {
    "path": "Services/Discount/Discount.Grpc/appsettings.json",
    "chars": 221,
    "preview": "{\n  \"Logging\": {\n    \"LogLevel\": {\n      \"Default\": \"Information\",\n      \"Microsoft.AspNetCore\": \"Warning\"\n    }\n  },\n  "
  },
  {
    "path": "Services/Ordering/Ordering.Api/Controllers/OrderController.cs",
    "chars": 1732,
    "preview": "using MediatR;\nusing Microsoft.AspNetCore.Mvc;\nusing Ordering.Application.Features.Orders.Commands.CreateOrder;\nusing O"
  },
  {
    "path": "Services/Ordering/Ordering.Api/Dockerfile",
    "chars": 1376,
    "preview": "#See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Do"
  },
  {
    "path": "Services/Ordering/Ordering.Api/EventBusConsumer/BasketCheckoutConsumer.cs",
    "chars": 702,
    "preview": "using AutoMapper;\nusing EventBus.Messages.Events;\nusing MassTransit;\nusing MediatR;\nusing Ordering.Application.Features"
  },
  {
    "path": "Services/Ordering/Ordering.Api/HostExtensions.cs",
    "chars": 1430,
    "preview": "using Microsoft.EntityFrameworkCore;\n\nnamespace Ordering.Api;\n\npublic static class HostExtensions\n{\n    public static I"
  },
  {
    "path": "Services/Ordering/Ordering.Api/Mapper/CheckoutProfile.cs",
    "chars": 309,
    "preview": "using AutoMapper;\nusing EventBus.Messages.Events;\nusing Ordering.Application.Features.Orders.Commands.CreateOrder;\n\nnam"
  },
  {
    "path": "Services/Ordering/Ordering.Api/Ordering.Api.csproj",
    "chars": 1223,
    "preview": "<Project Sdk=\"Microsoft.NET.Sdk.Web\">\n\n  <PropertyGroup>\n    <TargetFramework>net8.0</TargetFramework>\n    <Nullable>en"
  },
  {
    "path": "Services/Ordering/Ordering.Api/Ordering.Api.http",
    "chars": 131,
    "preview": "@Ordering.Api_HostAddress = http://localhost:5116\n\nGET {{Ordering.Api_HostAddress}}/weatherforecast/\nAccept: application"
  },
  {
    "path": "Services/Ordering/Ordering.Api/Program.cs",
    "chars": 1313,
    "preview": "using EventBus.Messages.Common;\nusing MassTransit;\nusing Ordering.Api;\nusing Ordering.Api.EventBusConsumer;\nusing Orderi"
  },
  {
    "path": "Services/Ordering/Ordering.Api/Properties/launchSettings.json",
    "chars": 1041,
    "preview": "{\n  \"profiles\": {\n    \"Ordering.Api\": {\n      \"commandName\": \"Project\",\n      \"launchBrowser\": true,\n      \"launchUrl\": "
  },
  {
    "path": "Services/Ordering/Ordering.Api/appsettings.Development.json",
    "chars": 364,
    "preview": "{\n  \"ConnectionStrings\": {\n    \"OrderingConnectionString\": \"Server=localhost; Database=orderdb; User Id=sa; Password=Adm"
  },
  {
    "path": "Services/Ordering/Ordering.Api/appsettings.json",
    "chars": 142,
    "preview": "{\n  \"Logging\": {\n    \"LogLevel\": {\n      \"Default\": \"Information\",\n      \"Microsoft.AspNetCore\": \"Warning\"\n    }\n  },\n  "
  },
  {
    "path": "Services/Ordering/Ordering.Application/ApplicationServiceRegistration.cs",
    "chars": 810,
    "preview": "using FluentValidation;\nusing MediatR;\nusing Microsoft.Extensions.DependencyInjection;\nusing Ordering.Application.Behav"
  },
  {
    "path": "Services/Ordering/Ordering.Application/Behaviors/UnhandledExceptionBehavior.cs",
    "chars": 723,
    "preview": "using FluentValidation;\nusing MediatR;\nusing Microsoft.Extensions.Logging;\n\nnamespace Ordering.Application.Behaviors;\n\n"
  },
  {
    "path": "Services/Ordering/Ordering.Application/Behaviors/ValidationBehavior.cs",
    "chars": 949,
    "preview": "using FluentValidation;\nusing MediatR;\n\n\nnamespace Ordering.Application.Behaviors;\n\npublic class ValidationBehavior<TRe"
  },
  {
    "path": "Services/Ordering/Ordering.Application/Contracts/Infrastructure/IEmailService.cs",
    "chars": 174,
    "preview": "using Ordering.Application.Models;\n\nnamespace Ordering.Application.Contracts.Infrastructure;\n\npublic interface IEmailSe"
  },
  {
    "path": "Services/Ordering/Ordering.Application/Contracts/Persistence/IAsyncRepository.cs",
    "chars": 900,
    "preview": "using Ordering.Domain.Common;\nusing System.Linq.Expressions;\n\nnamespace Ordering.Application.Contracts.Persistence;\n\npu"
  },
  {
    "path": "Services/Ordering/Ordering.Application/Contracts/Persistence/IOrderRepository.cs",
    "chars": 220,
    "preview": "using Ordering.Domain.Entities;\n\nnamespace Ordering.Application.Contracts.Persistence;\n\npublic interface IOrderReposito"
  },
  {
    "path": "Services/Ordering/Ordering.Application/Exceptions/NotFoundException.cs",
    "chars": 197,
    "preview": "namespace Ordering.Application.Exceptions;\n\npublic class NotFoundException(string name, object key) \n    : ApplicationE"
  },
  {
    "path": "Services/Ordering/Ordering.Application/Exceptions/ValidationException.cs",
    "chars": 587,
    "preview": "using FluentValidation.Results;\n\nnamespace Ordering.Application.Exceptions;\n\npublic class ValidationException : Applica"
  },
  {
    "path": "Services/Ordering/Ordering.Application/Features/Orders/Commands/CreateOrder/CreateOrderCommand.cs",
    "chars": 403,
    "preview": "using MediatR;\n\nnamespace Ordering.Application.Features.Orders.Commands.CreateOrder;\n\npublic sealed record CreateOrderC"
  },
  {
    "path": "Services/Ordering/Ordering.Application/Features/Orders/Commands/CreateOrder/CreateOrderCommandHandler.cs",
    "chars": 1406,
    "preview": "using AutoMapper;\nusing MediatR;\nusing Microsoft.Extensions.Logging;\nusing Ordering.Application.Contracts.Infrastructur"
  },
  {
    "path": "Services/Ordering/Ordering.Application/Features/Orders/Commands/CreateOrder/CreateOrderCommandValidator.cs",
    "chars": 736,
    "preview": "using FluentValidation;\n\nnamespace Ordering.Application.Features.Orders.Commands.CreateOrder;\n\npublic class CreateOrder"
  },
  {
    "path": "Services/Ordering/Ordering.Application/Features/Orders/Commands/DeleteOrder/DeleteOrderCommand.cs",
    "chars": 146,
    "preview": "using MediatR;\n\nnamespace Ordering.Application.Features.Orders.Commands.DeleteOrder;\n\npublic sealed record DeleteOrderC"
  },
  {
    "path": "Services/Ordering/Ordering.Application/Features/Orders/Commands/DeleteOrder/DeleteOrderCommandHandler.cs",
    "chars": 991,
    "preview": "using MediatR;\nusing Microsoft.Extensions.Logging;\nusing Ordering.Application.Contracts.Persistence;\nusing Ordering.App"
  },
  {
    "path": "Services/Ordering/Ordering.Application/Features/Orders/Commands/UpdateOrder/UpdateOrderCommand.cs",
    "chars": 414,
    "preview": "using MediatR;\n\nnamespace Ordering.Application.Features.Orders.Commands.UpdateOrder;\n\npublic sealed record UpdateOrderC"
  },
  {
    "path": "Services/Ordering/Ordering.Application/Features/Orders/Commands/UpdateOrder/UpdateOrderCommandHandler.cs",
    "chars": 1041,
    "preview": "using AutoMapper;\nusing MediatR;\nusing Microsoft.Extensions.Logging;\nusing Ordering.Application.Contracts.Persistence;\n"
  },
  {
    "path": "Services/Ordering/Ordering.Application/Features/Orders/Commands/UpdateOrder/UpdateOrderCommandValidator.cs",
    "chars": 736,
    "preview": "using FluentValidation;\n\nnamespace Ordering.Application.Features.Orders.Commands.UpdateOrder;\n\npublic class UpdateOrder"
  },
  {
    "path": "Services/Ordering/Ordering.Application/Features/Orders/Queries/GetOrdersList/GetOrdersListQuery.cs",
    "chars": 179,
    "preview": "using MediatR;\n\nnamespace Ordering.Application.Features.Orders.Queries.GetOrdersList;\n\npublic sealed record GetOrdersLi"
  },
  {
    "path": "Services/Ordering/Ordering.Application/Features/Orders/Queries/GetOrdersList/GetOrdersListQueryHandler.cs",
    "chars": 580,
    "preview": "using AutoMapper;\nusing MediatR;\nusing Ordering.Application.Contracts.Persistence;\n\nnamespace Ordering.Application.Feat"
  },
  {
    "path": "Services/Ordering/Ordering.Application/Features/Orders/Queries/GetOrdersList/OrderViewModel.cs",
    "chars": 680,
    "preview": "namespace Ordering.Application.Features.Orders.Queries.GetOrdersList;\n\npublic class OrderViewModel\n{\n    public int Id "
  },
  {
    "path": "Services/Ordering/Ordering.Application/Mappings/MappingProfile.cs",
    "chars": 551,
    "preview": "using AutoMapper;\nusing Ordering.Application.Features.Orders.Commands.CreateOrder;\nusing Ordering.Application.Features."
  },
  {
    "path": "Services/Ordering/Ordering.Application/Models/Email.cs",
    "chars": 341,
    "preview": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\n\nna"
  },
  {
    "path": "Services/Ordering/Ordering.Application/Models/EmailSetting.cs",
    "chars": 298,
    "preview": "namespace Ordering.Application.Models;\n\npublic class EmailSetting\n{\n    public string From { get; set; } = string.Empty"
  },
  {
    "path": "Services/Ordering/Ordering.Application/Ordering.Application.csproj",
    "chars": 933,
    "preview": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>net8.0</TargetFramework>\n    <ImplicitUsings>"
  },
  {
    "path": "Services/Ordering/Ordering.Domain/Common/EntityBase.cs",
    "chars": 310,
    "preview": "namespace Ordering.Domain.Common;\n\npublic abstract class EntityBase\n{\n    public int Id { get; set; }\n    public string"
  },
  {
    "path": "Services/Ordering/Ordering.Domain/Common/ValueObject.cs",
    "chars": 1003,
    "preview": "namespace Ordering.Domain.Common;\n\npublic abstract class ValueObject\n{\n    protected static bool EqualOperator(ValueObj"
  },
  {
    "path": "Services/Ordering/Ordering.Domain/Entities/Order.cs",
    "chars": 649,
    "preview": "using Ordering.Domain.Common;\n\nnamespace Ordering.Domain.Entities;\n\npublic class Order : EntityBase\n{\n    public string"
  },
  {
    "path": "Services/Ordering/Ordering.Domain/Ordering.Domain.csproj",
    "chars": 207,
    "preview": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>net8.0</TargetFramework>\n    <ImplicitUsings>"
  },
  {
    "path": "Services/Ordering/Ordering.Infrastructure/InfrastructureServiceRegistration.cs",
    "chars": 1126,
    "preview": "using Microsoft.EntityFrameworkCore;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInj"
  },
  {
    "path": "Services/Ordering/Ordering.Infrastructure/Migrations/20231211200458_Init.Designer.cs",
    "chars": 3253,
    "preview": "// <auto-generated />\nusing System;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Infrastruc"
  },
  {
    "path": "Services/Ordering/Ordering.Infrastructure/Migrations/20231211200458_Init.cs",
    "chars": 2240,
    "preview": "using System;\nusing Microsoft.EntityFrameworkCore.Migrations;\n\n#nullable disable\n\nnamespace Ordering.Infrastructure.Mig"
  },
  {
    "path": "Services/Ordering/Ordering.Infrastructure/Migrations/OrderDBContextModelSnapshot.cs",
    "chars": 3172,
    "preview": "// <auto-generated />\nusing System;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Infrastruc"
  },
  {
    "path": "Services/Ordering/Ordering.Infrastructure/Ordering.Infrastructure.csproj",
    "chars": 612,
    "preview": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>net8.0</TargetFramework>\n    <ImplicitUsings>"
  },
  {
    "path": "Services/Ordering/Ordering.Infrastructure/Persistence/OrderDBContext.cs",
    "chars": 1205,
    "preview": "using Microsoft.EntityFrameworkCore;\nusing Ordering.Domain.Common;\nusing Ordering.Domain.Entities;\nusing System.Reflect"
  },
  {
    "path": "Services/Ordering/Ordering.Infrastructure/Persistence/OrderDBContextSeed.cs",
    "chars": 1263,
    "preview": "using Microsoft.EntityFrameworkCore;\nusing Microsoft.Extensions.Logging;\nusing Ordering.Domain.Entities;\n\nnamespace Ord"
  },
  {
    "path": "Services/Ordering/Ordering.Infrastructure/Proxies/EmailService.cs",
    "chars": 280,
    "preview": "using Ordering.Application.Contracts.Infrastructure;\nusing Ordering.Application.Models;\n\nnamespace Ordering.Infrastruct"
  },
  {
    "path": "Services/Ordering/Ordering.Infrastructure/Repositories/OrderRepository.cs",
    "chars": 509,
    "preview": "using Microsoft.EntityFrameworkCore;\nusing Ordering.Application.Contracts.Persistence;\nusing Ordering.Domain.Entities;\n"
  },
  {
    "path": "Services/Ordering/Ordering.Infrastructure/Repositories/RepositoryBase.cs",
    "chars": 2741,
    "preview": "using Microsoft.EntityFrameworkCore;\nusing Ordering.Application.Contracts.Persistence;\nusing Ordering.Domain.Common;\nus"
  },
  {
    "path": "docker-compose.dcproj",
    "chars": 851,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"15.0\" Sdk=\"Microsoft.Docker.Sdk\">\n  <PropertyGroup Label=\""
  },
  {
    "path": "docker-compose.override.yml",
    "chars": 3867,
    "preview": "version: '3.4'\n\nservices:\n\n  catalogdb:\n    container_name: catalogdb\n    restart: always\n    volumes:\n      - ./mongo_d"
  },
  {
    "path": "docker-compose.yml",
    "chars": 1509,
    "preview": "version: '3.4'\n\nservices:\n  catalogdb:\n    image: mongo\n\n  basketdb:\n    image: redis:alpine\n\n  discountdb:\n    image: p"
  },
  {
    "path": "launchSettings.json",
    "chars": 460,
    "preview": "{\n  \"profiles\": {\n    \"Docker Compose\": {\n      \"commandName\": \"DockerCompose\",\n      \"commandVersion\": \"1.0\",\n      \"se"
  },
  {
    "path": "mongo_data/WiredTiger",
    "chars": 50,
    "preview": "WiredTiger\nWiredTiger 11.2.0: (November 10, 2022)\n"
  },
  {
    "path": "mongo_data/WiredTiger.turtle",
    "chars": 1479,
    "preview": "WiredTiger version string\nWiredTiger 11.2.0: (November 10, 2022)\nWiredTiger version\nmajor=11,minor=2,patch=0\nfile:WiredT"
  }
]

// ... and 92 more files (download for full content)

About this extraction

This page contains the full source code of the BehzadDara/OnlineShop GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 239 files (300.1 MB), approximately 41.5k tokens, and a symbol index with 212 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!