Merge from Dev
This commit is contained in:
commit
fd0a30d62a
29
_docker/rabbitmq/Dockerfile.nanowin
Normal file
29
_docker/rabbitmq/Dockerfile.nanowin
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
#https://github.com/spring2/dockerfiles/tree/master/rabbitmq
|
||||||
|
|
||||||
|
FROM microsoft/windowsservercore
|
||||||
|
|
||||||
|
SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"]
|
||||||
|
|
||||||
|
ENV chocolateyUseWindowsCompression false
|
||||||
|
|
||||||
|
RUN iex ((new-object net.webclient).DownloadString('https://chocolatey.org/install.ps1')); \
|
||||||
|
choco install -y curl;
|
||||||
|
|
||||||
|
RUN choco install -y erlang
|
||||||
|
ENV ERLANG_SERVICE_MANAGER_PATH="C:\Program Files\erl8.2\erts-8.2\bin"
|
||||||
|
RUN choco install -y rabbitmq
|
||||||
|
ENV RABBITMQ_SERVER="C:\Program Files\RabbitMQ Server\rabbitmq_server-3.6.5"
|
||||||
|
|
||||||
|
ENV RABBITMQ_CONFIG_FILE="c:\rabbitmq"
|
||||||
|
COPY rabbitmq.config C:/
|
||||||
|
COPY rabbitmq.config C:/Users/ContainerAdministrator/AppData/Roaming/RabbitMQ/
|
||||||
|
COPY enabled_plugins C:/Users/ContainerAdministrator/AppData/Roaming/RabbitMQ/
|
||||||
|
|
||||||
|
|
||||||
|
EXPOSE 4369
|
||||||
|
EXPOSE 5672
|
||||||
|
EXPOSE 5671
|
||||||
|
EXPOSE 15672
|
||||||
|
|
||||||
|
WORKDIR C:/Program\ Files/RabbitMQ\ Server/rabbitmq_server-3.6.5/sbin
|
||||||
|
CMD .\rabbitmq-server.bat
|
1
_docker/rabbitmq/enabled_plugins
Normal file
1
_docker/rabbitmq/enabled_plugins
Normal file
@ -0,0 +1 @@
|
|||||||
|
[rabbitmq_amqp1_0,rabbitmq_management].
|
1
_docker/rabbitmq/rabbitmq.config
Normal file
1
_docker/rabbitmq/rabbitmq.config
Normal file
@ -0,0 +1 @@
|
|||||||
|
[{rabbit, [{loopback_users, []}]}].
|
30
_docker/redis/Dockerfile.nanowin
Normal file
30
_docker/redis/Dockerfile.nanowin
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
# The MSI installs a service which is hard to override, so let's use a zip file.
|
||||||
|
|
||||||
|
FROM microsoft/windowsservercore
|
||||||
|
MAINTAINER alexellis2@gmail.com
|
||||||
|
|
||||||
|
SHELL ["powershell"]
|
||||||
|
RUN $ErrorActionPreference = 'Stop'; \
|
||||||
|
wget https://github.com/MSOpenTech/redis/releases/download/win-3.2.100/Redis-x64-3.2.100.zip -OutFile Redis-x64-3.2.100.zip ; \
|
||||||
|
Expand-Archive Redis-x64-3.2.100.zip -dest 'C:\\Program Files\\Redis\\' ; \
|
||||||
|
Remove-Item Redis-x64-3.2.100.zip -Force
|
||||||
|
|
||||||
|
RUN setx PATH '%PATH%;C:\\Program Files\\Redis\\'
|
||||||
|
WORKDIR 'C:\\Program Files\\Redis\\'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
RUN Get-Content redis.windows.conf | Where { $_ -notmatch 'bind 127.0.0.1' } | Set-Content redis.openport.conf ; \
|
||||||
|
Get-Content redis.openport.conf | Where { $_ -notmatch 'protected-mode yes' } | Set-Content redis.unprotected.conf ; \
|
||||||
|
Add-Content redis.unprotected.conf 'protected-mode no' ; \
|
||||||
|
Add-Content redis.unprotected.conf 'bind 0.0.0.0' ; \
|
||||||
|
Get-Content redis.unprotected.conf
|
||||||
|
|
||||||
|
EXPOSE 6379
|
||||||
|
|
||||||
|
RUN set-itemproperty -path 'HKLM:\SYSTEM\CurrentControlSet\Services\Dnscache\Parameters' -Name ServerPriorityTimeLimit -Value 0 -Type DWord
|
||||||
|
|
||||||
|
# Define our command to be run when launching the container
|
||||||
|
CMD .\\redis-server.exe .\\redis.unprotected.conf --port 6379 ; \
|
||||||
|
Write-Host Redis Started... ; \
|
||||||
|
while ($true) { Start-Sleep -Seconds 3600 }
|
79
docker-compose-windows.override.yml
Normal file
79
docker-compose-windows.override.yml
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
version: '2.1'
|
||||||
|
|
||||||
|
# The default docker-compose.override file can use the "localhost" as the external name for testing web apps within the same dev machine.
|
||||||
|
# The ESHOP_EXTERNAL_DNS_NAME_OR_IP environment variable is taken, by default, from the ".env" file defined like:
|
||||||
|
# ESHOP_EXTERNAL_DNS_NAME_OR_IP=localhost
|
||||||
|
# but values present in the environment vars at runtime will always override those defined inside the .env file
|
||||||
|
# An external IP or DNS name has to be used (instead localhost and the 10.0.75.1 IP) when testing the Web apps and the Xamarin apps from remote machines/devices using the same WiFi, for instance.
|
||||||
|
|
||||||
|
services:
|
||||||
|
|
||||||
|
basket.api:
|
||||||
|
environment:
|
||||||
|
- ASPNETCORE_ENVIRONMENT=Development
|
||||||
|
- ASPNETCORE_URLS=http://0.0.0.0:5103
|
||||||
|
- ConnectionString=basket.data
|
||||||
|
- identityUrl=http://identity.api:5105 #Local: You need to open your local dev-machine firewall at range 5100-5105. at range 5100-5105.
|
||||||
|
- EventBusConnection=rabbitmq
|
||||||
|
ports:
|
||||||
|
- "5103:5103"
|
||||||
|
|
||||||
|
catalog.api:
|
||||||
|
environment:
|
||||||
|
- ASPNETCORE_ENVIRONMENT=Development
|
||||||
|
- ASPNETCORE_URLS=http://0.0.0.0:5101
|
||||||
|
- ConnectionString=Server=sql.data;Database=Microsoft.eShopOnContainers.Services.CatalogDb;User Id=sa;Password=Pass@word
|
||||||
|
- ExternalCatalogBaseUrl=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5101 #Local: You need to open your local dev-machine firewall at range 5100-5105. at range 5100-5105.
|
||||||
|
- EventBusConnection=rabbitmq
|
||||||
|
ports:
|
||||||
|
- "5101:5101"
|
||||||
|
|
||||||
|
identity.api:
|
||||||
|
environment:
|
||||||
|
- ASPNETCORE_ENVIRONMENT=Development
|
||||||
|
- ASPNETCORE_URLS=http://0.0.0.0:5105
|
||||||
|
- SpaClient=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5104
|
||||||
|
- ConnectionStrings__DefaultConnection=Server=sql.data;Database=Microsoft.eShopOnContainers.Service.IdentityDb;User Id=sa;Password=Pass@word
|
||||||
|
- MvcClient=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5100 #Local: You need to open your local dev-machine firewall at range 5100-5105.
|
||||||
|
ports:
|
||||||
|
- "5105:5105"
|
||||||
|
|
||||||
|
ordering.api:
|
||||||
|
environment:
|
||||||
|
- ASPNETCORE_ENVIRONMENT=Development
|
||||||
|
- ASPNETCORE_URLS=http://0.0.0.0:5102
|
||||||
|
- ConnectionString=Server=sql.data;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word
|
||||||
|
- identityUrl=http://identity.api:5105 #Local: You need to open your local dev-machine firewall at range 5100-5105. at range 5100-5105.
|
||||||
|
- EventBusConnection=rabbitmq
|
||||||
|
ports:
|
||||||
|
- "5102:5102"
|
||||||
|
|
||||||
|
webspa:
|
||||||
|
environment:
|
||||||
|
- ASPNETCORE_ENVIRONMENT=Development
|
||||||
|
- ASPNETCORE_URLS=http://0.0.0.0:5104
|
||||||
|
- CatalogUrl=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5101
|
||||||
|
- OrderingUrl=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5102
|
||||||
|
- IdentityUrl=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5105 #Local: You need to open your local dev-machine firewall at range 5100-5105. at range 5100-5105.
|
||||||
|
- BasketUrl=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5103
|
||||||
|
ports:
|
||||||
|
- "5104:5104"
|
||||||
|
|
||||||
|
webmvc:
|
||||||
|
environment:
|
||||||
|
- ASPNETCORE_ENVIRONMENT=Development
|
||||||
|
- ASPNETCORE_URLS=http://0.0.0.0:5100
|
||||||
|
- CatalogUrl=http://catalog.api:5101
|
||||||
|
- OrderingUrl=http://ordering.api:5102
|
||||||
|
- BasketUrl=http://basket.api:5103
|
||||||
|
- IdentityUrl=http://10.0.75.1:5105 #Local: Use 10.0.75.1 in a "Docker for Windows" environment, if using "localhost" from browser.
|
||||||
|
#Remote: Use ${ESHOP_EXTERNAL_DNS_NAME_OR_IP} if using external IP or DNS name from browser.
|
||||||
|
ports:
|
||||||
|
- "5100:5100"
|
||||||
|
|
||||||
|
sql.data:
|
||||||
|
environment:
|
||||||
|
- SA_PASSWORD=Pass@word
|
||||||
|
- ACCEPT_EULA=Y
|
||||||
|
ports:
|
||||||
|
- "5433:1433"
|
80
docker-compose-windows.prod.yml
Normal file
80
docker-compose-windows.prod.yml
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
version: '2.1'
|
||||||
|
|
||||||
|
# The Production docker-compose file has to have the external/real IPs or DNS names for the services
|
||||||
|
# The ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP environment variable is taken, by default, from the ".env" file defined like:
|
||||||
|
# ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP=192.168.88.248
|
||||||
|
# but values present in the environment vars at runtime will always override those defined inside the .env file
|
||||||
|
# An external IP or DNS name has to be used when testing the Web apps and the Xamarin apps from remote machines/devices using the same WiFi, for instance.
|
||||||
|
#
|
||||||
|
# Set ASPNETCORE_ENVIRONMENT=Development to get errors while testing.
|
||||||
|
#
|
||||||
|
# You need to start it with the following CLI command:
|
||||||
|
# docker-compose -f docker-compose-windows.yml -f docker-compose-windows.prod.yml up -d
|
||||||
|
|
||||||
|
services:
|
||||||
|
|
||||||
|
basket.api:
|
||||||
|
environment:
|
||||||
|
- ASPNETCORE_ENVIRONMENT=Production
|
||||||
|
- ASPNETCORE_URLS=http://0.0.0.0:5103
|
||||||
|
- ConnectionString=basket.data
|
||||||
|
- identityUrl=http://identity.api:5105 #Local: You need to open your host's firewall at range 5100-5105. at range 5100-5105.
|
||||||
|
ports:
|
||||||
|
- "5103:5103"
|
||||||
|
|
||||||
|
catalog.api:
|
||||||
|
environment:
|
||||||
|
- ASPNETCORE_ENVIRONMENT=Production
|
||||||
|
- ASPNETCORE_URLS=http://0.0.0.0:5101
|
||||||
|
- ConnectionString=Server=sql.data;Database=Microsoft.eShopOnContainers.Services.CatalogDb;User Id=sa;Password=Pass@word
|
||||||
|
- ExternalCatalogBaseUrl=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5101 #Local: You need to open your host's firewall at range 5100-5105. at range 5100-5105.
|
||||||
|
ports:
|
||||||
|
- "5101:5101"
|
||||||
|
|
||||||
|
identity.api:
|
||||||
|
environment:
|
||||||
|
- ASPNETCORE_ENVIRONMENT=Production
|
||||||
|
- ASPNETCORE_URLS=http://0.0.0.0:5105
|
||||||
|
- SpaClient=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5104
|
||||||
|
- ConnectionStrings__DefaultConnection=Server=sql.data;Database=Microsoft.eShopOnContainers.Service.IdentityDb;User Id=sa;Password=Pass@word
|
||||||
|
- MvcClient=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5100 #Local: You need to open your host's firewall at range 5100-5105.
|
||||||
|
ports:
|
||||||
|
- "5105:5105"
|
||||||
|
|
||||||
|
ordering.api:
|
||||||
|
environment:
|
||||||
|
- ASPNETCORE_ENVIRONMENT=Production
|
||||||
|
- ASPNETCORE_URLS=http://0.0.0.0:5102
|
||||||
|
- ConnectionString=Server=sql.data;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word
|
||||||
|
- identityUrl=http://identity.api:5105 #Local: You need to open your host's firewall at range 5100-5105. at range 5100-5105.
|
||||||
|
ports:
|
||||||
|
- "5102:5102"
|
||||||
|
|
||||||
|
webspa:
|
||||||
|
environment:
|
||||||
|
- ASPNETCORE_ENVIRONMENT=Production
|
||||||
|
- ASPNETCORE_URLS=http://0.0.0.0:5104
|
||||||
|
- CatalogUrl=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5101
|
||||||
|
- OrderingUrl=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5102
|
||||||
|
- IdentityUrl=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5105 #Local: You need to open your host's firewall at range 5100-5105. at range 5100-5105.
|
||||||
|
- BasketUrl=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5103
|
||||||
|
ports:
|
||||||
|
- "5104:5104"
|
||||||
|
|
||||||
|
webmvc:
|
||||||
|
environment:
|
||||||
|
- ASPNETCORE_ENVIRONMENT=Production
|
||||||
|
- ASPNETCORE_URLS=http://0.0.0.0:5100
|
||||||
|
- CatalogUrl=http://catalog.api:5101
|
||||||
|
- OrderingUrl=http://ordering.api:5102
|
||||||
|
- IdentityUrl=http://${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}:5105 #Local: Use ${ESHOP_PROD_EXTERNAL_DNS_NAME_OR_IP}, if using external IP or DNS name from browser.
|
||||||
|
- BasketUrl=http://basket.api:5103
|
||||||
|
ports:
|
||||||
|
- "5100:5100"
|
||||||
|
|
||||||
|
sql.data:
|
||||||
|
environment:
|
||||||
|
- SA_PASSWORD=Pass@word
|
||||||
|
- ACCEPT_EULA=Y
|
||||||
|
ports:
|
||||||
|
- "5433:1433"
|
80
docker-compose-windows.yml
Normal file
80
docker-compose-windows.yml
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
version: '2.1'
|
||||||
|
|
||||||
|
services:
|
||||||
|
basket.api:
|
||||||
|
image: eshop/basket.api
|
||||||
|
build:
|
||||||
|
context: ./src/Services/Basket/Basket.API
|
||||||
|
dockerfile: Dockerfile.nanowin
|
||||||
|
depends_on:
|
||||||
|
- basket.data
|
||||||
|
- identity.api
|
||||||
|
|
||||||
|
catalog.api:
|
||||||
|
image: eshop/catalog.api
|
||||||
|
build:
|
||||||
|
context: ./src/Services/Catalog/Catalog.API
|
||||||
|
dockerfile: Dockerfile.nanowin
|
||||||
|
depends_on:
|
||||||
|
- sql.data
|
||||||
|
|
||||||
|
identity.api:
|
||||||
|
image: eshop/identity.api
|
||||||
|
build:
|
||||||
|
context: ./src/Services/Identity/Identity.API
|
||||||
|
dockerfile: Dockerfile.nanowin
|
||||||
|
depends_on:
|
||||||
|
- sql.data
|
||||||
|
|
||||||
|
ordering.api:
|
||||||
|
image: eshop/ordering.api
|
||||||
|
build:
|
||||||
|
context: ./src/Services/Ordering/Ordering.API
|
||||||
|
dockerfile: Dockerfile.nanowin
|
||||||
|
depends_on:
|
||||||
|
- sql.data
|
||||||
|
|
||||||
|
webspa:
|
||||||
|
image: eshop/webspa
|
||||||
|
build:
|
||||||
|
context: ./src/Web/WebSPA
|
||||||
|
dockerfile: Dockerfile.nanowin
|
||||||
|
depends_on:
|
||||||
|
- identity.api
|
||||||
|
- basket.api
|
||||||
|
|
||||||
|
webmvc:
|
||||||
|
image: eshop/webmvc
|
||||||
|
build:
|
||||||
|
context: ./src/Web/WebMVC
|
||||||
|
dockerfile: Dockerfile.nanowin
|
||||||
|
depends_on:
|
||||||
|
- catalog.api
|
||||||
|
- ordering.api
|
||||||
|
- identity.api
|
||||||
|
- basket.api
|
||||||
|
|
||||||
|
sql.data:
|
||||||
|
image: microsoft/mssql-server-windows
|
||||||
|
|
||||||
|
basket.data:
|
||||||
|
image: redis
|
||||||
|
build:
|
||||||
|
context: ./_docker/redis
|
||||||
|
dockerfile: Dockerfile.nanowin
|
||||||
|
ports:
|
||||||
|
- "6379:6379"
|
||||||
|
|
||||||
|
rabbitmq:
|
||||||
|
image: rabbitmq
|
||||||
|
build:
|
||||||
|
context: ./_docker/rabbitmq
|
||||||
|
dockerfile: Dockerfile.nanowin
|
||||||
|
ports:
|
||||||
|
- "5672:5672"
|
||||||
|
|
||||||
|
networks:
|
||||||
|
default:
|
||||||
|
external:
|
||||||
|
name: nat
|
||||||
|
|
@ -8,7 +8,7 @@ version: '2'
|
|||||||
#
|
#
|
||||||
# Set ASPNETCORE_ENVIRONMENT=Development to get errors while testing.
|
# Set ASPNETCORE_ENVIRONMENT=Development to get errors while testing.
|
||||||
#
|
#
|
||||||
# You need to start it with the following CLI command:
|
# You need to start it with the following CLI command:
|
||||||
# docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d
|
# docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d
|
||||||
|
|
||||||
services:
|
services:
|
||||||
|
@ -72,6 +72,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EventBus", "src\BuildingBlo
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EventBusRabbitMQ", "src\BuildingBlocks\EventBus\EventBusRabbitMQ\EventBusRabbitMQ.csproj", "{8088F3FC-6787-45FA-A924-816EC81CBFAC}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EventBusRabbitMQ", "src\BuildingBlocks\EventBus\EventBusRabbitMQ\EventBusRabbitMQ.csproj", "{8088F3FC-6787-45FA-A924-816EC81CBFAC}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IntegrationEventLogEF", "src\BuildingBlocks\EventBus\IntegrationEventLogEF\IntegrationEventLogEF.csproj", "{9EE28E45-1533-472B-8267-56C48855BA0E}"
|
||||||
|
EndProject
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "HealthChecks", "HealthChecks", "{A81ECBC2-6B00-4DCD-8388-469174033379}"
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "HealthChecks", "HealthChecks", "{A81ECBC2-6B00-4DCD-8388-469174033379}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.HealthChecks", "src\BuildingBlocks\HealthChecks\src\Microsoft.AspNetCore.HealthChecks\Microsoft.AspNetCore.HealthChecks.csproj", "{DF8367F8-E6BD-4D07-99D2-E416BF8AB01E}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.HealthChecks", "src\BuildingBlocks\HealthChecks\src\Microsoft.AspNetCore.HealthChecks\Microsoft.AspNetCore.HealthChecks.csproj", "{DF8367F8-E6BD-4D07-99D2-E416BF8AB01E}"
|
||||||
@ -896,5 +898,6 @@ Global
|
|||||||
{942ED6E8-0050-495F-A0EA-01E97F63760C} = {A81ECBC2-6B00-4DCD-8388-469174033379}
|
{942ED6E8-0050-495F-A0EA-01E97F63760C} = {A81ECBC2-6B00-4DCD-8388-469174033379}
|
||||||
{7804FC60-23E6-490C-8E08-F9FEF829F184} = {A81ECBC2-6B00-4DCD-8388-469174033379}
|
{7804FC60-23E6-490C-8E08-F9FEF829F184} = {A81ECBC2-6B00-4DCD-8388-469174033379}
|
||||||
{C0A7918D-B4F2-4E7F-8DE2-1E5279EF079F} = {E279BF0F-7F66-4F3A-A3AB-2CDA66C1CD04}
|
{C0A7918D-B4F2-4E7F-8DE2-1E5279EF079F} = {E279BF0F-7F66-4F3A-A3AB-2CDA66C1CD04}
|
||||||
|
{9EE28E45-1533-472B-8267-56C48855BA0E} = {807BB76E-B2BB-47A2-A57B-3D1B20FF5E7F}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
@ -1,18 +1,10 @@
|
|||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
# Visual Studio 15
|
# Visual Studio 15
|
||||||
VisualStudioVersion = 15.0.26213.1
|
VisualStudioVersion = 15.0.26228.9
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{932D8224-11F6-4D07-B109-DA28AD288A63}"
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{932D8224-11F6-4D07-B109-DA28AD288A63}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{3AF739CD-81D8-428D-A08A-0A58372DEBF6}"
|
|
||||||
ProjectSection(SolutionItems) = preProject
|
|
||||||
docker-compose.override.yml = docker-compose.override.yml
|
|
||||||
docker-compose.yml = docker-compose.yml
|
|
||||||
global.json = global.json
|
|
||||||
NuGet.config = NuGet.config
|
|
||||||
EndProjectSection
|
|
||||||
EndProject
|
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Services", "Services", "{91CF7717-08AB-4E65-B10E-0B426F01E2E8}"
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Services", "Services", "{91CF7717-08AB-4E65-B10E-0B426F01E2E8}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Web Apps", "Web Apps", "{E279BF0F-7F66-4F3A-A3AB-2CDA66C1CD04}"
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Web Apps", "Web Apps", "{E279BF0F-7F66-4F3A-A3AB-2CDA66C1CD04}"
|
||||||
@ -49,7 +41,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Shared Code", "Shared Code"
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Targets", "Targets", "{9CC7814B-72A6-465B-A61C-57B512DEE303}"
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Targets", "Targets", "{9CC7814B-72A6-465B-A61C-57B512DEE303}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebSPA", "src\Web\WebSPA\WebSPA.csproj"", "{9842DB3A-1391-48C7-A49C-2FABD0A18AC2}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebSPA", "src\Web\WebSPA\WebSPA.csproj", "{9842DB3A-1391-48C7-A49C-2FABD0A18AC2}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Mobile Apps", "Mobile Apps", "{B7B1D395-4E06-4036-BE86-C216756B9367}"
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Mobile Apps", "Mobile Apps", "{B7B1D395-4E06-4036-BE86-C216756B9367}"
|
||||||
EndProject
|
EndProject
|
||||||
@ -75,6 +67,28 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnitTest", "test\Services\U
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Identity.API", "src\Services\Identity\Identity.API\Identity.API.csproj", "{A579E108-5445-403D-A407-339AC4D1611B}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Identity.API", "src\Services\Identity\Identity.API\Identity.API.csproj", "{A579E108-5445-403D-A407-339AC4D1611B}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{E53339B2-1760-4266-BCC7-CA923CBCF16C}") = "docker-compose", "docker-compose.dcproj", "{FEA0C318-FFED-4D39-8781-265718CA43DD}"
|
||||||
|
ProjectSection(ProjectDependencies) = postProject
|
||||||
|
{A579E108-5445-403D-A407-339AC4D1611B} = {A579E108-5445-403D-A407-339AC4D1611B}
|
||||||
|
{9842DB3A-1391-48C7-A49C-2FABD0A18AC2} = {9842DB3A-1391-48C7-A49C-2FABD0A18AC2}
|
||||||
|
{F0333D8E-0B27-42B7-B2C6-78F3657624E2} = {F0333D8E-0B27-42B7-B2C6-78F3657624E2}
|
||||||
|
{42681D9D-750A-4DF7-BD9F-9292CFD5C253} = {42681D9D-750A-4DF7-BD9F-9292CFD5C253}
|
||||||
|
{2110CBB0-3B38-4EE4-A743-DF6968D80D90} = {2110CBB0-3B38-4EE4-A743-DF6968D80D90}
|
||||||
|
{231226CE-690B-4979-8870-9A79D80928E2} = {231226CE-690B-4979-8870-9A79D80928E2}
|
||||||
|
EndProjectSection
|
||||||
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "BuildingBlocks", "BuildingBlocks", "{1EF3AC0F-F27C-46DD-AC53-D762D2C11C45}"
|
||||||
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "EventBus", "EventBus", "{B473B70F-0796-4862-B1AD-BB742D93B868}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EventBus", "src\BuildingBlocks\EventBus\EventBus\EventBus.csproj", "{3D6B7A87-162E-4479-B256-1291BEB503B6}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EventBusRabbitMQ", "src\BuildingBlocks\EventBus\EventBusRabbitMQ\EventBusRabbitMQ.csproj", "{52AF222A-258C-4032-ACDD-857D7251BC1E}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IntegrationEventLogEF", "src\BuildingBlocks\EventBus\IntegrationEventLogEF\IntegrationEventLogEF.csproj", "{438B774F-5569-4DE2-AA62-3F8BAEB31C55}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FunctionalTests", "test\Services\FunctionalTests\FunctionalTests.csproj", "{2DA840CE-FCEA-4CF7-B1A1-ADD7775E7357}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Ad-Hoc|Any CPU = Ad-Hoc|Any CPU
|
Ad-Hoc|Any CPU = Ad-Hoc|Any CPU
|
||||||
@ -1004,6 +1018,198 @@ Global
|
|||||||
{FEA0C318-FFED-4D39-8781-265718CA43DD}.Release|x64.Build.0 = Release|Any CPU
|
{FEA0C318-FFED-4D39-8781-265718CA43DD}.Release|x64.Build.0 = Release|Any CPU
|
||||||
{FEA0C318-FFED-4D39-8781-265718CA43DD}.Release|x86.ActiveCfg = Release|Any CPU
|
{FEA0C318-FFED-4D39-8781-265718CA43DD}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
{FEA0C318-FFED-4D39-8781-265718CA43DD}.Release|x86.Build.0 = Release|Any CPU
|
{FEA0C318-FFED-4D39-8781-265718CA43DD}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
{3D6B7A87-162E-4479-B256-1291BEB503B6}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{3D6B7A87-162E-4479-B256-1291BEB503B6}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{3D6B7A87-162E-4479-B256-1291BEB503B6}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU
|
||||||
|
{3D6B7A87-162E-4479-B256-1291BEB503B6}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU
|
||||||
|
{3D6B7A87-162E-4479-B256-1291BEB503B6}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
|
||||||
|
{3D6B7A87-162E-4479-B256-1291BEB503B6}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
|
||||||
|
{3D6B7A87-162E-4479-B256-1291BEB503B6}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||||
|
{3D6B7A87-162E-4479-B256-1291BEB503B6}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||||
|
{3D6B7A87-162E-4479-B256-1291BEB503B6}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{3D6B7A87-162E-4479-B256-1291BEB503B6}.Ad-Hoc|x64.Build.0 = Debug|Any CPU
|
||||||
|
{3D6B7A87-162E-4479-B256-1291BEB503B6}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{3D6B7A87-162E-4479-B256-1291BEB503B6}.Ad-Hoc|x86.Build.0 = Debug|Any CPU
|
||||||
|
{3D6B7A87-162E-4479-B256-1291BEB503B6}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{3D6B7A87-162E-4479-B256-1291BEB503B6}.AppStore|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{3D6B7A87-162E-4479-B256-1291BEB503B6}.AppStore|ARM.ActiveCfg = Debug|Any CPU
|
||||||
|
{3D6B7A87-162E-4479-B256-1291BEB503B6}.AppStore|ARM.Build.0 = Debug|Any CPU
|
||||||
|
{3D6B7A87-162E-4479-B256-1291BEB503B6}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
|
||||||
|
{3D6B7A87-162E-4479-B256-1291BEB503B6}.AppStore|iPhone.Build.0 = Debug|Any CPU
|
||||||
|
{3D6B7A87-162E-4479-B256-1291BEB503B6}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||||
|
{3D6B7A87-162E-4479-B256-1291BEB503B6}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||||
|
{3D6B7A87-162E-4479-B256-1291BEB503B6}.AppStore|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{3D6B7A87-162E-4479-B256-1291BEB503B6}.AppStore|x64.Build.0 = Debug|Any CPU
|
||||||
|
{3D6B7A87-162E-4479-B256-1291BEB503B6}.AppStore|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{3D6B7A87-162E-4479-B256-1291BEB503B6}.AppStore|x86.Build.0 = Debug|Any CPU
|
||||||
|
{3D6B7A87-162E-4479-B256-1291BEB503B6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{3D6B7A87-162E-4479-B256-1291BEB503B6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{3D6B7A87-162E-4479-B256-1291BEB503B6}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||||
|
{3D6B7A87-162E-4479-B256-1291BEB503B6}.Debug|ARM.Build.0 = Debug|Any CPU
|
||||||
|
{3D6B7A87-162E-4479-B256-1291BEB503B6}.Debug|iPhone.ActiveCfg = Debug|Any CPU
|
||||||
|
{3D6B7A87-162E-4479-B256-1291BEB503B6}.Debug|iPhone.Build.0 = Debug|Any CPU
|
||||||
|
{3D6B7A87-162E-4479-B256-1291BEB503B6}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||||
|
{3D6B7A87-162E-4479-B256-1291BEB503B6}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||||
|
{3D6B7A87-162E-4479-B256-1291BEB503B6}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{3D6B7A87-162E-4479-B256-1291BEB503B6}.Debug|x64.Build.0 = Debug|Any CPU
|
||||||
|
{3D6B7A87-162E-4479-B256-1291BEB503B6}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{3D6B7A87-162E-4479-B256-1291BEB503B6}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{3D6B7A87-162E-4479-B256-1291BEB503B6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{3D6B7A87-162E-4479-B256-1291BEB503B6}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{3D6B7A87-162E-4479-B256-1291BEB503B6}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||||
|
{3D6B7A87-162E-4479-B256-1291BEB503B6}.Release|ARM.Build.0 = Release|Any CPU
|
||||||
|
{3D6B7A87-162E-4479-B256-1291BEB503B6}.Release|iPhone.ActiveCfg = Release|Any CPU
|
||||||
|
{3D6B7A87-162E-4479-B256-1291BEB503B6}.Release|iPhone.Build.0 = Release|Any CPU
|
||||||
|
{3D6B7A87-162E-4479-B256-1291BEB503B6}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||||
|
{3D6B7A87-162E-4479-B256-1291BEB503B6}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||||
|
{3D6B7A87-162E-4479-B256-1291BEB503B6}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{3D6B7A87-162E-4479-B256-1291BEB503B6}.Release|x64.Build.0 = Release|Any CPU
|
||||||
|
{3D6B7A87-162E-4479-B256-1291BEB503B6}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{3D6B7A87-162E-4479-B256-1291BEB503B6}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
{52AF222A-258C-4032-ACDD-857D7251BC1E}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{52AF222A-258C-4032-ACDD-857D7251BC1E}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{52AF222A-258C-4032-ACDD-857D7251BC1E}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU
|
||||||
|
{52AF222A-258C-4032-ACDD-857D7251BC1E}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU
|
||||||
|
{52AF222A-258C-4032-ACDD-857D7251BC1E}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
|
||||||
|
{52AF222A-258C-4032-ACDD-857D7251BC1E}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
|
||||||
|
{52AF222A-258C-4032-ACDD-857D7251BC1E}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||||
|
{52AF222A-258C-4032-ACDD-857D7251BC1E}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||||
|
{52AF222A-258C-4032-ACDD-857D7251BC1E}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{52AF222A-258C-4032-ACDD-857D7251BC1E}.Ad-Hoc|x64.Build.0 = Debug|Any CPU
|
||||||
|
{52AF222A-258C-4032-ACDD-857D7251BC1E}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{52AF222A-258C-4032-ACDD-857D7251BC1E}.Ad-Hoc|x86.Build.0 = Debug|Any CPU
|
||||||
|
{52AF222A-258C-4032-ACDD-857D7251BC1E}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{52AF222A-258C-4032-ACDD-857D7251BC1E}.AppStore|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{52AF222A-258C-4032-ACDD-857D7251BC1E}.AppStore|ARM.ActiveCfg = Debug|Any CPU
|
||||||
|
{52AF222A-258C-4032-ACDD-857D7251BC1E}.AppStore|ARM.Build.0 = Debug|Any CPU
|
||||||
|
{52AF222A-258C-4032-ACDD-857D7251BC1E}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
|
||||||
|
{52AF222A-258C-4032-ACDD-857D7251BC1E}.AppStore|iPhone.Build.0 = Debug|Any CPU
|
||||||
|
{52AF222A-258C-4032-ACDD-857D7251BC1E}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||||
|
{52AF222A-258C-4032-ACDD-857D7251BC1E}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||||
|
{52AF222A-258C-4032-ACDD-857D7251BC1E}.AppStore|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{52AF222A-258C-4032-ACDD-857D7251BC1E}.AppStore|x64.Build.0 = Debug|Any CPU
|
||||||
|
{52AF222A-258C-4032-ACDD-857D7251BC1E}.AppStore|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{52AF222A-258C-4032-ACDD-857D7251BC1E}.AppStore|x86.Build.0 = Debug|Any CPU
|
||||||
|
{52AF222A-258C-4032-ACDD-857D7251BC1E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{52AF222A-258C-4032-ACDD-857D7251BC1E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{52AF222A-258C-4032-ACDD-857D7251BC1E}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||||
|
{52AF222A-258C-4032-ACDD-857D7251BC1E}.Debug|ARM.Build.0 = Debug|Any CPU
|
||||||
|
{52AF222A-258C-4032-ACDD-857D7251BC1E}.Debug|iPhone.ActiveCfg = Debug|Any CPU
|
||||||
|
{52AF222A-258C-4032-ACDD-857D7251BC1E}.Debug|iPhone.Build.0 = Debug|Any CPU
|
||||||
|
{52AF222A-258C-4032-ACDD-857D7251BC1E}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||||
|
{52AF222A-258C-4032-ACDD-857D7251BC1E}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||||
|
{52AF222A-258C-4032-ACDD-857D7251BC1E}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{52AF222A-258C-4032-ACDD-857D7251BC1E}.Debug|x64.Build.0 = Debug|Any CPU
|
||||||
|
{52AF222A-258C-4032-ACDD-857D7251BC1E}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{52AF222A-258C-4032-ACDD-857D7251BC1E}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{52AF222A-258C-4032-ACDD-857D7251BC1E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{52AF222A-258C-4032-ACDD-857D7251BC1E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{52AF222A-258C-4032-ACDD-857D7251BC1E}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||||
|
{52AF222A-258C-4032-ACDD-857D7251BC1E}.Release|ARM.Build.0 = Release|Any CPU
|
||||||
|
{52AF222A-258C-4032-ACDD-857D7251BC1E}.Release|iPhone.ActiveCfg = Release|Any CPU
|
||||||
|
{52AF222A-258C-4032-ACDD-857D7251BC1E}.Release|iPhone.Build.0 = Release|Any CPU
|
||||||
|
{52AF222A-258C-4032-ACDD-857D7251BC1E}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||||
|
{52AF222A-258C-4032-ACDD-857D7251BC1E}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||||
|
{52AF222A-258C-4032-ACDD-857D7251BC1E}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{52AF222A-258C-4032-ACDD-857D7251BC1E}.Release|x64.Build.0 = Release|Any CPU
|
||||||
|
{52AF222A-258C-4032-ACDD-857D7251BC1E}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{52AF222A-258C-4032-ACDD-857D7251BC1E}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
{438B774F-5569-4DE2-AA62-3F8BAEB31C55}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{438B774F-5569-4DE2-AA62-3F8BAEB31C55}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{438B774F-5569-4DE2-AA62-3F8BAEB31C55}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU
|
||||||
|
{438B774F-5569-4DE2-AA62-3F8BAEB31C55}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU
|
||||||
|
{438B774F-5569-4DE2-AA62-3F8BAEB31C55}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
|
||||||
|
{438B774F-5569-4DE2-AA62-3F8BAEB31C55}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
|
||||||
|
{438B774F-5569-4DE2-AA62-3F8BAEB31C55}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||||
|
{438B774F-5569-4DE2-AA62-3F8BAEB31C55}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||||
|
{438B774F-5569-4DE2-AA62-3F8BAEB31C55}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{438B774F-5569-4DE2-AA62-3F8BAEB31C55}.Ad-Hoc|x64.Build.0 = Debug|Any CPU
|
||||||
|
{438B774F-5569-4DE2-AA62-3F8BAEB31C55}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{438B774F-5569-4DE2-AA62-3F8BAEB31C55}.Ad-Hoc|x86.Build.0 = Debug|Any CPU
|
||||||
|
{438B774F-5569-4DE2-AA62-3F8BAEB31C55}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{438B774F-5569-4DE2-AA62-3F8BAEB31C55}.AppStore|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{438B774F-5569-4DE2-AA62-3F8BAEB31C55}.AppStore|ARM.ActiveCfg = Debug|Any CPU
|
||||||
|
{438B774F-5569-4DE2-AA62-3F8BAEB31C55}.AppStore|ARM.Build.0 = Debug|Any CPU
|
||||||
|
{438B774F-5569-4DE2-AA62-3F8BAEB31C55}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
|
||||||
|
{438B774F-5569-4DE2-AA62-3F8BAEB31C55}.AppStore|iPhone.Build.0 = Debug|Any CPU
|
||||||
|
{438B774F-5569-4DE2-AA62-3F8BAEB31C55}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||||
|
{438B774F-5569-4DE2-AA62-3F8BAEB31C55}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||||
|
{438B774F-5569-4DE2-AA62-3F8BAEB31C55}.AppStore|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{438B774F-5569-4DE2-AA62-3F8BAEB31C55}.AppStore|x64.Build.0 = Debug|Any CPU
|
||||||
|
{438B774F-5569-4DE2-AA62-3F8BAEB31C55}.AppStore|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{438B774F-5569-4DE2-AA62-3F8BAEB31C55}.AppStore|x86.Build.0 = Debug|Any CPU
|
||||||
|
{438B774F-5569-4DE2-AA62-3F8BAEB31C55}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{438B774F-5569-4DE2-AA62-3F8BAEB31C55}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{438B774F-5569-4DE2-AA62-3F8BAEB31C55}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||||
|
{438B774F-5569-4DE2-AA62-3F8BAEB31C55}.Debug|ARM.Build.0 = Debug|Any CPU
|
||||||
|
{438B774F-5569-4DE2-AA62-3F8BAEB31C55}.Debug|iPhone.ActiveCfg = Debug|Any CPU
|
||||||
|
{438B774F-5569-4DE2-AA62-3F8BAEB31C55}.Debug|iPhone.Build.0 = Debug|Any CPU
|
||||||
|
{438B774F-5569-4DE2-AA62-3F8BAEB31C55}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||||
|
{438B774F-5569-4DE2-AA62-3F8BAEB31C55}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||||
|
{438B774F-5569-4DE2-AA62-3F8BAEB31C55}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{438B774F-5569-4DE2-AA62-3F8BAEB31C55}.Debug|x64.Build.0 = Debug|Any CPU
|
||||||
|
{438B774F-5569-4DE2-AA62-3F8BAEB31C55}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{438B774F-5569-4DE2-AA62-3F8BAEB31C55}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{438B774F-5569-4DE2-AA62-3F8BAEB31C55}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{438B774F-5569-4DE2-AA62-3F8BAEB31C55}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{438B774F-5569-4DE2-AA62-3F8BAEB31C55}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||||
|
{438B774F-5569-4DE2-AA62-3F8BAEB31C55}.Release|ARM.Build.0 = Release|Any CPU
|
||||||
|
{438B774F-5569-4DE2-AA62-3F8BAEB31C55}.Release|iPhone.ActiveCfg = Release|Any CPU
|
||||||
|
{438B774F-5569-4DE2-AA62-3F8BAEB31C55}.Release|iPhone.Build.0 = Release|Any CPU
|
||||||
|
{438B774F-5569-4DE2-AA62-3F8BAEB31C55}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||||
|
{438B774F-5569-4DE2-AA62-3F8BAEB31C55}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||||
|
{438B774F-5569-4DE2-AA62-3F8BAEB31C55}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{438B774F-5569-4DE2-AA62-3F8BAEB31C55}.Release|x64.Build.0 = Release|Any CPU
|
||||||
|
{438B774F-5569-4DE2-AA62-3F8BAEB31C55}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{438B774F-5569-4DE2-AA62-3F8BAEB31C55}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
{2DA840CE-FCEA-4CF7-B1A1-ADD7775E7357}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{2DA840CE-FCEA-4CF7-B1A1-ADD7775E7357}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{2DA840CE-FCEA-4CF7-B1A1-ADD7775E7357}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU
|
||||||
|
{2DA840CE-FCEA-4CF7-B1A1-ADD7775E7357}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU
|
||||||
|
{2DA840CE-FCEA-4CF7-B1A1-ADD7775E7357}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
|
||||||
|
{2DA840CE-FCEA-4CF7-B1A1-ADD7775E7357}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
|
||||||
|
{2DA840CE-FCEA-4CF7-B1A1-ADD7775E7357}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||||
|
{2DA840CE-FCEA-4CF7-B1A1-ADD7775E7357}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||||
|
{2DA840CE-FCEA-4CF7-B1A1-ADD7775E7357}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{2DA840CE-FCEA-4CF7-B1A1-ADD7775E7357}.Ad-Hoc|x64.Build.0 = Debug|Any CPU
|
||||||
|
{2DA840CE-FCEA-4CF7-B1A1-ADD7775E7357}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{2DA840CE-FCEA-4CF7-B1A1-ADD7775E7357}.Ad-Hoc|x86.Build.0 = Debug|Any CPU
|
||||||
|
{2DA840CE-FCEA-4CF7-B1A1-ADD7775E7357}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{2DA840CE-FCEA-4CF7-B1A1-ADD7775E7357}.AppStore|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{2DA840CE-FCEA-4CF7-B1A1-ADD7775E7357}.AppStore|ARM.ActiveCfg = Debug|Any CPU
|
||||||
|
{2DA840CE-FCEA-4CF7-B1A1-ADD7775E7357}.AppStore|ARM.Build.0 = Debug|Any CPU
|
||||||
|
{2DA840CE-FCEA-4CF7-B1A1-ADD7775E7357}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
|
||||||
|
{2DA840CE-FCEA-4CF7-B1A1-ADD7775E7357}.AppStore|iPhone.Build.0 = Debug|Any CPU
|
||||||
|
{2DA840CE-FCEA-4CF7-B1A1-ADD7775E7357}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||||
|
{2DA840CE-FCEA-4CF7-B1A1-ADD7775E7357}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||||
|
{2DA840CE-FCEA-4CF7-B1A1-ADD7775E7357}.AppStore|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{2DA840CE-FCEA-4CF7-B1A1-ADD7775E7357}.AppStore|x64.Build.0 = Debug|Any CPU
|
||||||
|
{2DA840CE-FCEA-4CF7-B1A1-ADD7775E7357}.AppStore|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{2DA840CE-FCEA-4CF7-B1A1-ADD7775E7357}.AppStore|x86.Build.0 = Debug|Any CPU
|
||||||
|
{2DA840CE-FCEA-4CF7-B1A1-ADD7775E7357}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{2DA840CE-FCEA-4CF7-B1A1-ADD7775E7357}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{2DA840CE-FCEA-4CF7-B1A1-ADD7775E7357}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||||
|
{2DA840CE-FCEA-4CF7-B1A1-ADD7775E7357}.Debug|ARM.Build.0 = Debug|Any CPU
|
||||||
|
{2DA840CE-FCEA-4CF7-B1A1-ADD7775E7357}.Debug|iPhone.ActiveCfg = Debug|Any CPU
|
||||||
|
{2DA840CE-FCEA-4CF7-B1A1-ADD7775E7357}.Debug|iPhone.Build.0 = Debug|Any CPU
|
||||||
|
{2DA840CE-FCEA-4CF7-B1A1-ADD7775E7357}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||||
|
{2DA840CE-FCEA-4CF7-B1A1-ADD7775E7357}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||||
|
{2DA840CE-FCEA-4CF7-B1A1-ADD7775E7357}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{2DA840CE-FCEA-4CF7-B1A1-ADD7775E7357}.Debug|x64.Build.0 = Debug|Any CPU
|
||||||
|
{2DA840CE-FCEA-4CF7-B1A1-ADD7775E7357}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{2DA840CE-FCEA-4CF7-B1A1-ADD7775E7357}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{2DA840CE-FCEA-4CF7-B1A1-ADD7775E7357}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{2DA840CE-FCEA-4CF7-B1A1-ADD7775E7357}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{2DA840CE-FCEA-4CF7-B1A1-ADD7775E7357}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||||
|
{2DA840CE-FCEA-4CF7-B1A1-ADD7775E7357}.Release|ARM.Build.0 = Release|Any CPU
|
||||||
|
{2DA840CE-FCEA-4CF7-B1A1-ADD7775E7357}.Release|iPhone.ActiveCfg = Release|Any CPU
|
||||||
|
{2DA840CE-FCEA-4CF7-B1A1-ADD7775E7357}.Release|iPhone.Build.0 = Release|Any CPU
|
||||||
|
{2DA840CE-FCEA-4CF7-B1A1-ADD7775E7357}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||||
|
{2DA840CE-FCEA-4CF7-B1A1-ADD7775E7357}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||||
|
{2DA840CE-FCEA-4CF7-B1A1-ADD7775E7357}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{2DA840CE-FCEA-4CF7-B1A1-ADD7775E7357}.Release|x64.Build.0 = Release|Any CPU
|
||||||
|
{2DA840CE-FCEA-4CF7-B1A1-ADD7775E7357}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{2DA840CE-FCEA-4CF7-B1A1-ADD7775E7357}.Release|x86.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
@ -1039,5 +1245,11 @@ Global
|
|||||||
{67F9D3A8-F71E-4428-913F-C37AE82CDB24} = {778289CA-31F7-4464-8C2A-612EE846F8A7}
|
{67F9D3A8-F71E-4428-913F-C37AE82CDB24} = {778289CA-31F7-4464-8C2A-612EE846F8A7}
|
||||||
{7796F5D8-31FC-45A4-B673-19DE5BA194CF} = {EF0337F2-ED00-4643-89FD-EE10863F1870}
|
{7796F5D8-31FC-45A4-B673-19DE5BA194CF} = {EF0337F2-ED00-4643-89FD-EE10863F1870}
|
||||||
{A579E108-5445-403D-A407-339AC4D1611B} = {02DF7FEE-C302-433D-A6CD-237A2569F236}
|
{A579E108-5445-403D-A407-339AC4D1611B} = {02DF7FEE-C302-433D-A6CD-237A2569F236}
|
||||||
|
{1EF3AC0F-F27C-46DD-AC53-D762D2C11C45} = {932D8224-11F6-4D07-B109-DA28AD288A63}
|
||||||
|
{B473B70F-0796-4862-B1AD-BB742D93B868} = {1EF3AC0F-F27C-46DD-AC53-D762D2C11C45}
|
||||||
|
{3D6B7A87-162E-4479-B256-1291BEB503B6} = {B473B70F-0796-4862-B1AD-BB742D93B868}
|
||||||
|
{52AF222A-258C-4032-ACDD-857D7251BC1E} = {B473B70F-0796-4862-B1AD-BB742D93B868}
|
||||||
|
{438B774F-5569-4DE2-AA62-3F8BAEB31C55} = {B473B70F-0796-4862-B1AD-BB742D93B868}
|
||||||
|
{2DA840CE-FCEA-4CF7-B1A1-ADD7775E7357} = {EF0337F2-ED00-4643-89FD-EE10863F1870}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
@ -9,8 +9,10 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events
|
|||||||
public IntegrationEvent()
|
public IntegrationEvent()
|
||||||
{
|
{
|
||||||
Id = Guid.NewGuid();
|
Id = Guid.NewGuid();
|
||||||
|
CreationDate = DateTime.UtcNow;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Guid Id { get; }
|
public Guid Id { get; }
|
||||||
|
public DateTime CreationDate { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events.IntegrationEventLog
|
namespace Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF
|
||||||
{
|
{
|
||||||
public enum EventStateEnum
|
public enum EventStateEnum
|
||||||
{
|
{
|
@ -0,0 +1,48 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF
|
||||||
|
{
|
||||||
|
public class IntegrationEventLogContext : DbContext
|
||||||
|
{
|
||||||
|
public IntegrationEventLogContext(DbContextOptions<IntegrationEventLogContext> options) : base(options)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public DbSet<IntegrationEventLogEntry> IntegrationEventLogs { get; set; }
|
||||||
|
|
||||||
|
protected override void OnModelCreating(ModelBuilder builder)
|
||||||
|
{
|
||||||
|
builder.Entity<IntegrationEventLogEntry>(ConfigureIntegrationEventLogEntry);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigureIntegrationEventLogEntry(EntityTypeBuilder<IntegrationEventLogEntry> builder)
|
||||||
|
{
|
||||||
|
builder.ToTable("IntegrationEventLog");
|
||||||
|
|
||||||
|
builder.HasKey(e => e.EventId);
|
||||||
|
|
||||||
|
builder.Property(e => e.EventId)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
builder.Property(e => e.Content)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
builder.Property(e => e.CreationTime)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
builder.Property(e => e.State)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
builder.Property(e => e.TimesSent)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
builder.Property(e => e.EventTypeName)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>netcoreapp1.1</TargetFramework>
|
||||||
|
<RuntimeFrameworkVersion>1.1.0</RuntimeFrameworkVersion>
|
||||||
|
<RootNamespace>Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF</RootNamespace>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="1.1.1" />
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="1.1.1" />
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="1.1.1" />
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="1.1.1" />
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer.Design" Version="1.1.1" />
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="1.1.0" />
|
||||||
|
<PackageReference Include="Newtonsoft.Json" Version="9.0.1" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="1.0.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\EventBus\EventBus.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
@ -2,15 +2,17 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events;
|
||||||
|
|
||||||
namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events.IntegrationEventLog
|
namespace Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF
|
||||||
{
|
{
|
||||||
public class IntegrationEventLogEntry
|
public class IntegrationEventLogEntry
|
||||||
{
|
{
|
||||||
|
private IntegrationEventLogEntry() { }
|
||||||
public IntegrationEventLogEntry(IntegrationEvent @event)
|
public IntegrationEventLogEntry(IntegrationEvent @event)
|
||||||
{
|
{
|
||||||
EventId = @event.Id;
|
EventId = @event.Id;
|
||||||
CreationTime = DateTime.UtcNow;
|
CreationTime = @event.CreationDate;
|
||||||
EventTypeName = @event.GetType().FullName;
|
EventTypeName = @event.GetType().FullName;
|
||||||
Content = JsonConvert.SerializeObject(@event);
|
Content = JsonConvert.SerializeObject(@event);
|
||||||
State = EventStateEnum.NotPublished;
|
State = EventStateEnum.NotPublished;
|
@ -0,0 +1,15 @@
|
|||||||
|
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Data.Common;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF.Services
|
||||||
|
{
|
||||||
|
public interface IIntegrationEventLogService
|
||||||
|
{
|
||||||
|
Task SaveEventAsync(IntegrationEvent @event, DbTransaction transaction);
|
||||||
|
Task MarkEventAsPublishedAsync(IntegrationEvent @event);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,53 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage;
|
||||||
|
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events;
|
||||||
|
using System.Data.Common;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF.Services
|
||||||
|
{
|
||||||
|
public class IntegrationEventLogService : IIntegrationEventLogService
|
||||||
|
{
|
||||||
|
private readonly IntegrationEventLogContext _integrationEventLogContext;
|
||||||
|
private readonly DbConnection _dbConnection;
|
||||||
|
|
||||||
|
public IntegrationEventLogService(DbConnection dbConnection)
|
||||||
|
{
|
||||||
|
_dbConnection = dbConnection?? throw new ArgumentNullException("dbConnection");
|
||||||
|
_integrationEventLogContext = new IntegrationEventLogContext(
|
||||||
|
new DbContextOptionsBuilder<IntegrationEventLogContext>()
|
||||||
|
.UseSqlServer(_dbConnection)
|
||||||
|
.ConfigureWarnings(warnings => warnings.Throw(RelationalEventId.QueryClientEvaluationWarning))
|
||||||
|
.Options);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task SaveEventAsync(IntegrationEvent @event, DbTransaction transaction)
|
||||||
|
{
|
||||||
|
if(transaction == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException("transaction", $"A {typeof(DbTransaction).FullName} is required as a pre-requisite to save the event.");
|
||||||
|
}
|
||||||
|
|
||||||
|
var eventLogEntry = new IntegrationEventLogEntry(@event);
|
||||||
|
|
||||||
|
_integrationEventLogContext.Database.UseTransaction(transaction);
|
||||||
|
_integrationEventLogContext.IntegrationEventLogs.Add(eventLogEntry);
|
||||||
|
|
||||||
|
return _integrationEventLogContext.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task MarkEventAsPublishedAsync(IntegrationEvent @event)
|
||||||
|
{
|
||||||
|
var eventLogEntry = _integrationEventLogContext.IntegrationEventLogs.Single(ie => ie.EventId == @event.Id);
|
||||||
|
eventLogEntry.TimesSent++;
|
||||||
|
eventLogEntry.State = EventStateEnum.Published;
|
||||||
|
|
||||||
|
_integrationEventLogContext.IntegrationEventLogs.Update(eventLogEntry);
|
||||||
|
|
||||||
|
return _integrationEventLogContext.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
8
src/Services/Basket/Basket.API/Dockerfile.nanowin
Normal file
8
src/Services/Basket/Basket.API/Dockerfile.nanowin
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
FROM microsoft/dotnet:1.1-runtime-nanoserver
|
||||||
|
SHELL ["powershell"]
|
||||||
|
ARG source
|
||||||
|
WORKDIR /app
|
||||||
|
RUN set-itemproperty -path 'HKLM:\SYSTEM\CurrentControlSet\Services\Dnscache\Parameters' -Name ServerPriorityTimeLimit -Value 0 -Type DWord
|
||||||
|
EXPOSE 80
|
||||||
|
COPY ${source:-obj/Docker/publish} .
|
||||||
|
ENTRYPOINT ["dotnet", "Basket.API.dll"]
|
@ -0,0 +1,18 @@
|
|||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Basket.API.Infrastructure.ActionResults
|
||||||
|
{
|
||||||
|
public class InternalServerErrorObjectResult : ObjectResult
|
||||||
|
{
|
||||||
|
public InternalServerErrorObjectResult(object error)
|
||||||
|
: base(error)
|
||||||
|
{
|
||||||
|
StatusCode = StatusCodes.Status500InternalServerError;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Basket.API.Infrastructure.Exceptions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Exception type for app exceptions
|
||||||
|
/// </summary>
|
||||||
|
public class BasketDomainException : Exception
|
||||||
|
{
|
||||||
|
public BasketDomainException()
|
||||||
|
{ }
|
||||||
|
|
||||||
|
public BasketDomainException(string message)
|
||||||
|
: base(message)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
public BasketDomainException(string message, Exception innerException)
|
||||||
|
: base(message, innerException)
|
||||||
|
{ }
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,67 @@
|
|||||||
|
using Basket.API.Infrastructure.ActionResults;
|
||||||
|
using Basket.API.Infrastructure.Exceptions;
|
||||||
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.AspNetCore.Mvc.Filters;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Basket.API.Infrastructure.Filters
|
||||||
|
{
|
||||||
|
public class HttpGlobalExceptionFilter : IExceptionFilter
|
||||||
|
{
|
||||||
|
private readonly IHostingEnvironment env;
|
||||||
|
private readonly ILogger<HttpGlobalExceptionFilter> logger;
|
||||||
|
|
||||||
|
public HttpGlobalExceptionFilter(IHostingEnvironment env, ILogger<HttpGlobalExceptionFilter> logger)
|
||||||
|
{
|
||||||
|
this.env = env;
|
||||||
|
this.logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnException(ExceptionContext context)
|
||||||
|
{
|
||||||
|
logger.LogError(new EventId(context.Exception.HResult),
|
||||||
|
context.Exception,
|
||||||
|
context.Exception.Message);
|
||||||
|
|
||||||
|
if (context.Exception.GetType() == typeof(BasketDomainException))
|
||||||
|
{
|
||||||
|
var json = new JsonErrorResponse
|
||||||
|
{
|
||||||
|
Messages = new[] { context.Exception.Message }
|
||||||
|
};
|
||||||
|
|
||||||
|
context.Result = new BadRequestObjectResult(json);
|
||||||
|
context.HttpContext.Response.StatusCode = (int)HttpStatusCode.BadRequest;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var json = new JsonErrorResponse
|
||||||
|
{
|
||||||
|
Messages = new[] { "An error ocurr.Try it again." }
|
||||||
|
};
|
||||||
|
|
||||||
|
if (env.IsDevelopment())
|
||||||
|
{
|
||||||
|
json.DeveloperMeesage = context.Exception;
|
||||||
|
}
|
||||||
|
|
||||||
|
context.Result = new InternalServerErrorObjectResult(json);
|
||||||
|
context.HttpContext.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
|
||||||
|
}
|
||||||
|
context.ExceptionHandled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class JsonErrorResponse
|
||||||
|
{
|
||||||
|
public string[] Messages { get; set; }
|
||||||
|
|
||||||
|
public object DeveloperMeesage { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -20,18 +20,18 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.IntegrationEvents.Even
|
|||||||
foreach (var id in userIds)
|
foreach (var id in userIds)
|
||||||
{
|
{
|
||||||
var basket = await _repository.GetBasket(id);
|
var basket = await _repository.GetBasket(id);
|
||||||
await UpdateBasket(@event.ProductId, @event.NewPrice, basket);
|
await UpdatePriceInBasketItems(@event.ProductId, @event.NewPrice, @event.OldPrice, basket);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task UpdateBasket(int productId, decimal newPrice, CustomerBasket basket)
|
private async Task UpdatePriceInBasketItems(int productId, decimal newPrice, decimal oldPrice, CustomerBasket basket)
|
||||||
{
|
{
|
||||||
var itemsToUpdate = basket?.Items?.Where(x => int.Parse(x.ProductId) == productId).ToList();
|
var itemsToUpdate = basket?.Items?.Where(x => int.Parse(x.ProductId) == productId).ToList();
|
||||||
if (itemsToUpdate != null)
|
if (itemsToUpdate != null)
|
||||||
{
|
{
|
||||||
foreach (var item in itemsToUpdate)
|
foreach (var item in itemsToUpdate)
|
||||||
{
|
{
|
||||||
if(item.UnitPrice != newPrice)
|
if(item.UnitPrice == oldPrice)
|
||||||
{
|
{
|
||||||
var originalPrice = item.UnitPrice;
|
var originalPrice = item.UnitPrice;
|
||||||
item.UnitPrice = newPrice;
|
item.UnitPrice = newPrice;
|
||||||
@ -39,7 +39,7 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.IntegrationEvents.Even
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
await _repository.UpdateBasket(basket);
|
await _repository.UpdateBasket(basket);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@ using Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ;
|
|||||||
using System;
|
using System;
|
||||||
using Microsoft.Extensions.HealthChecks;
|
using Microsoft.Extensions.HealthChecks;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Basket.API.Infrastructure.Filters;
|
||||||
|
|
||||||
namespace Microsoft.eShopOnContainers.Services.Basket.API
|
namespace Microsoft.eShopOnContainers.Services.Basket.API
|
||||||
{
|
{
|
||||||
@ -43,7 +44,11 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Add framework services.
|
// Add framework services.
|
||||||
services.AddMvc();
|
services.AddMvc(options =>
|
||||||
|
{
|
||||||
|
options.Filters.Add(typeof(HttpGlobalExceptionFilter));
|
||||||
|
}).AddControllersAsServices();
|
||||||
|
|
||||||
services.Configure<BasketSettings>(Configuration);
|
services.Configure<BasketSettings>(Configuration);
|
||||||
|
|
||||||
//By connecting here we are making sure that our service
|
//By connecting here we are making sure that our service
|
||||||
|
@ -61,6 +61,7 @@
|
|||||||
<ProjectReference Include="..\..\..\BuildingBlocks\HealthChecks\src\Microsoft.AspNetCore.HealthChecks\Microsoft.AspNetCore.HealthChecks.csproj" />
|
<ProjectReference Include="..\..\..\BuildingBlocks\HealthChecks\src\Microsoft.AspNetCore.HealthChecks\Microsoft.AspNetCore.HealthChecks.csproj" />
|
||||||
<ProjectReference Include="..\..\..\BuildingBlocks\HealthChecks\src\Microsoft.Extensions.HealthChecks.Data\Microsoft.Extensions.HealthChecks.Data.csproj" />
|
<ProjectReference Include="..\..\..\BuildingBlocks\HealthChecks\src\Microsoft.Extensions.HealthChecks.Data\Microsoft.Extensions.HealthChecks.Data.csproj" />
|
||||||
<ProjectReference Include="..\..\..\BuildingBlocks\HealthChecks\src\Microsoft.Extensions.HealthChecks\Microsoft.Extensions.HealthChecks.csproj" />
|
<ProjectReference Include="..\..\..\BuildingBlocks\HealthChecks\src\Microsoft.Extensions.HealthChecks\Microsoft.Extensions.HealthChecks.csproj" />
|
||||||
|
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\IntegrationEventLogEF\IntegrationEventLogEF.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -1,43 +1,51 @@
|
|||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
|
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
|
||||||
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events.IntegrationEventLog;
|
using Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF.Services;
|
||||||
using Microsoft.eShopOnContainers.Services.Catalog.API.Infrastructure;
|
using Microsoft.eShopOnContainers.Services.Catalog.API.Infrastructure;
|
||||||
using Microsoft.eShopOnContainers.Services.Catalog.API.IntegrationEvents.Events;
|
using Microsoft.eShopOnContainers.Services.Catalog.API.IntegrationEvents.Events;
|
||||||
using Microsoft.eShopOnContainers.Services.Catalog.API.Model;
|
using Microsoft.eShopOnContainers.Services.Catalog.API.Model;
|
||||||
using Microsoft.eShopOnContainers.Services.Catalog.API.ViewModel;
|
using Microsoft.eShopOnContainers.Services.Catalog.API.ViewModel;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Data.Common;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events;
|
||||||
|
|
||||||
namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers
|
namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers
|
||||||
{
|
{
|
||||||
[Route("api/v1/[controller]")]
|
[Route("api/v1/[controller]")]
|
||||||
public class CatalogController : ControllerBase
|
public class CatalogController : ControllerBase
|
||||||
{
|
{
|
||||||
private readonly CatalogContext _context;
|
private readonly CatalogContext _catalogContext;
|
||||||
private readonly IOptionsSnapshot<Settings> _settings;
|
private readonly IOptionsSnapshot<Settings> _settings;
|
||||||
private readonly IEventBus _eventBus;
|
private readonly IEventBus _eventBus;
|
||||||
|
private readonly Func<DbConnection, IIntegrationEventLogService> _integrationEventLogServiceFactory;
|
||||||
|
|
||||||
public CatalogController(CatalogContext context, IOptionsSnapshot<Settings> settings, IEventBus eventBus)
|
public CatalogController(CatalogContext Context, IOptionsSnapshot<Settings> settings, IEventBus eventBus, Func<DbConnection, IIntegrationEventLogService> integrationEventLogServiceFactory)
|
||||||
{
|
{
|
||||||
_context = context;
|
_catalogContext = Context;
|
||||||
_settings = settings;
|
_settings = settings;
|
||||||
_eventBus = eventBus;
|
_eventBus = eventBus;
|
||||||
|
_integrationEventLogServiceFactory = integrationEventLogServiceFactory;
|
||||||
|
|
||||||
((DbContext)context).ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
|
((DbContext)Context).ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
|
||||||
}
|
}
|
||||||
|
|
||||||
// GET api/v1/[controller]/items[?pageSize=3&pageIndex=10]
|
// GET api/v1/[controller]/items[?pageSize=3&pageIndex=10]
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
[Route("[action]")]
|
[Route("[action]")]
|
||||||
public async Task<IActionResult> Items([FromQuery]int pageSize = 10, [FromQuery]int pageIndex = 0)
|
public async Task<IActionResult> Items([FromQuery]int pageSize = 10, [FromQuery]int pageIndex = 0)
|
||||||
|
|
||||||
{
|
{
|
||||||
var totalItems = await _context.CatalogItems
|
var totalItems = await _catalogContext.CatalogItems
|
||||||
.LongCountAsync();
|
.LongCountAsync();
|
||||||
|
|
||||||
var itemsOnPage = await _context.CatalogItems
|
var itemsOnPage = await _catalogContext.CatalogItems
|
||||||
.OrderBy(c=>c.Name)
|
.OrderBy(c=>c.Name)
|
||||||
.Skip(pageSize * pageIndex)
|
.Skip(pageSize * pageIndex)
|
||||||
.Take(pageSize)
|
.Take(pageSize)
|
||||||
@ -57,11 +65,11 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers
|
|||||||
public async Task<IActionResult> Items(string name, [FromQuery]int pageSize = 10, [FromQuery]int pageIndex = 0)
|
public async Task<IActionResult> Items(string name, [FromQuery]int pageSize = 10, [FromQuery]int pageIndex = 0)
|
||||||
{
|
{
|
||||||
|
|
||||||
var totalItems = await _context.CatalogItems
|
var totalItems = await _catalogContext.CatalogItems
|
||||||
.Where(c => c.Name.StartsWith(name))
|
.Where(c => c.Name.StartsWith(name))
|
||||||
.LongCountAsync();
|
.LongCountAsync();
|
||||||
|
|
||||||
var itemsOnPage = await _context.CatalogItems
|
var itemsOnPage = await _catalogContext.CatalogItems
|
||||||
.Where(c => c.Name.StartsWith(name))
|
.Where(c => c.Name.StartsWith(name))
|
||||||
.Skip(pageSize * pageIndex)
|
.Skip(pageSize * pageIndex)
|
||||||
.Take(pageSize)
|
.Take(pageSize)
|
||||||
@ -80,7 +88,7 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers
|
|||||||
[Route("[action]/type/{catalogTypeId}/brand/{catalogBrandId}")]
|
[Route("[action]/type/{catalogTypeId}/brand/{catalogBrandId}")]
|
||||||
public async Task<IActionResult> Items(int? catalogTypeId, int? catalogBrandId, [FromQuery]int pageSize = 10, [FromQuery]int pageIndex = 0)
|
public async Task<IActionResult> Items(int? catalogTypeId, int? catalogBrandId, [FromQuery]int pageSize = 10, [FromQuery]int pageIndex = 0)
|
||||||
{
|
{
|
||||||
var root = (IQueryable<CatalogItem>)_context.CatalogItems;
|
var root = (IQueryable<CatalogItem>)_catalogContext.CatalogItems;
|
||||||
|
|
||||||
if (catalogTypeId.HasValue)
|
if (catalogTypeId.HasValue)
|
||||||
{
|
{
|
||||||
@ -113,7 +121,7 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers
|
|||||||
[Route("[action]")]
|
[Route("[action]")]
|
||||||
public async Task<IActionResult> CatalogTypes()
|
public async Task<IActionResult> CatalogTypes()
|
||||||
{
|
{
|
||||||
var items = await _context.CatalogTypes
|
var items = await _catalogContext.CatalogTypes
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
|
|
||||||
return Ok(items);
|
return Ok(items);
|
||||||
@ -124,43 +132,64 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers
|
|||||||
[Route("[action]")]
|
[Route("[action]")]
|
||||||
public async Task<IActionResult> CatalogBrands()
|
public async Task<IActionResult> CatalogBrands()
|
||||||
{
|
{
|
||||||
var items = await _context.CatalogBrands
|
var items = await _catalogContext.CatalogBrands
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
|
|
||||||
return Ok(items);
|
return Ok(items);
|
||||||
}
|
}
|
||||||
|
|
||||||
//POST api/v1/[controller]/edit
|
//POST api/v1/[controller]/update
|
||||||
[Route("edit")]
|
[Route("update")]
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
public async Task<IActionResult> EditProduct([FromBody]CatalogItem product)
|
public async Task<IActionResult> UpdateProduct([FromBody]CatalogItem productToUpdate)
|
||||||
{
|
{
|
||||||
var item = await _context.CatalogItems.SingleOrDefaultAsync(i => i.Id == product.Id);
|
var catalogItem = await _catalogContext.CatalogItems.SingleOrDefaultAsync(i => i.Id == productToUpdate.Id);
|
||||||
|
if (catalogItem == null) return NotFound();
|
||||||
|
|
||||||
if (item == null)
|
bool raiseProductPriceChangedEvent = false;
|
||||||
|
IntegrationEvent priceChangedEvent = null;
|
||||||
|
|
||||||
|
if (catalogItem.Price != productToUpdate.Price) raiseProductPriceChangedEvent = true;
|
||||||
|
|
||||||
|
if (raiseProductPriceChangedEvent) // Create event if price has changed
|
||||||
{
|
{
|
||||||
return NotFound();
|
var oldPrice = catalogItem.Price;
|
||||||
|
priceChangedEvent = new ProductPriceChangedIntegrationEvent(catalogItem.Id, productToUpdate.Price, oldPrice);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item.Price != product.Price)
|
//Update current product
|
||||||
|
catalogItem = productToUpdate;
|
||||||
|
|
||||||
|
//Use of an EF Core resiliency strategy when using multiple DbContexts within an explicit BeginTransaction():
|
||||||
|
//See: https://docs.microsoft.com/en-us/ef/core/miscellaneous/connection-resiliency
|
||||||
|
var strategy = _catalogContext.Database.CreateExecutionStrategy();
|
||||||
|
var eventLogService = _integrationEventLogServiceFactory(_catalogContext.Database.GetDbConnection());
|
||||||
|
await strategy.ExecuteAsync(async () =>
|
||||||
{
|
{
|
||||||
var oldPrice = item.Price;
|
// Achieving atomicity between original Catalog database operation and the IntegrationEventLog thanks to a local transaction
|
||||||
item.Price = product.Price;
|
using (var transaction = _catalogContext.Database.BeginTransaction())
|
||||||
_context.CatalogItems.Update(item);
|
{
|
||||||
|
_catalogContext.CatalogItems.Update(catalogItem);
|
||||||
|
await _catalogContext.SaveChangesAsync();
|
||||||
|
|
||||||
var @event = new ProductPriceChangedIntegrationEvent(item.Id, item.Price, oldPrice);
|
//Save to EventLog only if product price changed
|
||||||
var eventLogEntry = new IntegrationEventLogEntry(@event);
|
if (raiseProductPriceChangedEvent)
|
||||||
_context.IntegrationEventLog.Add(eventLogEntry);
|
{
|
||||||
|
|
||||||
await _context.SaveChangesAsync();
|
await eventLogService.SaveEventAsync(priceChangedEvent, _catalogContext.Database.CurrentTransaction.GetDbTransaction());
|
||||||
|
}
|
||||||
_eventBus.Publish(@event);
|
|
||||||
|
transaction.Commit();
|
||||||
eventLogEntry.TimesSent++;
|
}
|
||||||
eventLogEntry.State = EventStateEnum.Published;
|
});
|
||||||
_context.IntegrationEventLog.Update(eventLogEntry);
|
|
||||||
await _context.SaveChangesAsync();
|
|
||||||
}
|
//Publish to Event Bus only if product price changed
|
||||||
|
if (raiseProductPriceChangedEvent)
|
||||||
|
{
|
||||||
|
_eventBus.Publish(priceChangedEvent);
|
||||||
|
await eventLogService.MarkEventAsPublishedAsync(priceChangedEvent);
|
||||||
|
}
|
||||||
|
|
||||||
return Ok();
|
return Ok();
|
||||||
}
|
}
|
||||||
@ -170,7 +199,7 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers
|
|||||||
[HttpPost]
|
[HttpPost]
|
||||||
public async Task<IActionResult> CreateProduct([FromBody]CatalogItem product)
|
public async Task<IActionResult> CreateProduct([FromBody]CatalogItem product)
|
||||||
{
|
{
|
||||||
_context.CatalogItems.Add(
|
_catalogContext.CatalogItems.Add(
|
||||||
new CatalogItem
|
new CatalogItem
|
||||||
{
|
{
|
||||||
CatalogBrandId = product.CatalogBrandId,
|
CatalogBrandId = product.CatalogBrandId,
|
||||||
@ -181,7 +210,7 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers
|
|||||||
Price = product.Price
|
Price = product.Price
|
||||||
});
|
});
|
||||||
|
|
||||||
await _context.SaveChangesAsync();
|
await _catalogContext.SaveChangesAsync();
|
||||||
|
|
||||||
return Ok();
|
return Ok();
|
||||||
}
|
}
|
||||||
@ -191,15 +220,15 @@ namespace Microsoft.eShopOnContainers.Services.Catalog.API.Controllers
|
|||||||
[HttpDelete]
|
[HttpDelete]
|
||||||
public async Task<IActionResult> DeleteProduct(int id)
|
public async Task<IActionResult> DeleteProduct(int id)
|
||||||
{
|
{
|
||||||
var product = _context.CatalogItems.SingleOrDefault(x => x.Id == id);
|
var product = _catalogContext.CatalogItems.SingleOrDefault(x => x.Id == id);
|
||||||
|
|
||||||
if (product == null)
|
if (product == null)
|
||||||
{
|
{
|
||||||
return NotFound();
|
return NotFound();
|
||||||
}
|
}
|
||||||
|
|
||||||
_context.CatalogItems.Remove(product);
|
_catalogContext.CatalogItems.Remove(product);
|
||||||
await _context.SaveChangesAsync();
|
await _catalogContext.SaveChangesAsync();
|
||||||
|
|
||||||
return Ok();
|
return Ok();
|
||||||
}
|
}
|
||||||
|
8
src/Services/Catalog/Catalog.API/Dockerfile.nanowin
Normal file
8
src/Services/Catalog/Catalog.API/Dockerfile.nanowin
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
FROM microsoft/dotnet:1.1-runtime-nanoserver
|
||||||
|
SHELL ["powershell"]
|
||||||
|
ARG source
|
||||||
|
WORKDIR /app
|
||||||
|
RUN set-itemproperty -path 'HKLM:\SYSTEM\CurrentControlSet\Services\Dnscache\Parameters' -Name ServerPriorityTimeLimit -Value 0 -Type DWord
|
||||||
|
EXPOSE 80
|
||||||
|
COPY ${source:-obj/Docker/publish} .
|
||||||
|
ENTRYPOINT ["dotnet", "Catalog.API.dll"]
|
@ -0,0 +1,18 @@
|
|||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Catalog.API.Infrastructure.ActionResults
|
||||||
|
{
|
||||||
|
public class InternalServerErrorObjectResult : ObjectResult
|
||||||
|
{
|
||||||
|
public InternalServerErrorObjectResult(object error)
|
||||||
|
: base(error)
|
||||||
|
{
|
||||||
|
StatusCode = StatusCodes.Status500InternalServerError;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -3,24 +3,24 @@
|
|||||||
using EntityFrameworkCore.Metadata.Builders;
|
using EntityFrameworkCore.Metadata.Builders;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Model;
|
using Model;
|
||||||
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events.IntegrationEventLog;
|
using Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF;
|
||||||
|
|
||||||
public class CatalogContext : DbContext
|
public class CatalogContext : DbContext
|
||||||
{
|
{
|
||||||
public CatalogContext(DbContextOptions options) : base(options)
|
public CatalogContext(DbContextOptions<CatalogContext> options) : base(options)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
public DbSet<CatalogItem> CatalogItems { get; set; }
|
public DbSet<CatalogItem> CatalogItems { get; set; }
|
||||||
public DbSet<CatalogBrand> CatalogBrands { get; set; }
|
public DbSet<CatalogBrand> CatalogBrands { get; set; }
|
||||||
public DbSet<CatalogType> CatalogTypes { get; set; }
|
public DbSet<CatalogType> CatalogTypes { get; set; }
|
||||||
public DbSet<IntegrationEventLogEntry> IntegrationEventLog { get; set; }
|
//public DbSet<IntegrationEventLogEntry> IntegrationEventLog { get; set; }
|
||||||
|
|
||||||
protected override void OnModelCreating(ModelBuilder builder)
|
protected override void OnModelCreating(ModelBuilder builder)
|
||||||
{
|
{
|
||||||
builder.Entity<CatalogBrand>(ConfigureCatalogBrand);
|
builder.Entity<CatalogBrand>(ConfigureCatalogBrand);
|
||||||
builder.Entity<CatalogType>(ConfigureCatalogType);
|
builder.Entity<CatalogType>(ConfigureCatalogType);
|
||||||
builder.Entity<CatalogItem>(ConfigureCatalogItem);
|
builder.Entity<CatalogItem>(ConfigureCatalogItem);
|
||||||
builder.Entity<IntegrationEventLogEntry>(ConfigureIntegrationEventLogEntry);
|
//builder.Entity<IntegrationEventLogEntry>(ConfigureIntegrationEventLogEntry);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConfigureCatalogItem(EntityTypeBuilder<CatalogItem> builder)
|
void ConfigureCatalogItem(EntityTypeBuilder<CatalogItem> builder)
|
||||||
@ -80,30 +80,30 @@
|
|||||||
.HasMaxLength(100);
|
.HasMaxLength(100);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConfigureIntegrationEventLogEntry(EntityTypeBuilder<IntegrationEventLogEntry> builder)
|
//void ConfigureIntegrationEventLogEntry(EntityTypeBuilder<IntegrationEventLogEntry> builder)
|
||||||
{
|
//{
|
||||||
builder.ToTable("IntegrationEventLog");
|
// builder.ToTable("IntegrationEventLog");
|
||||||
|
|
||||||
builder.HasKey(e => e.EventId);
|
// builder.HasKey(e => e.EventId);
|
||||||
|
|
||||||
builder.Property(e => e.EventId)
|
// builder.Property(e => e.EventId)
|
||||||
.IsRequired();
|
// .IsRequired();
|
||||||
|
|
||||||
builder.Property(e => e.Content)
|
// builder.Property(e => e.Content)
|
||||||
.IsRequired();
|
// .IsRequired();
|
||||||
|
|
||||||
builder.Property(e => e.CreationTime)
|
// builder.Property(e => e.CreationTime)
|
||||||
.IsRequired();
|
// .IsRequired();
|
||||||
|
|
||||||
builder.Property(e => e.State)
|
// builder.Property(e => e.State)
|
||||||
.IsRequired();
|
// .IsRequired();
|
||||||
|
|
||||||
builder.Property(e => e.TimesSent)
|
// builder.Property(e => e.TimesSent)
|
||||||
.IsRequired();
|
// .IsRequired();
|
||||||
|
|
||||||
builder.Property(e => e.EventTypeName)
|
// builder.Property(e => e.EventTypeName)
|
||||||
.IsRequired();
|
// .IsRequired();
|
||||||
|
|
||||||
}
|
//}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -84,14 +84,14 @@
|
|||||||
{
|
{
|
||||||
return new List<CatalogItem>()
|
return new List<CatalogItem>()
|
||||||
{
|
{
|
||||||
new CatalogItem() { CatalogTypeId=2,CatalogBrandId=2, Description = ".NET Bot Black Sweatshirt", Name = ".NET Bot Black Sweatshirt", Price = 19.5M, PictureUri = "http://externalcatalogbaseurltobereplaced/api/v1/pic/1" },
|
new CatalogItem() { CatalogTypeId=2,CatalogBrandId=2, Description = ".NET Bot Black Hoodie", Name = ".NET Bot Black Hoodie", Price = 19.5M, PictureUri = "http://externalcatalogbaseurltobereplaced/api/v1/pic/1" },
|
||||||
new CatalogItem() { CatalogTypeId=1,CatalogBrandId=2, Description = ".NET Black & White Mug", Name = ".NET Black & White Mug", Price= 8.50M, PictureUri = "http://externalcatalogbaseurltobereplaced/api/v1/pic/2" },
|
new CatalogItem() { CatalogTypeId=1,CatalogBrandId=2, Description = ".NET Black & White Mug", Name = ".NET Black & White Mug", Price= 8.50M, PictureUri = "http://externalcatalogbaseurltobereplaced/api/v1/pic/2" },
|
||||||
new CatalogItem() { CatalogTypeId=2,CatalogBrandId=5, Description = "Prism White T-Shirt", Name = "Prism White T-Shirt", Price = 12, PictureUri = "http://externalcatalogbaseurltobereplaced/api/v1/pic/3" },
|
new CatalogItem() { CatalogTypeId=2,CatalogBrandId=5, Description = "Prism White T-Shirt", Name = "Prism White T-Shirt", Price = 12, PictureUri = "http://externalcatalogbaseurltobereplaced/api/v1/pic/3" },
|
||||||
new CatalogItem() { CatalogTypeId=2,CatalogBrandId=2, Description = ".NET Foundation Sweatshirt", Name = ".NET Foundation Sweatshirt", Price = 12, PictureUri = "http://externalcatalogbaseurltobereplaced/api/v1/pic/4" },
|
new CatalogItem() { CatalogTypeId=2,CatalogBrandId=2, Description = ".NET Foundation T-shirt", Name = ".NET Foundation T-shirt", Price = 12, PictureUri = "http://externalcatalogbaseurltobereplaced/api/v1/pic/4" },
|
||||||
new CatalogItem() { CatalogTypeId=3,CatalogBrandId=5, Description = "Roslyn Red Sheet", Name = "Roslyn Red Sheet", Price = 8.5M, PictureUri = "http://externalcatalogbaseurltobereplaced/api/v1/pic/5" },
|
new CatalogItem() { CatalogTypeId=3,CatalogBrandId=5, Description = "Roslyn Red Sheet", Name = "Roslyn Red Sheet", Price = 8.5M, PictureUri = "http://externalcatalogbaseurltobereplaced/api/v1/pic/5" },
|
||||||
new CatalogItem() { CatalogTypeId=2,CatalogBrandId=2, Description = ".NET Blue Sweatshirt", Name = ".NET Blue Sweatshirt", Price = 12, PictureUri = "http://externalcatalogbaseurltobereplaced/api/v1/pic/6" },
|
new CatalogItem() { CatalogTypeId=2,CatalogBrandId=2, Description = ".NET Blue Hoodie", Name = ".NET Blue Hoodie", Price = 12, PictureUri = "http://externalcatalogbaseurltobereplaced/api/v1/pic/6" },
|
||||||
new CatalogItem() { CatalogTypeId=2,CatalogBrandId=5, Description = "Roslyn Red T-Shirt", Name = "Roslyn Red T-Shirt", Price = 12, PictureUri = "http://externalcatalogbaseurltobereplaced/api/v1/pic/7" },
|
new CatalogItem() { CatalogTypeId=2,CatalogBrandId=5, Description = "Roslyn Red T-Shirt", Name = "Roslyn Red T-Shirt", Price = 12, PictureUri = "http://externalcatalogbaseurltobereplaced/api/v1/pic/7" },
|
||||||
new CatalogItem() { CatalogTypeId=2,CatalogBrandId=5, Description = "Kudu Purple Sweatshirt", Name = "Kudu Purple Sweatshirt", Price = 8.5M, PictureUri = "http://externalcatalogbaseurltobereplaced/api/v1/pic/8" },
|
new CatalogItem() { CatalogTypeId=2,CatalogBrandId=5, Description = "Kudu Purple Hoodie", Name = "Kudu Purple Hoodie", Price = 8.5M, PictureUri = "http://externalcatalogbaseurltobereplaced/api/v1/pic/8" },
|
||||||
new CatalogItem() { CatalogTypeId=1,CatalogBrandId=5, Description = "Cup<T> White Mug", Name = "Cup<T> White Mug", Price = 12, PictureUri = "http://externalcatalogbaseurltobereplaced/api/v1/pic/9" },
|
new CatalogItem() { CatalogTypeId=1,CatalogBrandId=5, Description = "Cup<T> White Mug", Name = "Cup<T> White Mug", Price = 12, PictureUri = "http://externalcatalogbaseurltobereplaced/api/v1/pic/9" },
|
||||||
new CatalogItem() { CatalogTypeId=3,CatalogBrandId=2, Description = ".NET Foundation Sheet", Name = ".NET Foundation Sheet", Price = 12, PictureUri = "http://externalcatalogbaseurltobereplaced/api/v1/pic/10" },
|
new CatalogItem() { CatalogTypeId=3,CatalogBrandId=2, Description = ".NET Foundation Sheet", Name = ".NET Foundation Sheet", Price = 12, PictureUri = "http://externalcatalogbaseurltobereplaced/api/v1/pic/10" },
|
||||||
new CatalogItem() { CatalogTypeId=3,CatalogBrandId=2, Description = "Cup<T> Sheet", Name = "Cup<T> Sheet", Price = 8.5M, PictureUri = "http://externalcatalogbaseurltobereplaced/api/v1/pic/11" },
|
new CatalogItem() { CatalogTypeId=3,CatalogBrandId=2, Description = "Cup<T> Sheet", Name = "Cup<T> Sheet", Price = 8.5M, PictureUri = "http://externalcatalogbaseurltobereplaced/api/v1/pic/11" },
|
||||||
|
@ -0,0 +1,99 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Metadata;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.eShopOnContainers.Services.Catalog.API.Infrastructure;
|
||||||
|
|
||||||
|
namespace Catalog.API.Infrastructure.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(CatalogContext))]
|
||||||
|
[Migration("20170322124244_RemoveIntegrationEventLogs")]
|
||||||
|
partial class RemoveIntegrationEventLogs
|
||||||
|
{
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
modelBuilder
|
||||||
|
.HasAnnotation("ProductVersion", "1.1.1")
|
||||||
|
.HasAnnotation("SqlServer:Sequence:.catalog_brand_hilo", "'catalog_brand_hilo', '', '1', '10', '', '', 'Int64', 'False'")
|
||||||
|
.HasAnnotation("SqlServer:Sequence:.catalog_hilo", "'catalog_hilo', '', '1', '10', '', '', 'Int64', 'False'")
|
||||||
|
.HasAnnotation("SqlServer:Sequence:.catalog_type_hilo", "'catalog_type_hilo', '', '1', '10', '', '', 'Int64', 'False'")
|
||||||
|
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Catalog.API.Model.CatalogBrand", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasAnnotation("SqlServer:HiLoSequenceName", "catalog_brand_hilo")
|
||||||
|
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.SequenceHiLo);
|
||||||
|
|
||||||
|
b.Property<string>("Brand")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(100);
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("CatalogBrand");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Catalog.API.Model.CatalogItem", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasAnnotation("SqlServer:HiLoSequenceName", "catalog_hilo")
|
||||||
|
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.SequenceHiLo);
|
||||||
|
|
||||||
|
b.Property<int>("CatalogBrandId");
|
||||||
|
|
||||||
|
b.Property<int>("CatalogTypeId");
|
||||||
|
|
||||||
|
b.Property<string>("Description");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(50);
|
||||||
|
|
||||||
|
b.Property<string>("PictureUri");
|
||||||
|
|
||||||
|
b.Property<decimal>("Price");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("CatalogBrandId");
|
||||||
|
|
||||||
|
b.HasIndex("CatalogTypeId");
|
||||||
|
|
||||||
|
b.ToTable("Catalog");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Catalog.API.Model.CatalogType", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasAnnotation("SqlServer:HiLoSequenceName", "catalog_type_hilo")
|
||||||
|
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.SequenceHiLo);
|
||||||
|
|
||||||
|
b.Property<string>("Type")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(100);
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("CatalogType");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Catalog.API.Model.CatalogItem", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Microsoft.eShopOnContainers.Services.Catalog.API.Model.CatalogBrand", "CatalogBrand")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("CatalogBrandId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("Microsoft.eShopOnContainers.Services.Catalog.API.Model.CatalogType", "CatalogType")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("CatalogTypeId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
namespace Catalog.API.Infrastructure.Migrations
|
||||||
|
{
|
||||||
|
public partial class RemoveIntegrationEventLogs : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "IntegrationEventLog");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "IntegrationEventLog",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
EventId = table.Column<Guid>(nullable: false),
|
||||||
|
Content = table.Column<string>(nullable: false),
|
||||||
|
CreationTime = table.Column<DateTime>(nullable: false),
|
||||||
|
EventTypeName = table.Column<string>(nullable: false),
|
||||||
|
State = table.Column<int>(nullable: false),
|
||||||
|
TimesSent = table.Column<int>(nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_IntegrationEventLog", x => x.EventId);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -4,7 +4,6 @@ using Microsoft.EntityFrameworkCore.Infrastructure;
|
|||||||
using Microsoft.EntityFrameworkCore.Metadata;
|
using Microsoft.EntityFrameworkCore.Metadata;
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
using Microsoft.eShopOnContainers.Services.Catalog.API.Infrastructure;
|
using Microsoft.eShopOnContainers.Services.Catalog.API.Infrastructure;
|
||||||
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events;
|
|
||||||
|
|
||||||
namespace Catalog.API.Infrastructure.Migrations
|
namespace Catalog.API.Infrastructure.Migrations
|
||||||
{
|
{
|
||||||
@ -20,28 +19,6 @@ namespace Catalog.API.Infrastructure.Migrations
|
|||||||
.HasAnnotation("SqlServer:Sequence:.catalog_type_hilo", "'catalog_type_hilo', '', '1', '10', '', '', 'Int64', 'False'")
|
.HasAnnotation("SqlServer:Sequence:.catalog_type_hilo", "'catalog_type_hilo', '', '1', '10', '', '', 'Int64', 'False'")
|
||||||
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
|
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
|
||||||
|
|
||||||
modelBuilder.Entity("Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events.IntegrationEventLogEntry", b =>
|
|
||||||
{
|
|
||||||
b.Property<Guid>("EventId")
|
|
||||||
.ValueGeneratedOnAdd();
|
|
||||||
|
|
||||||
b.Property<string>("Content")
|
|
||||||
.IsRequired();
|
|
||||||
|
|
||||||
b.Property<DateTime>("CreationTime");
|
|
||||||
|
|
||||||
b.Property<string>("EventTypeName")
|
|
||||||
.IsRequired();
|
|
||||||
|
|
||||||
b.Property<int>("State");
|
|
||||||
|
|
||||||
b.Property<int>("TimesSent");
|
|
||||||
|
|
||||||
b.HasKey("EventId");
|
|
||||||
|
|
||||||
b.ToTable("IntegrationEventLog");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Catalog.API.Model.CatalogBrand", b =>
|
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Catalog.API.Model.CatalogBrand", b =>
|
||||||
{
|
{
|
||||||
b.Property<int>("Id")
|
b.Property<int>("Id")
|
@ -0,0 +1,24 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Catalog.API.Infrastructure.Exceptions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Exception type for app exceptions
|
||||||
|
/// </summary>
|
||||||
|
public class CatalogDomainException : Exception
|
||||||
|
{
|
||||||
|
public CatalogDomainException()
|
||||||
|
{ }
|
||||||
|
|
||||||
|
public CatalogDomainException(string message)
|
||||||
|
: base(message)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
public CatalogDomainException(string message, Exception innerException)
|
||||||
|
: base(message, innerException)
|
||||||
|
{ }
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,63 @@
|
|||||||
|
using Catalog.API.Infrastructure.ActionResults;
|
||||||
|
using Catalog.API.Infrastructure.Exceptions;
|
||||||
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.AspNetCore.Mvc.Filters;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using System.Net;
|
||||||
|
|
||||||
|
namespace Catalog.API.Infrastructure.Filters
|
||||||
|
{
|
||||||
|
public class HttpGlobalExceptionFilter : IExceptionFilter
|
||||||
|
{
|
||||||
|
private readonly IHostingEnvironment env;
|
||||||
|
private readonly ILogger<HttpGlobalExceptionFilter> logger;
|
||||||
|
|
||||||
|
public HttpGlobalExceptionFilter(IHostingEnvironment env, ILogger<HttpGlobalExceptionFilter> logger)
|
||||||
|
{
|
||||||
|
this.env = env;
|
||||||
|
this.logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnException(ExceptionContext context)
|
||||||
|
{
|
||||||
|
logger.LogError(new EventId(context.Exception.HResult),
|
||||||
|
context.Exception,
|
||||||
|
context.Exception.Message);
|
||||||
|
|
||||||
|
if (context.Exception.GetType() == typeof(CatalogDomainException))
|
||||||
|
{
|
||||||
|
var json = new JsonErrorResponse
|
||||||
|
{
|
||||||
|
Messages = new[] { context.Exception.Message }
|
||||||
|
};
|
||||||
|
|
||||||
|
context.Result = new BadRequestObjectResult(json);
|
||||||
|
context.HttpContext.Response.StatusCode = (int)HttpStatusCode.BadRequest;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var json = new JsonErrorResponse
|
||||||
|
{
|
||||||
|
Messages = new[] { "An error ocurr.Try it again." }
|
||||||
|
};
|
||||||
|
|
||||||
|
if (env.IsDevelopment())
|
||||||
|
{
|
||||||
|
json.DeveloperMeesage = context.Exception;
|
||||||
|
}
|
||||||
|
|
||||||
|
context.Result = new InternalServerErrorObjectResult(json);
|
||||||
|
context.HttpContext.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
|
||||||
|
}
|
||||||
|
context.ExceptionHandled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class JsonErrorResponse
|
||||||
|
{
|
||||||
|
public string[] Messages { get; set; }
|
||||||
|
|
||||||
|
public object DeveloperMeesage { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,43 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Metadata;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF;
|
||||||
|
|
||||||
|
namespace Catalog.API.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(IntegrationEventLogContext))]
|
||||||
|
[Migration("20170322145434_IntegrationEventInitial")]
|
||||||
|
partial class IntegrationEventInitial
|
||||||
|
{
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
modelBuilder
|
||||||
|
.HasAnnotation("ProductVersion", "1.1.1")
|
||||||
|
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF.IntegrationEventLogEntry", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("EventId")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<string>("Content")
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreationTime");
|
||||||
|
|
||||||
|
b.Property<string>("EventTypeName")
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Property<int>("State");
|
||||||
|
|
||||||
|
b.Property<int>("TimesSent");
|
||||||
|
|
||||||
|
b.HasKey("EventId");
|
||||||
|
|
||||||
|
b.ToTable("IntegrationEventLog");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
namespace Catalog.API.Migrations
|
||||||
|
{
|
||||||
|
public partial class IntegrationEventInitial : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "IntegrationEventLog",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
EventId = table.Column<Guid>(nullable: false),
|
||||||
|
Content = table.Column<string>(nullable: false),
|
||||||
|
CreationTime = table.Column<DateTime>(nullable: false),
|
||||||
|
EventTypeName = table.Column<string>(nullable: false),
|
||||||
|
State = table.Column<int>(nullable: false),
|
||||||
|
TimesSent = table.Column<int>(nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_IntegrationEventLog", x => x.EventId);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "IntegrationEventLog");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,42 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Metadata;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF;
|
||||||
|
|
||||||
|
namespace Catalog.API.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(IntegrationEventLogContext))]
|
||||||
|
partial class IntegrationEventLogContextModelSnapshot : ModelSnapshot
|
||||||
|
{
|
||||||
|
protected override void BuildModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
modelBuilder
|
||||||
|
.HasAnnotation("ProductVersion", "1.1.1")
|
||||||
|
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
|
||||||
|
|
||||||
|
modelBuilder.Entity("Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF.IntegrationEventLogEntry", b =>
|
||||||
|
{
|
||||||
|
b.Property<Guid>("EventId")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<string>("Content")
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreationTime");
|
||||||
|
|
||||||
|
b.Property<string>("EventTypeName")
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Property<int>("State");
|
||||||
|
|
||||||
|
b.Property<int>("TimesSent");
|
||||||
|
|
||||||
|
b.HasKey("EventId");
|
||||||
|
|
||||||
|
b.ToTable("IntegrationEventLog");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,17 +1,22 @@
|
|||||||
namespace Microsoft.eShopOnContainers.Services.Catalog.API
|
namespace Microsoft.eShopOnContainers.Services.Catalog.API
|
||||||
{
|
{
|
||||||
|
using global::Catalog.API.Infrastructure.Filters;
|
||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
|
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
|
||||||
using Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ;
|
using Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ;
|
||||||
|
using Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF;
|
||||||
|
using Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF.Services;
|
||||||
using Microsoft.eShopOnContainers.Services.Catalog.API.Infrastructure;
|
using Microsoft.eShopOnContainers.Services.Catalog.API.Infrastructure;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.HealthChecks;
|
using Microsoft.Extensions.HealthChecks;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
|
using System;
|
||||||
|
using System.Data.Common;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
|
||||||
public class Startup
|
public class Startup
|
||||||
@ -37,6 +42,8 @@
|
|||||||
|
|
||||||
public void ConfigureServices(IServiceCollection services)
|
public void ConfigureServices(IServiceCollection services)
|
||||||
{
|
{
|
||||||
|
// Add framework services.
|
||||||
|
services.AddMvc(options =>
|
||||||
|
|
||||||
services.AddHealthChecks(checks =>
|
services.AddHealthChecks(checks =>
|
||||||
{
|
{
|
||||||
@ -45,10 +52,21 @@
|
|||||||
|
|
||||||
services.AddDbContext<CatalogContext>(c =>
|
services.AddDbContext<CatalogContext>(c =>
|
||||||
{
|
{
|
||||||
c.UseSqlServer(Configuration["ConnectionString"]);
|
options.Filters.Add(typeof(HttpGlobalExceptionFilter));
|
||||||
|
}).AddControllersAsServices();
|
||||||
|
|
||||||
|
services.AddDbContext<CatalogContext>(options =>
|
||||||
|
{
|
||||||
|
options.UseSqlServer(Configuration["ConnectionString"],
|
||||||
|
sqlServerOptionsAction: sqlOptions =>
|
||||||
|
{
|
||||||
|
sqlOptions.MigrationsAssembly(typeof(Startup).GetTypeInfo().Assembly.GetName().Name);
|
||||||
|
//Configuring Connection Resiliency: https://docs.microsoft.com/en-us/ef/core/miscellaneous/connection-resiliency
|
||||||
|
sqlOptions.EnableRetryOnFailure(maxRetryCount: 5, maxRetryDelay: TimeSpan.FromSeconds(30), errorNumbersToAdd: null);
|
||||||
|
});
|
||||||
// Changing default behavior when client evaluation occurs to throw.
|
// Changing default behavior when client evaluation occurs to throw.
|
||||||
// Default in EF Core would be to log a warning when client evaluation is performed.
|
// Default in EF Core would be to log a warning when client evaluation is performed.
|
||||||
c.ConfigureWarnings(warnings => warnings.Throw(RelationalEventId.QueryClientEvaluationWarning));
|
options.ConfigureWarnings(warnings => warnings.Throw(RelationalEventId.QueryClientEvaluationWarning));
|
||||||
//Check Client vs. Server evaluation: https://docs.microsoft.com/en-us/ef/core/querying/client-eval
|
//Check Client vs. Server evaluation: https://docs.microsoft.com/en-us/ef/core/querying/client-eval
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -77,22 +95,18 @@
|
|||||||
.AllowCredentials());
|
.AllowCredentials());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
services.AddTransient<Func<DbConnection, IIntegrationEventLogService>>(
|
||||||
|
sp => (DbConnection c) => new IntegrationEventLogService(c));
|
||||||
|
|
||||||
var serviceProvider = services.BuildServiceProvider();
|
var serviceProvider = services.BuildServiceProvider();
|
||||||
var configuration = serviceProvider.GetRequiredService<IOptionsSnapshot<Settings>>().Value;
|
var configuration = serviceProvider.GetRequiredService<IOptionsSnapshot<Settings>>().Value;
|
||||||
services.AddSingleton<IEventBus>(new EventBusRabbitMQ(configuration.EventBusConnection));
|
services.AddSingleton<IEventBus>(new EventBusRabbitMQ(configuration.EventBusConnection));
|
||||||
|
|
||||||
services.AddMvc();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
|
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
|
||||||
{
|
{
|
||||||
//Configure logs
|
//Configure logs
|
||||||
|
|
||||||
if (env.IsDevelopment())
|
|
||||||
{
|
|
||||||
app.UseDeveloperExceptionPage();
|
|
||||||
}
|
|
||||||
|
|
||||||
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
|
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
|
||||||
loggerFactory.AddDebug();
|
loggerFactory.AddDebug();
|
||||||
|
|
||||||
@ -105,9 +119,14 @@
|
|||||||
|
|
||||||
//Seed Data
|
//Seed Data
|
||||||
CatalogContextSeed.SeedAsync(app, loggerFactory)
|
CatalogContextSeed.SeedAsync(app, loggerFactory)
|
||||||
.Wait();
|
.Wait();
|
||||||
|
|
||||||
|
var integrationEventLogContext = new IntegrationEventLogContext(
|
||||||
|
new DbContextOptionsBuilder<IntegrationEventLogContext>()
|
||||||
|
.UseSqlServer(Configuration["ConnectionString"], b => b.MigrationsAssembly("Catalog.API"))
|
||||||
|
.Options);
|
||||||
|
integrationEventLogContext.Database.Migrate();
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
8
src/Services/Identity/Identity.API/Dockerfile.nanowin
Normal file
8
src/Services/Identity/Identity.API/Dockerfile.nanowin
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
FROM microsoft/dotnet:1.1-runtime-nanoserver
|
||||||
|
SHELL ["powershell"]
|
||||||
|
ARG source
|
||||||
|
WORKDIR /app
|
||||||
|
RUN set-itemproperty -path 'HKLM:\SYSTEM\CurrentControlSet\Services\Dnscache\Parameters' -Name ServerPriorityTimeLimit -Value 0 -Type DWord
|
||||||
|
EXPOSE 80
|
||||||
|
COPY ${source:-obj/Docker/publish} .
|
||||||
|
ENTRYPOINT ["dotnet", "Identity.API.dll"]
|
@ -45,6 +45,15 @@
|
|||||||
<p>
|
<p>
|
||||||
<a asp-action="Register" asp-route-returnurl="@ViewData["ReturnUrl"]" class="text">Register as a new user?</a>
|
<a asp-action="Register" asp-route-returnurl="@ViewData["ReturnUrl"]" class="text">Register as a new user?</a>
|
||||||
</p>
|
</p>
|
||||||
|
<p>
|
||||||
|
Note that for demo purposes you don't need to register and can login with these credentials:
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
User: <b>demouser@microsoft.com</b>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Password: <b>Pass@word1</b>
|
||||||
|
</p>
|
||||||
</form>
|
</form>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
using Domain.AggregatesModel.OrderAggregate;
|
using Domain.AggregatesModel.OrderAggregate;
|
||||||
using MediatR;
|
using MediatR;
|
||||||
using Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure.Services;
|
using Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure.Services;
|
||||||
using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Repositories;
|
using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Idempotency;
|
||||||
using System;
|
using System;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
@ -51,11 +51,8 @@
|
|||||||
|
|
||||||
_orderRepository.Add(order);
|
_orderRepository.Add(order);
|
||||||
|
|
||||||
var result = await _orderRepository.UnitOfWork
|
return await _orderRepository.UnitOfWork
|
||||||
.SaveEntitiesAsync();
|
.SaveEntitiesAsync();
|
||||||
|
|
||||||
return result > 0;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,5 @@
|
|||||||
using MediatR;
|
using MediatR;
|
||||||
using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Repositories;
|
using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Idempotency;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands
|
namespace Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands
|
||||||
@ -48,9 +45,9 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands
|
|||||||
return CreateResultForDuplicateRequest();
|
return CreateResultForDuplicateRequest();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
await _requestManager.CreateRequestForCommandAsync<T>(message.Id);
|
|
||||||
var result = await _mediator.SendAsync(message.Command);
|
var result = await _mediator.SendAsync(message.Command);
|
||||||
|
await _requestManager.CreateRequestForCommandAsync<T>(message.Id);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,46 @@
|
|||||||
|
using FluentValidation;
|
||||||
|
using MediatR;
|
||||||
|
using Ordering.Domain.Exceptions;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Ordering.API.Application.Decorators
|
||||||
|
{
|
||||||
|
public class ValidatorDecorator<TRequest, TResponse>
|
||||||
|
: IAsyncRequestHandler<TRequest, TResponse>
|
||||||
|
where TRequest : IAsyncRequest<TResponse>
|
||||||
|
{
|
||||||
|
private readonly IAsyncRequestHandler<TRequest, TResponse> _inner;
|
||||||
|
private readonly IValidator<TRequest>[] _validators;
|
||||||
|
|
||||||
|
|
||||||
|
public ValidatorDecorator(
|
||||||
|
IAsyncRequestHandler<TRequest, TResponse> inner,
|
||||||
|
IValidator<TRequest>[] validators)
|
||||||
|
{
|
||||||
|
_inner = inner;
|
||||||
|
_validators = validators;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<TResponse> Handle(TRequest message)
|
||||||
|
{
|
||||||
|
var failures = _validators
|
||||||
|
.Select(v => v.Validate(message))
|
||||||
|
.SelectMany(result => result.Errors)
|
||||||
|
.Where(error => error != null)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
if (failures.Any())
|
||||||
|
{
|
||||||
|
throw new OrderingDomainException(
|
||||||
|
$"Command Validation Errors for type {typeof(TRequest).Name}", new ValidationException("Validation exception", failures));
|
||||||
|
}
|
||||||
|
|
||||||
|
var response = await _inner.Handle(message);
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,39 @@
|
|||||||
|
using FluentValidation;
|
||||||
|
using MediatR;
|
||||||
|
using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using static Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands.CreateOrderCommand;
|
||||||
|
|
||||||
|
namespace Ordering.API.Application.Validations
|
||||||
|
{
|
||||||
|
public class CreateOrderCommandValidator : AbstractValidator<CreateOrderCommand>
|
||||||
|
{
|
||||||
|
public CreateOrderCommandValidator()
|
||||||
|
{
|
||||||
|
RuleFor(order => order.City).NotEmpty();
|
||||||
|
RuleFor(order => order.Street).NotEmpty();
|
||||||
|
RuleFor(order => order.State).NotEmpty();
|
||||||
|
RuleFor(order => order.Country).NotEmpty();
|
||||||
|
RuleFor(order => order.ZipCode).NotEmpty();
|
||||||
|
RuleFor(order => order.CardNumber).NotEmpty().Length(12, 19);
|
||||||
|
RuleFor(order => order.CardHolderName).NotEmpty();
|
||||||
|
RuleFor(order => order.CardExpiration).NotEmpty().Must(BeValidExpirationDate).WithMessage("Please specify a valid card expiration date");
|
||||||
|
RuleFor(order => order.CardSecurityNumber).NotEmpty().Length(3);
|
||||||
|
RuleFor(order => order.CardTypeId).NotEmpty();
|
||||||
|
RuleFor(order => order.OrderItems).Must(ContainOrderItems).WithMessage("No order items found");
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool BeValidExpirationDate(DateTime dateTime)
|
||||||
|
{
|
||||||
|
return dateTime >= DateTime.UtcNow;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool ContainOrderItems(IEnumerable<OrderItemDTO> orderItems)
|
||||||
|
{
|
||||||
|
return orderItems.Any();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
using FluentValidation;
|
||||||
|
using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Ordering.API.Application.Validations
|
||||||
|
{
|
||||||
|
public class IdentifierCommandValidator : AbstractValidator<IdentifiedCommand<CreateOrderCommand,bool>>
|
||||||
|
{
|
||||||
|
public IdentifierCommandValidator()
|
||||||
|
{
|
||||||
|
RuleFor(customer => customer.Id).NotEmpty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
8
src/Services/Ordering/Ordering.API/Dockerfile.nanowin
Normal file
8
src/Services/Ordering/Ordering.API/Dockerfile.nanowin
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
FROM microsoft/dotnet:1.1-runtime-nanoserver
|
||||||
|
SHELL ["powershell"]
|
||||||
|
ARG source
|
||||||
|
WORKDIR /app
|
||||||
|
RUN set-itemproperty -path 'HKLM:\SYSTEM\CurrentControlSet\Services\Dnscache\Parameters' -Name ServerPriorityTimeLimit -Value 0 -Type DWord
|
||||||
|
EXPOSE 80
|
||||||
|
COPY ${source:-obj/Docker/publish} .
|
||||||
|
ENTRYPOINT ["dotnet", "Ordering.API.dll"]
|
@ -2,6 +2,7 @@
|
|||||||
using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Queries;
|
using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Queries;
|
||||||
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate;
|
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate;
|
||||||
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate;
|
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate;
|
||||||
|
using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Idempotency;
|
||||||
using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Repositories;
|
using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Repositories;
|
||||||
|
|
||||||
namespace Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure.AutofacModules
|
namespace Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure.AutofacModules
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
using Autofac;
|
using Autofac;
|
||||||
using Autofac.Core;
|
using Autofac.Core;
|
||||||
|
using FluentValidation;
|
||||||
using MediatR;
|
using MediatR;
|
||||||
using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands;
|
using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands;
|
||||||
using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Decorators;
|
using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Decorators;
|
||||||
|
using Ordering.API.Application.Decorators;
|
||||||
using Ordering.API.Application.DomainEventHandlers.OrderStartedEvent;
|
using Ordering.API.Application.DomainEventHandlers.OrderStartedEvent;
|
||||||
|
using Ordering.API.Application.Validations;
|
||||||
using Ordering.Domain.Events;
|
using Ordering.Domain.Events;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@ -24,11 +27,17 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure.Autof
|
|||||||
.Where(i => i.IsClosedTypeOf(typeof(IAsyncRequestHandler<,>)))
|
.Where(i => i.IsClosedTypeOf(typeof(IAsyncRequestHandler<,>)))
|
||||||
.Select(i => new KeyedService("IAsyncRequestHandler", i)));
|
.Select(i => new KeyedService("IAsyncRequestHandler", i)));
|
||||||
|
|
||||||
// Register all the Domain Event Handler classes (they implement IAsyncNotificationHandler<>) in assembly holding the Domain Events
|
// Register all the event classes (they implement IAsyncNotificationHandler) in assembly holding the Commands
|
||||||
|
builder.RegisterAssemblyTypes(typeof(ValidateOrAddBuyerAggregateWhenOrderStartedDomainEventHandler).GetTypeInfo().Assembly)
|
||||||
|
.As(o => o.GetInterfaces()
|
||||||
|
.Where(i => i.IsClosedTypeOf(typeof(IAsyncNotificationHandler<>)))
|
||||||
|
.Select(i => new KeyedService("IAsyncNotificationHandler", i)));
|
||||||
|
|
||||||
builder
|
builder
|
||||||
.RegisterAssemblyTypes(typeof(ValidateOrAddBuyerAggregateWhenOrderStartedDomainEventHandler).GetTypeInfo().Assembly)
|
.RegisterAssemblyTypes(typeof(CreateOrderCommandValidator).GetTypeInfo().Assembly)
|
||||||
.Where(t => t.IsClosedTypeOf(typeof(IAsyncNotificationHandler<>)))
|
.Where(t => t.IsClosedTypeOf(typeof(IValidator<>)))
|
||||||
.AsImplementedInterfaces();
|
.AsImplementedInterfaces();
|
||||||
|
|
||||||
|
|
||||||
builder.Register<SingleInstanceFactory>(context =>
|
builder.Register<SingleInstanceFactory>(context =>
|
||||||
{
|
{
|
||||||
@ -44,9 +53,16 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure.Autof
|
|||||||
return t => (IEnumerable<object>)componentContext.Resolve(typeof(IEnumerable<>).MakeGenericType(t));
|
return t => (IEnumerable<object>)componentContext.Resolve(typeof(IEnumerable<>).MakeGenericType(t));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
builder.RegisterGenericDecorator(typeof(LogDecorator<,>),
|
builder.RegisterGenericDecorator(typeof(LogDecorator<,>),
|
||||||
typeof(IAsyncRequestHandler<,>),
|
typeof(IAsyncRequestHandler<,>),
|
||||||
"IAsyncRequestHandler");
|
"IAsyncRequestHandler")
|
||||||
|
.Keyed("handlerDecorator", typeof(IAsyncRequestHandler<,>));
|
||||||
|
|
||||||
|
builder.RegisterGenericDecorator(typeof(ValidatorDecorator<,>),
|
||||||
|
typeof(IAsyncRequestHandler<,>),
|
||||||
|
fromKey: "handlerDecorator");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
namespace Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure.Filters
|
namespace Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure.Filters
|
||||||
{
|
{
|
||||||
using AspNetCore.Mvc;
|
using AspNetCore.Mvc;
|
||||||
|
using global::Ordering.Domain.Exceptions;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
using Microsoft.AspNetCore.Mvc.Filters;
|
using Microsoft.AspNetCore.Mvc.Filters;
|
||||||
using Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure.ActionResults;
|
using Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure.ActionResults;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using System;
|
using System.Net;
|
||||||
|
|
||||||
public class HttpGlobalExceptionFilter : IExceptionFilter
|
public class HttpGlobalExceptionFilter : IExceptionFilter
|
||||||
{
|
{
|
||||||
@ -24,14 +25,17 @@
|
|||||||
context.Exception,
|
context.Exception,
|
||||||
context.Exception.Message);
|
context.Exception.Message);
|
||||||
|
|
||||||
if (context.Exception.GetType() == typeof(ArgumentException)) //TODO:Select a common exception for application like EshopException
|
if (context.Exception.GetType() == typeof(OrderingDomainException))
|
||||||
{
|
{
|
||||||
var json = new JsonErrorResponse
|
var json = new JsonErrorResponse
|
||||||
{
|
{
|
||||||
Messages = new[] { context.Exception.Message }
|
Messages = new[] { context.Exception.Message }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Result asigned to a result object but in destiny the response is empty. This is a known bug of .net core 1.1
|
||||||
|
//It will be fixed in .net core 1.1.2. See https://github.com/aspnet/Mvc/issues/5594 for more information
|
||||||
context.Result = new BadRequestObjectResult(json);
|
context.Result = new BadRequestObjectResult(json);
|
||||||
|
context.HttpContext.Response.StatusCode = (int)HttpStatusCode.BadRequest;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -45,9 +49,12 @@
|
|||||||
json.DeveloperMeesage = context.Exception;
|
json.DeveloperMeesage = context.Exception;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Result asigned to a result object but in destiny the response is empty. This is a known bug of .net core 1.1
|
||||||
|
// It will be fixed in .net core 1.1.2. See https://github.com/aspnet/Mvc/issues/5594 for more information
|
||||||
context.Result = new InternalServerErrorObjectResult(json);
|
context.Result = new InternalServerErrorObjectResult(json);
|
||||||
|
context.HttpContext.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
|
||||||
}
|
}
|
||||||
|
context.ExceptionHandled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private class JsonErrorResponse
|
private class JsonErrorResponse
|
||||||
|
@ -31,6 +31,8 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="FluentValidation.AspNetCore" Version="6.4.0" />
|
||||||
|
<PackageReference Include="FluentValidation.MVC6" Version="6.4.0" />
|
||||||
<PackageReference Include="MediatR.Extensions.Microsoft.DependencyInjection" Version="1.1.0" />
|
<PackageReference Include="MediatR.Extensions.Microsoft.DependencyInjection" Version="1.1.0" />
|
||||||
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="4.0.0" />
|
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="4.0.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="1.1.0" />
|
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="1.1.0" />
|
||||||
|
@ -46,7 +46,7 @@
|
|||||||
// Add framework services.
|
// Add framework services.
|
||||||
services.AddMvc(options =>
|
services.AddMvc(options =>
|
||||||
{
|
{
|
||||||
options.Filters.Add(typeof(HttpGlobalExceptionFilter));
|
options.Filters.Add(typeof(HttpGlobalExceptionFilter));
|
||||||
}).AddControllersAsServices(); //Injecting Controllers themselves thru DI
|
}).AddControllersAsServices(); //Injecting Controllers themselves thru DI
|
||||||
//For further info see: http://docs.autofac.org/en/latest/integration/aspnetcore.html#controllers-as-services
|
//For further info see: http://docs.autofac.org/en/latest/integration/aspnetcore.html#controllers-as-services
|
||||||
|
|
||||||
@ -59,10 +59,14 @@
|
|||||||
services.AddEntityFrameworkSqlServer()
|
services.AddEntityFrameworkSqlServer()
|
||||||
.AddDbContext<OrderingContext>(options =>
|
.AddDbContext<OrderingContext>(options =>
|
||||||
{
|
{
|
||||||
options.UseSqlServer(Configuration["ConnectionString"],
|
options.UseSqlServer(Configuration["ConnectionString"],
|
||||||
sqlop => sqlop.MigrationsAssembly(typeof(Startup).GetTypeInfo().Assembly.GetName().Name));
|
sqlServerOptionsAction: sqlOptions =>
|
||||||
|
{
|
||||||
|
sqlOptions.MigrationsAssembly(typeof(Startup).GetTypeInfo().Assembly.GetName().Name);
|
||||||
|
sqlOptions.EnableRetryOnFailure(maxRetryCount: 5, maxRetryDelay: TimeSpan.FromSeconds(30), errorNumbersToAdd: null);
|
||||||
|
});
|
||||||
},
|
},
|
||||||
ServiceLifetime.Scoped //DbContext is shared across the HTTP request scope (graph of objects started in the HTTP request)
|
ServiceLifetime.Scoped //Showing explicitly that the DbContext is shared across the HTTP request scope (graph of objects started in the HTTP request)
|
||||||
);
|
);
|
||||||
|
|
||||||
services.AddSwaggerGen();
|
services.AddSwaggerGen();
|
||||||
@ -109,12 +113,7 @@
|
|||||||
{
|
{
|
||||||
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
|
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
|
||||||
loggerFactory.AddDebug();
|
loggerFactory.AddDebug();
|
||||||
|
|
||||||
if (env.IsDevelopment())
|
|
||||||
{
|
|
||||||
app.UseDeveloperExceptionPage();
|
|
||||||
}
|
|
||||||
|
|
||||||
app.UseCors("CorsPolicy");
|
app.UseCors("CorsPolicy");
|
||||||
|
|
||||||
app.UseFailingMiddleware();
|
app.UseFailingMiddleware();
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using Microsoft.eShopOnContainers.Services.Ordering.Domain.Seedwork;
|
using Microsoft.eShopOnContainers.Services.Ordering.Domain.Seedwork;
|
||||||
|
using Ordering.Domain.Exceptions;
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate
|
namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate
|
||||||
@ -22,13 +23,13 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.B
|
|||||||
public PaymentMethod(int cardTypeId, string alias, string cardNumber, string securityNumber, string cardHolderName, DateTime expiration)
|
public PaymentMethod(int cardTypeId, string alias, string cardNumber, string securityNumber, string cardHolderName, DateTime expiration)
|
||||||
{
|
{
|
||||||
|
|
||||||
_cardNumber = !string.IsNullOrWhiteSpace(cardNumber) ? cardNumber : throw new ArgumentException(nameof(cardNumber));
|
_cardNumber = !string.IsNullOrWhiteSpace(cardNumber) ? cardNumber : throw new OrderingDomainException(nameof(cardNumber));
|
||||||
_securityNumber = !string.IsNullOrWhiteSpace(securityNumber) ? securityNumber : throw new ArgumentException(nameof(securityNumber));
|
_securityNumber = !string.IsNullOrWhiteSpace(securityNumber) ? securityNumber : throw new OrderingDomainException(nameof(securityNumber));
|
||||||
_cardHolderName = !string.IsNullOrWhiteSpace(cardHolderName) ? cardHolderName : throw new ArgumentException(nameof(cardHolderName));
|
_cardHolderName = !string.IsNullOrWhiteSpace(cardHolderName) ? cardHolderName : throw new OrderingDomainException(nameof(cardHolderName));
|
||||||
|
|
||||||
if (expiration < DateTime.UtcNow)
|
if (expiration < DateTime.UtcNow)
|
||||||
{
|
{
|
||||||
throw new ArgumentException(nameof(expiration));
|
throw new OrderingDomainException(nameof(expiration));
|
||||||
}
|
}
|
||||||
|
|
||||||
_alias = alias;
|
_alias = alias;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using Microsoft.eShopOnContainers.Services.Ordering.Domain.Seedwork;
|
using Microsoft.eShopOnContainers.Services.Ordering.Domain.Seedwork;
|
||||||
|
using Ordering.Domain.Exceptions;
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate
|
namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate
|
||||||
@ -24,12 +25,12 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.O
|
|||||||
{
|
{
|
||||||
if (units <= 0)
|
if (units <= 0)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException("Invalid number of units");
|
throw new OrderingDomainException("Invalid number of units");
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((unitPrice * units) < discount)
|
if ((unitPrice * units) < discount)
|
||||||
{
|
{
|
||||||
throw new ArgumentException("The total of order item is lower than applied discount");
|
throw new OrderingDomainException("The total of order item is lower than applied discount");
|
||||||
}
|
}
|
||||||
|
|
||||||
ProductId = productId;
|
ProductId = productId;
|
||||||
@ -58,7 +59,7 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.O
|
|||||||
{
|
{
|
||||||
if (discount < 0)
|
if (discount < 0)
|
||||||
{
|
{
|
||||||
throw new ArgumentException("Discount is not valid");
|
throw new OrderingDomainException("Discount is not valid");
|
||||||
}
|
}
|
||||||
|
|
||||||
_discount = discount;
|
_discount = discount;
|
||||||
@ -68,7 +69,7 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.O
|
|||||||
{
|
{
|
||||||
if (units < 0)
|
if (units < 0)
|
||||||
{
|
{
|
||||||
throw new ArgumentException("Invalid units");
|
throw new OrderingDomainException("Invalid units");
|
||||||
}
|
}
|
||||||
|
|
||||||
_units += units;
|
_units += units;
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate
|
namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate
|
||||||
{
|
{
|
||||||
|
using global::Ordering.Domain.Exceptions;
|
||||||
using Seedwork;
|
using Seedwork;
|
||||||
using SeedWork;
|
using SeedWork;
|
||||||
using System;
|
using System;
|
||||||
@ -34,7 +35,7 @@
|
|||||||
|
|
||||||
if (state == null)
|
if (state == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentException($"Possible values for OrderStatus: {String.Join(",", List().Select(s => s.Name))}");
|
throw new OrderingDomainException($"Possible values for OrderStatus: {String.Join(",", List().Select(s => s.Name))}");
|
||||||
}
|
}
|
||||||
|
|
||||||
return state;
|
return state;
|
||||||
@ -46,7 +47,7 @@
|
|||||||
|
|
||||||
if (state == null)
|
if (state == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentException($"Possible values for OrderStatus: {String.Join(",", List().Select(s => s.Name))}");
|
throw new OrderingDomainException($"Possible values for OrderStatus: {String.Join(",", List().Select(s => s.Name))}");
|
||||||
}
|
}
|
||||||
|
|
||||||
return state;
|
return state;
|
||||||
|
@ -0,0 +1,23 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Ordering.Domain.Exceptions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Exception type for domain exceptions
|
||||||
|
/// </summary>
|
||||||
|
public class OrderingDomainException : Exception
|
||||||
|
{
|
||||||
|
public OrderingDomainException()
|
||||||
|
{ }
|
||||||
|
|
||||||
|
public OrderingDomainException(string message)
|
||||||
|
: base(message)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
public OrderingDomainException(string message, Exception innerException)
|
||||||
|
: base(message, innerException)
|
||||||
|
{ }
|
||||||
|
}
|
||||||
|
}
|
@ -7,6 +7,6 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.Seedwork
|
|||||||
public interface IUnitOfWork : IDisposable
|
public interface IUnitOfWork : IDisposable
|
||||||
{
|
{
|
||||||
Task<int> SaveChangesAsync(CancellationToken cancellationToken = default(CancellationToken));
|
Task<int> SaveChangesAsync(CancellationToken cancellationToken = default(CancellationToken));
|
||||||
Task<int> SaveEntitiesAsync(CancellationToken cancellationToken = default(CancellationToken));
|
Task<bool> SaveEntitiesAsync(CancellationToken cancellationToken = default(CancellationToken));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ using System.Collections.Generic;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Repositories
|
namespace Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Idempotency
|
||||||
{
|
{
|
||||||
public interface IRequestManager
|
public interface IRequestManager
|
||||||
{
|
{
|
@ -1,10 +1,11 @@
|
|||||||
using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure;
|
using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure;
|
||||||
|
using Ordering.Domain.Exceptions;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Repositories
|
namespace Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Idempotency
|
||||||
{
|
{
|
||||||
public class RequestManager : IRequestManager
|
public class RequestManager : IRequestManager
|
||||||
{
|
{
|
||||||
@ -26,7 +27,7 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Repositor
|
|||||||
|
|
||||||
var exists = await ExistAsync(id);
|
var exists = await ExistAsync(id);
|
||||||
var request = exists ?
|
var request = exists ?
|
||||||
throw new Exception($"Request with {id} already exists") :
|
throw new OrderingDomainException($"Request with {id} already exists") :
|
||||||
new ClientRequest()
|
new ClientRequest()
|
||||||
{
|
{
|
||||||
Id = id,
|
Id = id,
|
@ -235,7 +235,7 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Infrastructure
|
|||||||
.IsRequired();
|
.IsRequired();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<int> SaveEntitiesAsync(CancellationToken cancellationToken = default(CancellationToken))
|
public async Task<bool> SaveEntitiesAsync(CancellationToken cancellationToken = default(CancellationToken))
|
||||||
{
|
{
|
||||||
// Dispatch Domain Events collection.
|
// Dispatch Domain Events collection.
|
||||||
// Choices:
|
// Choices:
|
||||||
@ -246,10 +246,11 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Infrastructure
|
|||||||
await _mediator.DispatchDomainEventsAsync(this);
|
await _mediator.DispatchDomainEventsAsync(this);
|
||||||
|
|
||||||
|
|
||||||
// After executing this line all the changes performed thought the DbContext will be commited
|
// After executing this line all the changes (from the Command Handler and Domain Event Handlers)
|
||||||
|
// performed thought the DbContext will be commited
|
||||||
var result = await base.SaveChangesAsync();
|
var result = await base.SaveChangesAsync();
|
||||||
|
|
||||||
return result;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,305 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<Import Project="..\packages\Microsoft.Net.Compilers.2.0.1\build\Microsoft.Net.Compilers.props" Condition="Exists('..\packages\Microsoft.Net.Compilers.2.0.1\build\Microsoft.Net.Compilers.props')" />
|
||||||
|
<Import Project="..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.1.0.3\build\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.props" Condition="Exists('..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.1.0.3\build\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.props')" />
|
||||||
|
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||||
|
<PropertyGroup>
|
||||||
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
|
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||||
|
<ProductVersion>
|
||||||
|
</ProductVersion>
|
||||||
|
<SchemaVersion>2.0</SchemaVersion>
|
||||||
|
<ProjectGuid>{07B42E24-32F8-4C10-99A8-0FB5AC6BFEBB}</ProjectGuid>
|
||||||
|
<ProjectTypeGuids>{349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids>
|
||||||
|
<OutputType>Library</OutputType>
|
||||||
|
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||||
|
<RootNamespace>Microsoft.eShopOnContainers.Catalog.WebForms</RootNamespace>
|
||||||
|
<AssemblyName>Catalog.WebForms</AssemblyName>
|
||||||
|
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
|
||||||
|
<UseIISExpress>true</UseIISExpress>
|
||||||
|
<IISExpressSSLPort />
|
||||||
|
<IISExpressAnonymousAuthentication />
|
||||||
|
<IISExpressWindowsAuthentication />
|
||||||
|
<IISExpressUseClassicPipelineMode />
|
||||||
|
<UseGlobalApplicationHostFile />
|
||||||
|
<NuGetPackageImportStamp>
|
||||||
|
</NuGetPackageImportStamp>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<Optimize>false</Optimize>
|
||||||
|
<OutputPath>bin\</OutputPath>
|
||||||
|
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<OutputPath>bin\</OutputPath>
|
||||||
|
<DefineConstants>TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="Autofac, Version=4.3.0.0, Culture=neutral, PublicKeyToken=17863af14b0044da, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\Autofac.4.3.0\lib\net45\Autofac.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=1.0.3.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.1.0.3\lib\net45\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Microsoft.CSharp" />
|
||||||
|
<Reference Include="System.ComponentModel.DataAnnotations" />
|
||||||
|
<Reference Include="System" />
|
||||||
|
<Reference Include="System.Data" />
|
||||||
|
<Reference Include="System.Core" />
|
||||||
|
<Reference Include="System.Data.DataSetExtensions" />
|
||||||
|
<Reference Include="System.Web.Extensions" />
|
||||||
|
<Reference Include="System.Xml.Linq" />
|
||||||
|
<Reference Include="System.Drawing" />
|
||||||
|
<Reference Include="System.Web" />
|
||||||
|
<Reference Include="System.Xml" />
|
||||||
|
<Reference Include="System.Configuration" />
|
||||||
|
<Reference Include="System.Web.Services" />
|
||||||
|
<Reference Include="System.EnterpriseServices" />
|
||||||
|
<Reference Include="System.Web.DynamicData" />
|
||||||
|
<Reference Include="System.Web.Entity" />
|
||||||
|
<Reference Include="System.Web.ApplicationServices" />
|
||||||
|
<Reference Include="Microsoft.Web.Infrastructure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||||
|
<Private>True</Private>
|
||||||
|
<HintPath>..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="AspNet.ScriptManager.bootstrap">
|
||||||
|
<HintPath>..\packages\AspNet.ScriptManager.bootstrap.3.0.0\lib\net45\AspNet.ScriptManager.bootstrap.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="AspNet.ScriptManager.jQuery">
|
||||||
|
<HintPath>..\packages\AspNet.ScriptManager.jQuery.1.10.2\lib\net45\AspNet.ScriptManager.jQuery.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Microsoft.ScriptManager.MSAjax">
|
||||||
|
<HintPath>..\packages\Microsoft.AspNet.ScriptManager.MSAjax.5.0.0\lib\net45\Microsoft.ScriptManager.MSAjax.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Microsoft.ScriptManager.WebForms">
|
||||||
|
<HintPath>..\packages\Microsoft.AspNet.ScriptManager.WebForms.5.0.0\lib\net45\Microsoft.ScriptManager.WebForms.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Web.Optimization, Version=1.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35">
|
||||||
|
<HintPath>..\packages\Microsoft.AspNet.Web.Optimization.1.1.3\lib\net40\System.Web.Optimization.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="WebGrease">
|
||||||
|
<Private>True</Private>
|
||||||
|
<HintPath>..\packages\WebGrease.1.5.2\lib\WebGrease.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Antlr3.Runtime">
|
||||||
|
<Private>True</Private>
|
||||||
|
<HintPath>..\packages\Antlr.3.4.1.9004\lib\Antlr3.Runtime.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Microsoft.AspNet.Web.Optimization.WebForms">
|
||||||
|
<Private>True</Private>
|
||||||
|
<HintPath>..\packages\Microsoft.AspNet.Web.Optimization.WebForms.1.1.3\lib\net45\Microsoft.AspNet.Web.Optimization.WebForms.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Microsoft.AspNet.FriendlyUrls">
|
||||||
|
<HintPath>..\packages\Microsoft.AspNet.FriendlyUrls.Core.1.0.2\lib\net45\Microsoft.AspNet.FriendlyUrls.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="Newtonsoft.Json">
|
||||||
|
<HintPath>..\packages\Newtonsoft.Json.6.0.4\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Microsoft.ApplicationInsights">
|
||||||
|
<HintPath>..\packages\Microsoft.ApplicationInsights.2.2.0\lib\net45\Microsoft.ApplicationInsights.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Microsoft.AI.Agent.Intercept">
|
||||||
|
<HintPath>..\packages\Microsoft.ApplicationInsights.Agent.Intercept.2.0.6\lib\net45\Microsoft.AI.Agent.Intercept.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Microsoft.AI.DependencyCollector">
|
||||||
|
<HintPath>..\packages\Microsoft.ApplicationInsights.DependencyCollector.2.2.0\lib\net45\Microsoft.AI.DependencyCollector.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Microsoft.AI.PerfCounterCollector">
|
||||||
|
<HintPath>..\packages\Microsoft.ApplicationInsights.PerfCounterCollector.2.2.0\lib\net45\Microsoft.AI.PerfCounterCollector.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Microsoft.AI.ServerTelemetryChannel">
|
||||||
|
<HintPath>..\packages\Microsoft.ApplicationInsights.WindowsServer.TelemetryChannel.2.2.0\lib\net45\Microsoft.AI.ServerTelemetryChannel.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Microsoft.AI.WindowsServer">
|
||||||
|
<HintPath>..\packages\Microsoft.ApplicationInsights.WindowsServer.2.2.0\lib\net45\Microsoft.AI.WindowsServer.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Microsoft.AI.Web">
|
||||||
|
<HintPath>..\packages\Microsoft.ApplicationInsights.Web.2.2.0\lib\net45\Microsoft.AI.Web.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Include="About.aspx" />
|
||||||
|
<Content Include="Contact.aspx" />
|
||||||
|
<Content Include="Content\bootstrap.css" />
|
||||||
|
<Content Include="Content\bootstrap.min.css" />
|
||||||
|
<Content Include="Content\fake_product_01.png" />
|
||||||
|
<Content Include="Content\fake_product_02.png" />
|
||||||
|
<Content Include="Content\fake_product_03.png" />
|
||||||
|
<Content Include="Content\fake_product_04.png" />
|
||||||
|
<Content Include="Content\fake_product_05.png" />
|
||||||
|
<Content Include="Content\Site.css" />
|
||||||
|
<Content Include="Default.aspx" />
|
||||||
|
<Content Include="favicon.ico" />
|
||||||
|
<Content Include="fonts\glyphicons-halflings-regular.svg" />
|
||||||
|
<Content Include="Global.asax" />
|
||||||
|
<Content Include="fonts\glyphicons-halflings-regular.woff" />
|
||||||
|
<Content Include="fonts\glyphicons-halflings-regular.ttf" />
|
||||||
|
<Content Include="fonts\glyphicons-halflings-regular.eot" />
|
||||||
|
<Content Include="ApplicationInsights.config">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<None Include="Dockerfile" />
|
||||||
|
<None Include=".dockerignore">
|
||||||
|
<DependentUpon>Dockerfile</DependentUpon>
|
||||||
|
</None>
|
||||||
|
<None Include="Properties\PublishProfiles\FolderProfile.pubxml" />
|
||||||
|
<None Include="Scripts\jquery-1.10.2.intellisense.js" />
|
||||||
|
<Content Include="Scripts\bootstrap.js" />
|
||||||
|
<Content Include="Scripts\bootstrap.min.js" />
|
||||||
|
<Content Include="Scripts\jquery-1.10.2.js" />
|
||||||
|
<Content Include="Scripts\jquery-1.10.2.min.js" />
|
||||||
|
<Content Include="Scripts\modernizr-2.6.2.js" />
|
||||||
|
<Content Include="Scripts\respond.js" />
|
||||||
|
<Content Include="Scripts\respond.min.js" />
|
||||||
|
<Content Include="Scripts\WebForms\DetailsView.js" />
|
||||||
|
<Content Include="Scripts\WebForms\Focus.js" />
|
||||||
|
<Content Include="Scripts\WebForms\GridView.js" />
|
||||||
|
<Content Include="Scripts\WebForms\Menu.js" />
|
||||||
|
<Content Include="Scripts\WebForms\MenuStandards.js" />
|
||||||
|
<Content Include="Scripts\WebForms\MSAjax\MicrosoftAjax.js" />
|
||||||
|
<Content Include="Scripts\WebForms\MSAjax\MicrosoftAjaxApplicationServices.js" />
|
||||||
|
<Content Include="Scripts\WebForms\MSAjax\MicrosoftAjaxComponentModel.js" />
|
||||||
|
<Content Include="Scripts\WebForms\MSAjax\MicrosoftAjaxCore.js" />
|
||||||
|
<Content Include="Scripts\WebForms\MSAjax\MicrosoftAjaxGlobalization.js" />
|
||||||
|
<Content Include="Scripts\WebForms\MSAjax\MicrosoftAjaxHistory.js" />
|
||||||
|
<Content Include="Scripts\WebForms\MSAjax\MicrosoftAjaxNetwork.js" />
|
||||||
|
<Content Include="Scripts\WebForms\MSAjax\MicrosoftAjaxSerialization.js" />
|
||||||
|
<Content Include="Scripts\WebForms\MSAjax\MicrosoftAjaxTimer.js" />
|
||||||
|
<Content Include="Scripts\WebForms\MSAjax\MicrosoftAjaxWebForms.js" />
|
||||||
|
<Content Include="Scripts\WebForms\MSAjax\MicrosoftAjaxWebServices.js" />
|
||||||
|
<Content Include="Scripts\WebForms\SmartNav.js" />
|
||||||
|
<Content Include="Scripts\WebForms\TreeView.js" />
|
||||||
|
<Content Include="Scripts\WebForms\WebForms.js" />
|
||||||
|
<Content Include="Scripts\WebForms\WebParts.js" />
|
||||||
|
<Content Include="Scripts\WebForms\WebUIValidation.js" />
|
||||||
|
<Content Include="Site.Master" />
|
||||||
|
<Content Include="ViewSwitcher.ascx" />
|
||||||
|
<Content Include="Web.config" />
|
||||||
|
<Content Include="Bundle.config" />
|
||||||
|
<Content Include="Site.Mobile.Master" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="App_Start\BundleConfig.cs" />
|
||||||
|
<Compile Include="About.aspx.cs">
|
||||||
|
<DependentUpon>About.aspx</DependentUpon>
|
||||||
|
<SubType>ASPXCodeBehind</SubType>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="About.aspx.designer.cs">
|
||||||
|
<DependentUpon>About.aspx</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="App_Start\RouteConfig.cs" />
|
||||||
|
<Compile Include="Contact.aspx.cs">
|
||||||
|
<DependentUpon>Contact.aspx</DependentUpon>
|
||||||
|
<SubType>ASPXCodeBehind</SubType>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="Contact.aspx.designer.cs">
|
||||||
|
<DependentUpon>Contact.aspx</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="Default.aspx.cs">
|
||||||
|
<DependentUpon>Default.aspx</DependentUpon>
|
||||||
|
<SubType>ASPXCodeBehind</SubType>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="Default.aspx.designer.cs">
|
||||||
|
<DependentUpon>Default.aspx</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="Extensions\ObservableExtensions.cs" />
|
||||||
|
<Compile Include="Global.asax.cs">
|
||||||
|
<DependentUpon>Global.asax</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="Models\CatalogBrand.cs" />
|
||||||
|
<Compile Include="Models\CatalogItem.cs" />
|
||||||
|
<Compile Include="Models\CatalogRoot.cs" />
|
||||||
|
<Compile Include="Models\CatalogType.cs" />
|
||||||
|
<Compile Include="Modules\AutoFacHttpModule.cs" />
|
||||||
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
<Compile Include="Services\CatalogMockService.cs" />
|
||||||
|
<Compile Include="Services\CatalogService.cs" />
|
||||||
|
<Compile Include="Services\Common.cs" />
|
||||||
|
<Compile Include="Services\ICatalogService.cs" />
|
||||||
|
<Compile Include="Services\IRouteProvider.cs" />
|
||||||
|
<Compile Include="Site.Master.cs">
|
||||||
|
<DependentUpon>Site.Master</DependentUpon>
|
||||||
|
<SubType>ASPXCodeBehind</SubType>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="Site.Master.designer.cs">
|
||||||
|
<DependentUpon>Site.Master</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="Site.Mobile.Master.cs">
|
||||||
|
<DependentUpon>Site.Mobile.Master</DependentUpon>
|
||||||
|
<SubType>ASPXCodeBehind</SubType>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="Site.Mobile.Master.designer.cs">
|
||||||
|
<DependentUpon>Site.Mobile.Master</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="ViewSwitcher.ascx.cs">
|
||||||
|
<DependentUpon>ViewSwitcher.ascx</DependentUpon>
|
||||||
|
<SubType>ASPXCodeBehind</SubType>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="ViewSwitcher.ascx.designer.cs">
|
||||||
|
<DependentUpon>ViewSwitcher.ascx</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Folder Include="App_Data\" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Include="packages.config" />
|
||||||
|
<Content Include="Scripts\jquery-1.10.2.min.map" />
|
||||||
|
<None Include="Web.Debug.config">
|
||||||
|
<DependentUpon>Web.config</DependentUpon>
|
||||||
|
</None>
|
||||||
|
<None Include="Web.Release.config">
|
||||||
|
<DependentUpon>Web.config</DependentUpon>
|
||||||
|
</None>
|
||||||
|
</ItemGroup>
|
||||||
|
<PropertyGroup>
|
||||||
|
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
|
||||||
|
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||||
|
<Import Project="$(VSToolsPath)\WebApplications\Microsoft.WebApplication.targets" Condition="'$(VSToolsPath)' != ''" />
|
||||||
|
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" Condition="false" />
|
||||||
|
<ProjectExtensions>
|
||||||
|
<VisualStudio>
|
||||||
|
<FlavorProperties GUID="{349c5851-65df-11da-9384-00065b846f21}">
|
||||||
|
<WebProjectProperties>
|
||||||
|
<UseIIS>True</UseIIS>
|
||||||
|
<AutoAssignPort>True</AutoAssignPort>
|
||||||
|
<DevelopmentServerPort>58178</DevelopmentServerPort>
|
||||||
|
<DevelopmentServerVPath>/</DevelopmentServerVPath>
|
||||||
|
<IISUrl>http://localhost:58178/</IISUrl>
|
||||||
|
<NTLMAuthentication>False</NTLMAuthentication>
|
||||||
|
<UseCustomServer>False</UseCustomServer>
|
||||||
|
<CustomServerUrl>
|
||||||
|
</CustomServerUrl>
|
||||||
|
<SaveServerSettingsInUserFile>False</SaveServerSettingsInUserFile>
|
||||||
|
</WebProjectProperties>
|
||||||
|
</FlavorProperties>
|
||||||
|
</VisualStudio>
|
||||||
|
</ProjectExtensions>
|
||||||
|
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||||
|
<PropertyGroup>
|
||||||
|
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Error Condition="!Exists('..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.1.0.3\build\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.1.0.3\build\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.props'))" />
|
||||||
|
<Error Condition="!Exists('..\packages\Microsoft.Net.Compilers.2.0.1\build\Microsoft.Net.Compilers.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Net.Compilers.2.0.1\build\Microsoft.Net.Compilers.props'))" />
|
||||||
|
</Target>
|
||||||
|
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||||
|
Other similar extension points exist, see Microsoft.Common.targets.
|
||||||
|
<Target Name="BeforeBuild">
|
||||||
|
</Target>
|
||||||
|
<Target Name="AfterBuild">
|
||||||
|
</Target>
|
||||||
|
-->
|
||||||
|
</Project>
|
45
src/Web/Catalog.WebForms/Catalog.WebForms/Default.aspx.cs
Normal file
45
src/Web/Catalog.WebForms/Catalog.WebForms/Default.aspx.cs
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
using Autofac;
|
||||||
|
using Autofac.Core;
|
||||||
|
using eShopOnContainers.Core.Models.Catalog;
|
||||||
|
using eShopOnContainers.Core.Services.Catalog;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Web;
|
||||||
|
using System.Web.UI;
|
||||||
|
using System.Web.UI.WebControls;
|
||||||
|
|
||||||
|
namespace Microsoft.eShopOnContainers.Catalog.WebForms
|
||||||
|
{
|
||||||
|
public partial class _Default : Page
|
||||||
|
{
|
||||||
|
private ICatalogService catalog;
|
||||||
|
|
||||||
|
protected _Default() { }
|
||||||
|
|
||||||
|
public _Default(ICatalogService catalog)
|
||||||
|
{
|
||||||
|
this.catalog = catalog;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnLoad(EventArgs e)
|
||||||
|
{
|
||||||
|
RegisterAsyncTask(new PageAsyncTask(LoadCatalogDataAsync));
|
||||||
|
|
||||||
|
base.OnLoad(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task LoadCatalogDataAsync()
|
||||||
|
{
|
||||||
|
var collection = await catalog?.GetCatalogAsync();
|
||||||
|
catalogList.DataSource = collection;
|
||||||
|
catalogList.DataBind();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void Page_Load(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
19
src/Web/Catalog.WebForms/Catalog.WebForms/Global.asax.cs
Normal file
19
src/Web/Catalog.WebForms/Catalog.WebForms/Global.asax.cs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
using System;
|
||||||
|
using System.Web;
|
||||||
|
using System.Web.Optimization;
|
||||||
|
using System.Web.Routing;
|
||||||
|
|
||||||
|
namespace Microsoft.eShopOnContainers.Catalog.WebForms
|
||||||
|
{
|
||||||
|
public class Global : HttpApplication
|
||||||
|
{
|
||||||
|
|
||||||
|
void Application_Start(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
// Code that runs on application startup
|
||||||
|
RouteConfig.RegisterRoutes(RouteTable.Routes);
|
||||||
|
BundleConfig.RegisterBundles(BundleTable.Bundles);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,83 @@
|
|||||||
|
using Autofac;
|
||||||
|
using eShopOnContainers.Core.Services.Catalog;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Web;
|
||||||
|
using System.Web.Configuration;
|
||||||
|
using System.Web.UI;
|
||||||
|
|
||||||
|
namespace Microsoft.eShopOnContainers.Catalog.WebForms.Modules
|
||||||
|
{
|
||||||
|
// Using DI with WebForms is not yet implemented.
|
||||||
|
// This implementation has been adapted from this post:
|
||||||
|
// https://blogs.msdn.microsoft.com/webdev/2016/10/19/modern-asp-net-web-forms-development-dependency-injection/
|
||||||
|
|
||||||
|
public class AutoFacHttpModule : IHttpModule
|
||||||
|
{
|
||||||
|
private static IContainer Container => lazyContainer.Value;
|
||||||
|
|
||||||
|
private static Lazy<IContainer> lazyContainer = new Lazy<IContainer>(() => CreateContainer());
|
||||||
|
|
||||||
|
private static IContainer CreateContainer()
|
||||||
|
{
|
||||||
|
// Configure AutoFac:
|
||||||
|
// Register Containers:
|
||||||
|
var settings = WebConfigurationManager.AppSettings;
|
||||||
|
var useFake = settings["usefake"];
|
||||||
|
bool fake = useFake == "true";
|
||||||
|
var builder = new ContainerBuilder();
|
||||||
|
if (fake)
|
||||||
|
{
|
||||||
|
builder.RegisterType<CatalogMockService>()
|
||||||
|
.As<ICatalogService>();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
builder.RegisterType<CatalogMockService>()
|
||||||
|
.As<ICatalogService>();
|
||||||
|
}
|
||||||
|
var container = builder.Build();
|
||||||
|
return container;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Container.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Init(HttpApplication context)
|
||||||
|
{
|
||||||
|
context.PreRequestHandlerExecute += (_, __) => InjectDependencies();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InjectDependencies()
|
||||||
|
{
|
||||||
|
if (HttpContext.Current.CurrentHandler is Page page)
|
||||||
|
{
|
||||||
|
// Get the code-behind class that we may have written
|
||||||
|
var pageType = page.GetType().BaseType;
|
||||||
|
|
||||||
|
// Determine if there is a constructor to inject, and grab it
|
||||||
|
var ctor = (from c in pageType.GetConstructors()
|
||||||
|
where c.GetParameters().Length > 0
|
||||||
|
select c).FirstOrDefault();
|
||||||
|
|
||||||
|
if (ctor != null)
|
||||||
|
{
|
||||||
|
// Resolve the parameters for the constructor
|
||||||
|
var args = (from parm in ctor.GetParameters()
|
||||||
|
select Container.Resolve(parm.ParameterType))
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
// Execute the constructor method with the arguments resolved
|
||||||
|
ctor.Invoke(page, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use the Autofac method to inject any properties that can be filled by Autofac
|
||||||
|
Container.InjectProperties(page);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
54
src/Web/Catalog.WebForms/Catalog.WebForms/Web.config
Normal file
54
src/Web/Catalog.WebForms/Catalog.WebForms/Web.config
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
For more information on how to configure your ASP.NET application, please visit
|
||||||
|
https://go.microsoft.com/fwlink/?LinkId=169433
|
||||||
|
-->
|
||||||
|
<configuration>
|
||||||
|
<appSettings>
|
||||||
|
<add key="usefake" value="true" />
|
||||||
|
</appSettings>
|
||||||
|
<system.web>
|
||||||
|
<compilation debug="true" targetFramework="4.5.2" />
|
||||||
|
<httpRuntime targetFramework="4.5.2" />
|
||||||
|
<pages>
|
||||||
|
<namespaces>
|
||||||
|
<add namespace="System.Web.Optimization" />
|
||||||
|
</namespaces>
|
||||||
|
<controls>
|
||||||
|
<add assembly="Microsoft.AspNet.Web.Optimization.WebForms" namespace="Microsoft.AspNet.Web.Optimization.WebForms" tagPrefix="webopt" />
|
||||||
|
</controls>
|
||||||
|
</pages>
|
||||||
|
<httpModules>
|
||||||
|
<add name="ApplicationInsightsWebTracking" type="Microsoft.ApplicationInsights.Web.ApplicationInsightsHttpModule, Microsoft.AI.Web" />
|
||||||
|
<!-- Use this if you are on IIS 7 and earlier -->
|
||||||
|
<add name="InjectModule" type="Microsoft.eShopOnContainers.Catalog.WebForms.Modules.AutoFacHttpModule, Catalog.WebForms" />
|
||||||
|
</httpModules>
|
||||||
|
</system.web>
|
||||||
|
<runtime>
|
||||||
|
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||||
|
<dependentAssembly>
|
||||||
|
<assemblyIdentity name="Newtonsoft.Json" culture="neutral" publicKeyToken="30ad4fe6b2a6aeed" />
|
||||||
|
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
|
||||||
|
</dependentAssembly>
|
||||||
|
<dependentAssembly>
|
||||||
|
<assemblyIdentity name="WebGrease" culture="neutral" publicKeyToken="31bf3856ad364e35" />
|
||||||
|
<bindingRedirect oldVersion="0.0.0.0-1.5.2.14234" newVersion="1.5.2.14234" />
|
||||||
|
</dependentAssembly>
|
||||||
|
</assemblyBinding>
|
||||||
|
</runtime>
|
||||||
|
<system.webServer>
|
||||||
|
<validation validateIntegratedModeConfiguration="false" />
|
||||||
|
<modules>
|
||||||
|
<remove name="ApplicationInsightsWebTracking" />
|
||||||
|
<add name="ApplicationInsightsWebTracking" type="Microsoft.ApplicationInsights.Web.ApplicationInsightsHttpModule, Microsoft.AI.Web" preCondition="managedHandler" />
|
||||||
|
<!-- Use this if you are on IIS 8 and later -->
|
||||||
|
<add name="InjectModule" type="Microsoft.eShopOnContainers.Catalog.WebForms.Modules.AutoFacHttpModule, Catalog.WebForms" />
|
||||||
|
</modules>
|
||||||
|
</system.webServer>
|
||||||
|
<system.codedom>
|
||||||
|
<compilers>
|
||||||
|
<compiler language="c#;cs;csharp" extension=".cs" type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=1.0.3.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" warningLevel="4" compilerOptions="/langversion:6 /nowarn:1659;1699;1701" />
|
||||||
|
<compiler language="vb;vbs;visualbasic;vbscript" extension=".vb" type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.VBCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=1.0.3.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" warningLevel="4" compilerOptions="/langversion:14 /nowarn:41008 /define:_MYTYPE=\"Web\" /optionInfer+" />
|
||||||
|
</compilers>
|
||||||
|
</system.codedom>
|
||||||
|
</configuration>
|
29
src/Web/Catalog.WebForms/Catalog.WebForms/packages.config
Normal file
29
src/Web/Catalog.WebForms/Catalog.WebForms/packages.config
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<packages>
|
||||||
|
<package id="Antlr" version="3.4.1.9004" targetFramework="net452" />
|
||||||
|
<package id="AspNet.ScriptManager.bootstrap" version="3.0.0" targetFramework="net452" />
|
||||||
|
<package id="AspNet.ScriptManager.jQuery" version="1.10.2" targetFramework="net452" />
|
||||||
|
<package id="Autofac" version="4.3.0" targetFramework="net452" />
|
||||||
|
<package id="bootstrap" version="3.0.0" targetFramework="net452" />
|
||||||
|
<package id="jQuery" version="1.10.2" targetFramework="net452" />
|
||||||
|
<package id="Microsoft.ApplicationInsights" version="2.2.0" targetFramework="net452" />
|
||||||
|
<package id="Microsoft.ApplicationInsights.Agent.Intercept" version="2.0.6" targetFramework="net452" />
|
||||||
|
<package id="Microsoft.ApplicationInsights.DependencyCollector" version="2.2.0" targetFramework="net452" />
|
||||||
|
<package id="Microsoft.ApplicationInsights.PerfCounterCollector" version="2.2.0" targetFramework="net452" />
|
||||||
|
<package id="Microsoft.ApplicationInsights.Web" version="2.2.0" targetFramework="net452" />
|
||||||
|
<package id="Microsoft.ApplicationInsights.WindowsServer" version="2.2.0" targetFramework="net452" />
|
||||||
|
<package id="Microsoft.ApplicationInsights.WindowsServer.TelemetryChannel" version="2.2.0" targetFramework="net452" />
|
||||||
|
<package id="Microsoft.AspNet.FriendlyUrls" version="1.0.2" targetFramework="net452" />
|
||||||
|
<package id="Microsoft.AspNet.FriendlyUrls.Core" version="1.0.2" targetFramework="net452" />
|
||||||
|
<package id="Microsoft.AspNet.ScriptManager.MSAjax" version="5.0.0" targetFramework="net452" />
|
||||||
|
<package id="Microsoft.AspNet.ScriptManager.WebForms" version="5.0.0" targetFramework="net452" />
|
||||||
|
<package id="Microsoft.AspNet.Web.Optimization" version="1.1.3" targetFramework="net452" />
|
||||||
|
<package id="Microsoft.AspNet.Web.Optimization.WebForms" version="1.1.3" targetFramework="net452" />
|
||||||
|
<package id="Microsoft.CodeDom.Providers.DotNetCompilerPlatform" version="1.0.3" targetFramework="net452" />
|
||||||
|
<package id="Microsoft.Net.Compilers" version="2.0.1" targetFramework="net452" developmentDependency="true" />
|
||||||
|
<package id="Microsoft.Web.Infrastructure" version="1.0.0.0" targetFramework="net452" />
|
||||||
|
<package id="Modernizr" version="2.6.2" targetFramework="net452" />
|
||||||
|
<package id="Newtonsoft.Json" version="6.0.4" targetFramework="net452" />
|
||||||
|
<package id="Respond" version="1.2.0" targetFramework="net452" />
|
||||||
|
<package id="WebGrease" version="1.5.2" targetFramework="net452" />
|
||||||
|
</packages>
|
8
src/Web/WebMVC/Dockerfile.nanowin
Normal file
8
src/Web/WebMVC/Dockerfile.nanowin
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
FROM microsoft/dotnet:1.1-runtime-nanoserver
|
||||||
|
SHELL ["powershell"]
|
||||||
|
ARG source
|
||||||
|
WORKDIR /app
|
||||||
|
RUN set-itemproperty -path 'HKLM:\SYSTEM\CurrentControlSet\Services\Dnscache\Parameters' -Name ServerPriorityTimeLimit -Value 0 -Type DWord
|
||||||
|
EXPOSE 80
|
||||||
|
COPY ${source:-obj/Docker/publish} .
|
||||||
|
ENTRYPOINT ["dotnet", "WebMVC.dll"]
|
@ -56,6 +56,8 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
|
|||||||
|
|
||||||
var response = await _apiClient.PostAsync(basketUrl, basket);
|
var response = await _apiClient.PostAsync(basketUrl, basket);
|
||||||
|
|
||||||
|
response.EnsureSuccessStatusCode();
|
||||||
|
|
||||||
return basket;
|
return basket;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,6 +88,8 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
|
|||||||
|
|
||||||
if (response.StatusCode == System.Net.HttpStatusCode.InternalServerError)
|
if (response.StatusCode == System.Net.HttpStatusCode.InternalServerError)
|
||||||
throw new Exception("Error creating order, try later");
|
throw new Exception("Error creating order, try later");
|
||||||
|
|
||||||
|
response.EnsureSuccessStatusCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OverrideUserInfoIntoOrder(Order original, Order destination)
|
public void OverrideUserInfoIntoOrder(Order original, Order destination)
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Polly;
|
using Polly;
|
||||||
using Polly.Wrap;
|
using Polly.Wrap;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Net;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
@ -76,13 +78,17 @@ namespace WebMVC.Services.Utilities
|
|||||||
// a new StringContent must be created for each retry
|
// a new StringContent must be created for each retry
|
||||||
// as it is disposed after each call
|
// as it is disposed after each call
|
||||||
HttpInvoker(() =>
|
HttpInvoker(() =>
|
||||||
|
{
|
||||||
|
var response = _client.PostAsync(uri, new StringContent(JsonConvert.SerializeObject(item), System.Text.Encoding.UTF8, "application/json"));
|
||||||
|
// raise exception if HttpResponseCode 500
|
||||||
|
// needed for circuit breaker to track fails
|
||||||
|
if (response.Result.StatusCode == HttpStatusCode.InternalServerError)
|
||||||
{
|
{
|
||||||
var response = _client.PostAsync(uri, new StringContent(JsonConvert.SerializeObject(item), System.Text.Encoding.UTF8, "application/json"));
|
throw new HttpRequestException();
|
||||||
// raise exception if not success response
|
}
|
||||||
// needed for circuit breaker to track fails
|
|
||||||
response.Result.EnsureSuccessStatusCode();
|
return response;
|
||||||
return response;
|
});
|
||||||
});
|
|
||||||
|
|
||||||
public Task<HttpResponseMessage> DeleteAsync(string uri) =>
|
public Task<HttpResponseMessage> DeleteAsync(string uri) =>
|
||||||
HttpInvoker(() => _client.DeleteAsync(uri));
|
HttpInvoker(() => _client.DeleteAsync(uri));
|
||||||
|
@ -44,7 +44,16 @@
|
|||||||
<p>
|
<p>
|
||||||
<a asp-action="Register" asp-route-returnurl="@ViewData["ReturnUrl"]" class="text">Register as a new user?</a>
|
<a asp-action="Register" asp-route-returnurl="@ViewData["ReturnUrl"]" class="text">Register as a new user?</a>
|
||||||
</p>
|
</p>
|
||||||
</form>
|
<p>
|
||||||
|
Note that for demo purposes you don't need to register and can login with these credentials:
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
User: <b>demouser@microsoft.com</b>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Password: <b>Pass@word1</b>
|
||||||
|
</p>
|
||||||
|
</form>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -38,7 +38,7 @@
|
|||||||
<div class="esh-basket-items--border row">
|
<div class="esh-basket-items--border row">
|
||||||
@if (item.OldUnitPrice != 0)
|
@if (item.OldUnitPrice != 0)
|
||||||
{
|
{
|
||||||
<div class="alert alert-warning esh-basket-margin12" role="alert"> The price of the item has changed.Old price was @item.OldUnitPrice $</div>
|
<div class="alert alert-warning esh-basket-margin12" role="alert"> Note that the price of this article changed in our Catalog. The old price when you originally added it to the basket was @item.OldUnitPrice $</div>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
<br/>
|
<br/>
|
||||||
|
2
src/Web/WebMVC/wwwroot/css/site.min.css
vendored
2
src/Web/WebMVC/wwwroot/css/site.min.css
vendored
File diff suppressed because one or more lines are too long
@ -29,7 +29,7 @@
|
|||||||
</article>
|
</article>
|
||||||
<br/>
|
<br/>
|
||||||
<div class="esh-basket-items-margin-left1 row">
|
<div class="esh-basket-items-margin-left1 row">
|
||||||
<div class="alert alert-warning" role="alert" *ngIf="item.oldUnitPrice > 0"> The price of the item has changed.Old price was {{item.oldUnitPrice}} $</div>
|
<div class="alert alert-warning" role="alert" *ngIf="item.oldUnitPrice > 0"> Note that the price of this article changed in our Catalog. The old price when you originally added it to the basket was {{item.oldUnitPrice}} $</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -5,6 +5,9 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="container">
|
<div class="container">
|
||||||
|
<div class="alert alert-warning esh-orders_new-alert" role="alert" [hidden]="!errorReceived">
|
||||||
|
Not possible to create a new order, please try later on
|
||||||
|
</div>
|
||||||
<form [formGroup]="newOrderForm" (ngSubmit)="submitForm(newOrderForm.value)">
|
<form [formGroup]="newOrderForm" (ngSubmit)="submitForm(newOrderForm.value)">
|
||||||
<section class="esh-orders_new-section">
|
<section class="esh-orders_new-section">
|
||||||
<h4 class="esh-orders_new-title">Shipping Address</h4>
|
<h4 class="esh-orders_new-title">Shipping Address</h4>
|
||||||
@ -105,7 +108,7 @@
|
|||||||
<div class="col-md-9">
|
<div class="col-md-9">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-2">
|
<div class="col-md-2">
|
||||||
<button type="submit" class="btn esh-orders_new-placeOrder" [disabled]="!newOrderForm.valid">[ Place Order ]</button>
|
<button type="submit" class="btn esh-orders_new-placeOrder" [disabled]="!newOrderForm.valid || isOrderProcessing">[ Place Order ]</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
@ -94,4 +94,8 @@
|
|||||||
&-image {
|
&-image {
|
||||||
height: $item-height;
|
height: $item-height;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&-alert {
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { Observable } from 'rxjs/Observable';
|
||||||
import { OrdersService } from '../orders.service';
|
import { OrdersService } from '../orders.service';
|
||||||
import { IOrder } from '../../shared/models/order.model';
|
import { IOrder } from '../../shared/models/order.model';
|
||||||
import { BasketWrapperService } from '../../shared/services/basket.wrapper.service';
|
import { BasketWrapperService } from '../../shared/services/basket.wrapper.service';
|
||||||
@ -13,10 +14,12 @@ import { Router } from '@angular/router';
|
|||||||
})
|
})
|
||||||
export class OrdersNewComponent implements OnInit {
|
export class OrdersNewComponent implements OnInit {
|
||||||
private newOrderForm: FormGroup; // new order form
|
private newOrderForm: FormGroup; // new order form
|
||||||
|
private isOrderProcessing: Boolean;
|
||||||
|
private errorReceived: Boolean;
|
||||||
private order: IOrder;
|
private order: IOrder;
|
||||||
|
|
||||||
constructor(private service: OrdersService, fb: FormBuilder, private router: Router, private basketEvents: BasketWrapperService) {
|
constructor(private service: OrdersService, fb: FormBuilder, private router: Router, private basketEvents: BasketWrapperService) {
|
||||||
// Obtener información del perfil de usuario.
|
// Obtain user profile information
|
||||||
this.order = service.mapBasketAndIdentityInfoNewOrder();
|
this.order = service.mapBasketAndIdentityInfoNewOrder();
|
||||||
this.newOrderForm = fb.group({
|
this.newOrderForm = fb.group({
|
||||||
'street': [this.order.street, Validators.required],
|
'street': [this.order.street, Validators.required],
|
||||||
@ -39,16 +42,25 @@ export class OrdersNewComponent implements OnInit {
|
|||||||
this.order.state = this.newOrderForm.controls['state'].value;
|
this.order.state = this.newOrderForm.controls['state'].value;
|
||||||
this.order.country = this.newOrderForm.controls['country'].value;
|
this.order.country = this.newOrderForm.controls['country'].value;
|
||||||
this.order.cardnumber = this.newOrderForm.controls['cardnumber'].value;
|
this.order.cardnumber = this.newOrderForm.controls['cardnumber'].value;
|
||||||
|
this.order.cardtypeid = 1;
|
||||||
this.order.cardholdername = this.newOrderForm.controls['cardholdername'].value;
|
this.order.cardholdername = this.newOrderForm.controls['cardholdername'].value;
|
||||||
this.order.cardexpiration = new Date(20 + this.newOrderForm.controls['expirationdate'].value.split('/')[1], this.newOrderForm.controls['expirationdate'].value.split('/')[0]);
|
this.order.cardexpiration = new Date(20 + this.newOrderForm.controls['expirationdate'].value.split('/')[1], this.newOrderForm.controls['expirationdate'].value.split('/')[0]);
|
||||||
this.order.cardsecuritynumber = this.newOrderForm.controls['securitycode'].value;
|
this.order.cardsecuritynumber = this.newOrderForm.controls['securitycode'].value;
|
||||||
|
|
||||||
this.service.postOrder(this.order).subscribe(res => {
|
this.service.postOrder(this.order)
|
||||||
|
.catch((errMessage) => {
|
||||||
|
this.errorReceived = true;
|
||||||
|
this.isOrderProcessing = false;
|
||||||
|
return Observable.throw(errMessage);
|
||||||
|
})
|
||||||
|
.subscribe(res => {
|
||||||
// this will emit an observable. Basket service is subscribed to this observable, and will react deleting the basket for the current user.
|
// this will emit an observable. Basket service is subscribed to this observable, and will react deleting the basket for the current user.
|
||||||
this.basketEvents.orderCreated();
|
this.basketEvents.orderCreated();
|
||||||
|
|
||||||
this.router.navigate(['orders']);
|
this.router.navigate(['orders']);
|
||||||
});
|
});
|
||||||
|
this.errorReceived = false;
|
||||||
|
this.isOrderProcessing = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
8
src/Web/WebSPA/Dockerfile.nanowin
Normal file
8
src/Web/WebSPA/Dockerfile.nanowin
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
FROM microsoft/dotnet:1.1-runtime-nanoserver
|
||||||
|
SHELL ["powershell"]
|
||||||
|
ARG source
|
||||||
|
WORKDIR /app
|
||||||
|
RUN set-itemproperty -path 'HKLM:\SYSTEM\CurrentControlSet\Services\Dnscache\Parameters' -Name ServerPriorityTimeLimit -Value 0 -Type DWord
|
||||||
|
EXPOSE 80
|
||||||
|
COPY ${source:-obj/Docker/publish} .
|
||||||
|
ENTRYPOINT ["dotnet", "WebSPA.dll"]
|
@ -0,0 +1,18 @@
|
|||||||
|
using Microsoft.AspNetCore.TestHost;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace FunctionalTests.Extensions
|
||||||
|
{
|
||||||
|
static class HttpClientExtensions
|
||||||
|
{
|
||||||
|
public static HttpClient CreateIdempotentClient(this TestServer server)
|
||||||
|
{
|
||||||
|
var client = server.CreateClient();
|
||||||
|
client.DefaultRequestHeaders.Add("x-requestid", Guid.NewGuid().ToString());
|
||||||
|
return client;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -34,7 +34,7 @@ namespace FunctionalTests.Services.Catalog
|
|||||||
|
|
||||||
public static class Post
|
public static class Post
|
||||||
{
|
{
|
||||||
public static string UpdateCatalogProduct = "api/v1/catalog/edit";
|
public static string UpdateCatalogProduct = "api/v1/catalog/update";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,7 +43,7 @@ namespace FunctionalTests.Services
|
|||||||
var itemToModify = basket.Items[2];
|
var itemToModify = basket.Items[2];
|
||||||
var oldPrice = itemToModify.UnitPrice;
|
var oldPrice = itemToModify.UnitPrice;
|
||||||
var newPrice = oldPrice + priceModification;
|
var newPrice = oldPrice + priceModification;
|
||||||
var pRes = await catalogClient.PostAsync(CatalogScenariosBase.Post.UpdateCatalogProduct, new StringContent(ChangePrice(itemToModify, newPrice), UTF8Encoding.UTF8, "application/json"));
|
var pRes = await catalogClient.PostAsync(CatalogScenariosBase.Post.UpdateCatalogProduct, new StringContent(ChangePrice(itemToModify, newPrice, originalCatalogProducts), UTF8Encoding.UTF8, "application/json"));
|
||||||
|
|
||||||
var modifiedCatalogProducts = await GetCatalogAsync(catalogClient);
|
var modifiedCatalogProducts = await GetCatalogAsync(catalogClient);
|
||||||
|
|
||||||
@ -100,14 +100,11 @@ namespace FunctionalTests.Services
|
|||||||
return JsonConvert.DeserializeObject<PaginatedItemsViewModel<CatalogItem>>(items);
|
return JsonConvert.DeserializeObject<PaginatedItemsViewModel<CatalogItem>>(items);
|
||||||
}
|
}
|
||||||
|
|
||||||
private string ChangePrice(BasketItem itemToModify, decimal newPrice)
|
private string ChangePrice(BasketItem itemToModify, decimal newPrice, PaginatedItemsViewModel<CatalogItem> catalogProducts)
|
||||||
{
|
{
|
||||||
var item = new CatalogItem()
|
var catalogProduct = catalogProducts.Data.Single(pr => pr.Id == int.Parse(itemToModify.ProductId));
|
||||||
{
|
catalogProduct.Price = newPrice;
|
||||||
Id = int.Parse(itemToModify.ProductId),
|
return JsonConvert.SerializeObject(catalogProduct);
|
||||||
Price = newPrice
|
|
||||||
};
|
|
||||||
return JsonConvert.SerializeObject(item);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private CustomerBasket ComposeBasket(string customerId, IEnumerable<CatalogItem> items)
|
private CustomerBasket ComposeBasket(string customerId, IEnumerable<CatalogItem> items)
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
using Microsoft.AspNetCore.TestHost;
|
using FunctionalTests.Extensions;
|
||||||
using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands;
|
using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands;
|
||||||
using Microsoft.eShopOnContainers.WebMVC.ViewModels;
|
using Microsoft.eShopOnContainers.WebMVC.ViewModels;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Data.SqlClient;
|
using System.Linq;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@ -20,22 +20,22 @@ namespace FunctionalTests.Services.Ordering
|
|||||||
{
|
{
|
||||||
using (var server = CreateServer())
|
using (var server = CreateServer())
|
||||||
{
|
{
|
||||||
var client = server.CreateClient();
|
var client = server.CreateIdempotentClient();
|
||||||
|
|
||||||
//Arrange
|
// GIVEN an order is created
|
||||||
await client.PostAsync(Post.AddNewOrder, new StringContent(BuildOrder(), UTF8Encoding.UTF8, "application/json"));
|
await client.PostAsync(Post.AddNewOrder, new StringContent(BuildOrder(), UTF8Encoding.UTF8, "application/json"));
|
||||||
|
|
||||||
var ordersResponse = await client.GetAsync(Get.Orders);
|
var ordersResponse = await client.GetAsync(Get.Orders);
|
||||||
var responseBody = await ordersResponse.Content.ReadAsStringAsync();
|
var responseBody = await ordersResponse.Content.ReadAsStringAsync();
|
||||||
dynamic orders = JsonConvert.DeserializeObject(responseBody);
|
var orders = JsonConvert.DeserializeObject<List<Order>>(responseBody);
|
||||||
string orderId = orders[0].ordernumber;
|
string orderId = orders.OrderByDescending(o => o.Date).First().OrderNumber;
|
||||||
|
|
||||||
//Act
|
//WHEN we request the order bit its id
|
||||||
var order= await client.GetAsync(Get.OrderBy(int.Parse(orderId)));
|
var order= await client.GetAsync(Get.OrderBy(int.Parse(orderId)));
|
||||||
var orderBody = await order.Content.ReadAsStringAsync();
|
var orderBody = await order.Content.ReadAsStringAsync();
|
||||||
var result = JsonConvert.DeserializeObject<Order>(orderBody);
|
var result = JsonConvert.DeserializeObject<Order>(orderBody);
|
||||||
|
|
||||||
//Assert
|
//THEN the requested order is returned
|
||||||
Assert.Equal(orderId, result.OrderNumber);
|
Assert.Equal(orderId, result.OrderNumber);
|
||||||
Assert.Equal("inprocess", result.Status);
|
Assert.Equal("inprocess", result.Status);
|
||||||
Assert.Equal(1, result.OrderItems.Count);
|
Assert.Equal(1, result.OrderItems.Count);
|
||||||
@ -63,7 +63,7 @@ namespace FunctionalTests.Services.Ordering
|
|||||||
order.AddOrderItem(new OrderItemDTO()
|
order.AddOrderItem(new OrderItemDTO()
|
||||||
{
|
{
|
||||||
ProductId = 1,
|
ProductId = 1,
|
||||||
Discount = 10M,
|
Discount = 8M,
|
||||||
UnitPrice = 10,
|
UnitPrice = 10,
|
||||||
Units = 1,
|
Units = 1,
|
||||||
ProductName = "Some name"
|
ProductName = "Some name"
|
||||||
|
@ -0,0 +1,18 @@
|
|||||||
|
using Microsoft.AspNetCore.TestHost;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace IntegrationTests.Services.Extensions
|
||||||
|
{
|
||||||
|
static class HttpClientExtensions
|
||||||
|
{
|
||||||
|
public static HttpClient CreateIdempotentClient(this TestServer server)
|
||||||
|
{
|
||||||
|
var client = server.CreateClient();
|
||||||
|
client.DefaultRequestHeaders.Add("x-requestid", Guid.NewGuid().ToString());
|
||||||
|
return client;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,7 @@
|
|||||||
namespace IntegrationTests.Services.Ordering
|
namespace IntegrationTests.Services.Ordering
|
||||||
{
|
{
|
||||||
|
using IntegrationTests.Services.Extensions;
|
||||||
|
using Microsoft.AspNetCore.TestHost;
|
||||||
using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands;
|
using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using System;
|
using System;
|
||||||
@ -28,9 +30,9 @@
|
|||||||
public async Task AddNewOrder_add_new_order_and_response_ok_status_code()
|
public async Task AddNewOrder_add_new_order_and_response_ok_status_code()
|
||||||
{
|
{
|
||||||
using (var server = CreateServer())
|
using (var server = CreateServer())
|
||||||
{
|
{
|
||||||
var content = new StringContent(BuildOrder(), UTF8Encoding.UTF8, "application/json");
|
var content = new StringContent(BuildOrder(), UTF8Encoding.UTF8, "application/json");
|
||||||
var response = await server.CreateClient()
|
var response = await server.CreateIdempotentClient()
|
||||||
.PostAsync(Post.AddNewOrder, content);
|
.PostAsync(Post.AddNewOrder, content);
|
||||||
|
|
||||||
response.EnsureSuccessStatusCode();
|
response.EnsureSuccessStatusCode();
|
||||||
@ -44,7 +46,7 @@
|
|||||||
{
|
{
|
||||||
var content = new StringContent(BuildOrderWithInvalidExperationTime(), UTF8Encoding.UTF8, "application/json");
|
var content = new StringContent(BuildOrderWithInvalidExperationTime(), UTF8Encoding.UTF8, "application/json");
|
||||||
|
|
||||||
var response = await server.CreateClient()
|
var response = await server.CreateIdempotentClient()
|
||||||
.PostAsync(Post.AddNewOrder, content);
|
.PostAsync(Post.AddNewOrder, content);
|
||||||
|
|
||||||
Assert.True(response.StatusCode == System.Net.HttpStatusCode.BadRequest);
|
Assert.True(response.StatusCode == System.Net.HttpStatusCode.BadRequest);
|
||||||
@ -102,5 +104,5 @@
|
|||||||
|
|
||||||
return JsonConvert.SerializeObject(order);
|
return JsonConvert.SerializeObject(order);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ namespace UnitTest.Ordering.Application
|
|||||||
{
|
{
|
||||||
using MediatR;
|
using MediatR;
|
||||||
using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands;
|
using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands;
|
||||||
using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Repositories;
|
using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Idempotency;
|
||||||
using Moq;
|
using Moq;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate;
|
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate;
|
||||||
|
using Ordering.Domain.Exceptions;
|
||||||
using System;
|
using System;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
@ -82,7 +83,7 @@ public class BuyerAggregateTest
|
|||||||
var expiration = DateTime.Now.AddYears(-1);
|
var expiration = DateTime.Now.AddYears(-1);
|
||||||
|
|
||||||
//Act - Assert
|
//Act - Assert
|
||||||
Assert.Throws<ArgumentException>(() => new PaymentMethod(cardTypeId, alias, cardNumber, securityNumber, cardHolderName, expiration));
|
Assert.Throws<OrderingDomainException>(() => new PaymentMethod(cardTypeId, alias, cardNumber, securityNumber, cardHolderName, expiration));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate;
|
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate;
|
||||||
using Ordering.Domain.Events;
|
using Ordering.Domain.Events;
|
||||||
|
using Ordering.Domain.Exceptions;
|
||||||
using System;
|
using System;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
@ -38,7 +39,7 @@ public class OrderAggregateTest
|
|||||||
var units = -1;
|
var units = -1;
|
||||||
|
|
||||||
//Act - Assert
|
//Act - Assert
|
||||||
Assert.Throws<ArgumentNullException>(() => new OrderItem(productId, productName, unitPrice, discount, pictureUrl, units));
|
Assert.Throws<OrderingDomainException>(() => new OrderItem(productId, productName, unitPrice, discount, pictureUrl, units));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@ -53,7 +54,7 @@ public class OrderAggregateTest
|
|||||||
var units = 1;
|
var units = 1;
|
||||||
|
|
||||||
//Act - Assert
|
//Act - Assert
|
||||||
Assert.Throws<ArgumentException>(() => new OrderItem(productId, productName, unitPrice, discount, pictureUrl, units));
|
Assert.Throws<OrderingDomainException>(() => new OrderItem(productId, productName, unitPrice, discount, pictureUrl, units));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@ -71,7 +72,7 @@ public class OrderAggregateTest
|
|||||||
var fakeOrderItem = new OrderItem(productId, productName, unitPrice, discount, pictureUrl, units);
|
var fakeOrderItem = new OrderItem(productId, productName, unitPrice, discount, pictureUrl, units);
|
||||||
|
|
||||||
//Assert
|
//Assert
|
||||||
Assert.Throws<ArgumentException>(() => fakeOrderItem.SetNewDiscount(-1));
|
Assert.Throws<OrderingDomainException>(() => fakeOrderItem.SetNewDiscount(-1));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@ -89,7 +90,7 @@ public class OrderAggregateTest
|
|||||||
var fakeOrderItem = new OrderItem(productId, productName, unitPrice, discount, pictureUrl, units);
|
var fakeOrderItem = new OrderItem(productId, productName, unitPrice, discount, pictureUrl, units);
|
||||||
|
|
||||||
//Assert
|
//Assert
|
||||||
Assert.Throws<ArgumentException>(() => fakeOrderItem.AddUnits(-1));
|
Assert.Throws<OrderingDomainException>(() => fakeOrderItem.AddUnits(-1));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user