Merge pull request #2 from Espent1004/eventHandlingCustomisation
Event handling customisation
This commit is contained in:
commit
71e52e9f89
@ -7,7 +7,7 @@
|
|||||||
<DockerServiceName>webmvc</DockerServiceName>
|
<DockerServiceName>webmvc</DockerServiceName>
|
||||||
<DockerTargetOS>Linux</DockerTargetOS>
|
<DockerTargetOS>Linux</DockerTargetOS>
|
||||||
<ProjectVersion>2.1</ProjectVersion>
|
<ProjectVersion>2.1</ProjectVersion>
|
||||||
<DockerLaunchAction>LaunchBrowser</DockerLaunchAction>
|
<DockerLaunchAction>None</DockerLaunchAction>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include=".dockerignore" />
|
<None Include=".dockerignore" />
|
||||||
|
@ -59,10 +59,20 @@ services:
|
|||||||
tenantmanager:
|
tenantmanager:
|
||||||
environment:
|
environment:
|
||||||
- ConnectionString=${ESHOP_AZURE_CATALOG_DB:-Server=sql.data;Database=Microsoft.eShopOnContainers.Services.TenantManagerDb;User Id=sa;Password=Pass@word}
|
- ConnectionString=${ESHOP_AZURE_CATALOG_DB:-Server=sql.data;Database=Microsoft.eShopOnContainers.Services.TenantManagerDb;User Id=sa;Password=Pass@word}
|
||||||
|
|
||||||
ports:
|
ports:
|
||||||
- "5115:80"
|
- "5115:80"
|
||||||
|
|
||||||
|
tenantacustomisation:
|
||||||
|
environment:
|
||||||
|
- EventBusConnection=${ESHOP_AZURE_SERVICE_BUS:-rabbitmq}
|
||||||
|
- EventBusUserName=${ESHOP_SERVICE_BUS_USERNAME}
|
||||||
|
- EventBusPassword=${ESHOP_SERVICE_BUS_PASSWORD}
|
||||||
|
- AzureServiceBusEnabled=False
|
||||||
|
- ConnectionString=${ESHOP_AZURE_CATALOG_DB:-Server=sql.data;Database=Microsoft.eShopOnContainers.Services.TenantADb;User Id=sa;Password=Pass@word}
|
||||||
|
|
||||||
|
ports:
|
||||||
|
- "5116:80"
|
||||||
|
|
||||||
basket.api:
|
basket.api:
|
||||||
environment:
|
environment:
|
||||||
- ASPNETCORE_ENVIRONMENT=Development
|
- ASPNETCORE_ENVIRONMENT=Development
|
||||||
|
@ -43,6 +43,14 @@ services:
|
|||||||
depends_on:
|
depends_on:
|
||||||
- sql.data
|
- sql.data
|
||||||
|
|
||||||
|
tenantacustomisation:
|
||||||
|
image: ${REGISTRY:-eshop}/tenantacustomisation:${PLATFORM:-linux}-${TAG:-latest}
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: src/Services/TenantCustomisations/TenantACustomisations/Dockerfile
|
||||||
|
depends_on:
|
||||||
|
- sql.data
|
||||||
|
|
||||||
catalog.api:
|
catalog.api:
|
||||||
image: ${REGISTRY:-eshop}/catalog.api:${PLATFORM:-linux}-${TAG:-latest}
|
image: ${REGISTRY:-eshop}/catalog.api:${PLATFORM:-linux}-${TAG:-latest}
|
||||||
build:
|
build:
|
||||||
|
@ -150,14 +150,14 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Devspace.Support", "Devspac
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Devspaces.Support", "src\BuildingBlocks\Devspaces.Support\Devspaces.Support.csproj", "{56C2EF0B-6BF2-41D9-BE07-6E6D08D06B35}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Devspaces.Support", "src\BuildingBlocks\Devspaces.Support\Devspaces.Support.csproj", "{56C2EF0B-6BF2-41D9-BE07-6E6D08D06B35}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "TenantCustomisations", "TenantCustomisations", "{D2D53ADC-5230-4EF4-95B0-31FD734992F6}"
|
|
||||||
EndProject
|
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TenantACustomisations", "..\TenantACustomisations\TenantACustomisations.csproj", "{6CBF0D7F-7566-428E-B704-4059A10FFD52}"
|
|
||||||
EndProject
|
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "TenantManager", "TenantManager", "{71587505-2945-4286-BF0B-BA4C004B0BA7}"
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "TenantManager", "TenantManager", "{71587505-2945-4286-BF0B-BA4C004B0BA7}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TenantManager", "src\Services\TenantManager\TenantManager\TenantManager.csproj", "{9C101827-119D-44EE-B0F0-94E7ABA8AE6A}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TenantManager", "src\Services\TenantManager\TenantManager\TenantManager.csproj", "{9C101827-119D-44EE-B0F0-94E7ABA8AE6A}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "TenantCustomisations", "TenantCustomisations", "{773A0C2A-CA6F-4D4A-860B-C518EFA6FACB}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TenantACustomisations", "src\Services\TenantCustomisations\TenantACustomisations\TenantACustomisations.csproj", "{76651DAE-FF27-44A4-AF84-34689E2FFDF2}"
|
||||||
|
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
|
||||||
@ -1804,54 +1804,6 @@ Global
|
|||||||
{56C2EF0B-6BF2-41D9-BE07-6E6D08D06B35}.Release|x64.Build.0 = Release|Any CPU
|
{56C2EF0B-6BF2-41D9-BE07-6E6D08D06B35}.Release|x64.Build.0 = Release|Any CPU
|
||||||
{56C2EF0B-6BF2-41D9-BE07-6E6D08D06B35}.Release|x86.ActiveCfg = Release|Any CPU
|
{56C2EF0B-6BF2-41D9-BE07-6E6D08D06B35}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
{56C2EF0B-6BF2-41D9-BE07-6E6D08D06B35}.Release|x86.Build.0 = Release|Any CPU
|
{56C2EF0B-6BF2-41D9-BE07-6E6D08D06B35}.Release|x86.Build.0 = Release|Any CPU
|
||||||
{6CBF0D7F-7566-428E-B704-4059A10FFD52}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{6CBF0D7F-7566-428E-B704-4059A10FFD52}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{6CBF0D7F-7566-428E-B704-4059A10FFD52}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU
|
|
||||||
{6CBF0D7F-7566-428E-B704-4059A10FFD52}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU
|
|
||||||
{6CBF0D7F-7566-428E-B704-4059A10FFD52}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
|
|
||||||
{6CBF0D7F-7566-428E-B704-4059A10FFD52}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
|
|
||||||
{6CBF0D7F-7566-428E-B704-4059A10FFD52}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
|
||||||
{6CBF0D7F-7566-428E-B704-4059A10FFD52}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
|
|
||||||
{6CBF0D7F-7566-428E-B704-4059A10FFD52}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU
|
|
||||||
{6CBF0D7F-7566-428E-B704-4059A10FFD52}.Ad-Hoc|x64.Build.0 = Debug|Any CPU
|
|
||||||
{6CBF0D7F-7566-428E-B704-4059A10FFD52}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU
|
|
||||||
{6CBF0D7F-7566-428E-B704-4059A10FFD52}.Ad-Hoc|x86.Build.0 = Debug|Any CPU
|
|
||||||
{6CBF0D7F-7566-428E-B704-4059A10FFD52}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{6CBF0D7F-7566-428E-B704-4059A10FFD52}.AppStore|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{6CBF0D7F-7566-428E-B704-4059A10FFD52}.AppStore|ARM.ActiveCfg = Debug|Any CPU
|
|
||||||
{6CBF0D7F-7566-428E-B704-4059A10FFD52}.AppStore|ARM.Build.0 = Debug|Any CPU
|
|
||||||
{6CBF0D7F-7566-428E-B704-4059A10FFD52}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
|
|
||||||
{6CBF0D7F-7566-428E-B704-4059A10FFD52}.AppStore|iPhone.Build.0 = Debug|Any CPU
|
|
||||||
{6CBF0D7F-7566-428E-B704-4059A10FFD52}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
|
||||||
{6CBF0D7F-7566-428E-B704-4059A10FFD52}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
|
|
||||||
{6CBF0D7F-7566-428E-B704-4059A10FFD52}.AppStore|x64.ActiveCfg = Debug|Any CPU
|
|
||||||
{6CBF0D7F-7566-428E-B704-4059A10FFD52}.AppStore|x64.Build.0 = Debug|Any CPU
|
|
||||||
{6CBF0D7F-7566-428E-B704-4059A10FFD52}.AppStore|x86.ActiveCfg = Debug|Any CPU
|
|
||||||
{6CBF0D7F-7566-428E-B704-4059A10FFD52}.AppStore|x86.Build.0 = Debug|Any CPU
|
|
||||||
{6CBF0D7F-7566-428E-B704-4059A10FFD52}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{6CBF0D7F-7566-428E-B704-4059A10FFD52}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{6CBF0D7F-7566-428E-B704-4059A10FFD52}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
|
||||||
{6CBF0D7F-7566-428E-B704-4059A10FFD52}.Debug|ARM.Build.0 = Debug|Any CPU
|
|
||||||
{6CBF0D7F-7566-428E-B704-4059A10FFD52}.Debug|iPhone.ActiveCfg = Debug|Any CPU
|
|
||||||
{6CBF0D7F-7566-428E-B704-4059A10FFD52}.Debug|iPhone.Build.0 = Debug|Any CPU
|
|
||||||
{6CBF0D7F-7566-428E-B704-4059A10FFD52}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
|
||||||
{6CBF0D7F-7566-428E-B704-4059A10FFD52}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
|
|
||||||
{6CBF0D7F-7566-428E-B704-4059A10FFD52}.Debug|x64.ActiveCfg = Debug|Any CPU
|
|
||||||
{6CBF0D7F-7566-428E-B704-4059A10FFD52}.Debug|x64.Build.0 = Debug|Any CPU
|
|
||||||
{6CBF0D7F-7566-428E-B704-4059A10FFD52}.Debug|x86.ActiveCfg = Debug|Any CPU
|
|
||||||
{6CBF0D7F-7566-428E-B704-4059A10FFD52}.Debug|x86.Build.0 = Debug|Any CPU
|
|
||||||
{6CBF0D7F-7566-428E-B704-4059A10FFD52}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{6CBF0D7F-7566-428E-B704-4059A10FFD52}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{6CBF0D7F-7566-428E-B704-4059A10FFD52}.Release|ARM.ActiveCfg = Release|Any CPU
|
|
||||||
{6CBF0D7F-7566-428E-B704-4059A10FFD52}.Release|ARM.Build.0 = Release|Any CPU
|
|
||||||
{6CBF0D7F-7566-428E-B704-4059A10FFD52}.Release|iPhone.ActiveCfg = Release|Any CPU
|
|
||||||
{6CBF0D7F-7566-428E-B704-4059A10FFD52}.Release|iPhone.Build.0 = Release|Any CPU
|
|
||||||
{6CBF0D7F-7566-428E-B704-4059A10FFD52}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
|
||||||
{6CBF0D7F-7566-428E-B704-4059A10FFD52}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
|
||||||
{6CBF0D7F-7566-428E-B704-4059A10FFD52}.Release|x64.ActiveCfg = Release|Any CPU
|
|
||||||
{6CBF0D7F-7566-428E-B704-4059A10FFD52}.Release|x64.Build.0 = Release|Any CPU
|
|
||||||
{6CBF0D7F-7566-428E-B704-4059A10FFD52}.Release|x86.ActiveCfg = Release|Any CPU
|
|
||||||
{6CBF0D7F-7566-428E-B704-4059A10FFD52}.Release|x86.Build.0 = Release|Any CPU
|
|
||||||
{9C101827-119D-44EE-B0F0-94E7ABA8AE6A}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
|
{9C101827-119D-44EE-B0F0-94E7ABA8AE6A}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{9C101827-119D-44EE-B0F0-94E7ABA8AE6A}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
|
{9C101827-119D-44EE-B0F0-94E7ABA8AE6A}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{9C101827-119D-44EE-B0F0-94E7ABA8AE6A}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU
|
{9C101827-119D-44EE-B0F0-94E7ABA8AE6A}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU
|
||||||
@ -1900,6 +1852,54 @@ Global
|
|||||||
{9C101827-119D-44EE-B0F0-94E7ABA8AE6A}.Release|x64.Build.0 = Release|Any CPU
|
{9C101827-119D-44EE-B0F0-94E7ABA8AE6A}.Release|x64.Build.0 = Release|Any CPU
|
||||||
{9C101827-119D-44EE-B0F0-94E7ABA8AE6A}.Release|x86.ActiveCfg = Release|Any CPU
|
{9C101827-119D-44EE-B0F0-94E7ABA8AE6A}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
{9C101827-119D-44EE-B0F0-94E7ABA8AE6A}.Release|x86.Build.0 = Release|Any CPU
|
{9C101827-119D-44EE-B0F0-94E7ABA8AE6A}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
{76651DAE-FF27-44A4-AF84-34689E2FFDF2}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{76651DAE-FF27-44A4-AF84-34689E2FFDF2}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{76651DAE-FF27-44A4-AF84-34689E2FFDF2}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU
|
||||||
|
{76651DAE-FF27-44A4-AF84-34689E2FFDF2}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU
|
||||||
|
{76651DAE-FF27-44A4-AF84-34689E2FFDF2}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
|
||||||
|
{76651DAE-FF27-44A4-AF84-34689E2FFDF2}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
|
||||||
|
{76651DAE-FF27-44A4-AF84-34689E2FFDF2}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||||
|
{76651DAE-FF27-44A4-AF84-34689E2FFDF2}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||||
|
{76651DAE-FF27-44A4-AF84-34689E2FFDF2}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{76651DAE-FF27-44A4-AF84-34689E2FFDF2}.Ad-Hoc|x64.Build.0 = Debug|Any CPU
|
||||||
|
{76651DAE-FF27-44A4-AF84-34689E2FFDF2}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{76651DAE-FF27-44A4-AF84-34689E2FFDF2}.Ad-Hoc|x86.Build.0 = Debug|Any CPU
|
||||||
|
{76651DAE-FF27-44A4-AF84-34689E2FFDF2}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{76651DAE-FF27-44A4-AF84-34689E2FFDF2}.AppStore|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{76651DAE-FF27-44A4-AF84-34689E2FFDF2}.AppStore|ARM.ActiveCfg = Debug|Any CPU
|
||||||
|
{76651DAE-FF27-44A4-AF84-34689E2FFDF2}.AppStore|ARM.Build.0 = Debug|Any CPU
|
||||||
|
{76651DAE-FF27-44A4-AF84-34689E2FFDF2}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
|
||||||
|
{76651DAE-FF27-44A4-AF84-34689E2FFDF2}.AppStore|iPhone.Build.0 = Debug|Any CPU
|
||||||
|
{76651DAE-FF27-44A4-AF84-34689E2FFDF2}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||||
|
{76651DAE-FF27-44A4-AF84-34689E2FFDF2}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||||
|
{76651DAE-FF27-44A4-AF84-34689E2FFDF2}.AppStore|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{76651DAE-FF27-44A4-AF84-34689E2FFDF2}.AppStore|x64.Build.0 = Debug|Any CPU
|
||||||
|
{76651DAE-FF27-44A4-AF84-34689E2FFDF2}.AppStore|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{76651DAE-FF27-44A4-AF84-34689E2FFDF2}.AppStore|x86.Build.0 = Debug|Any CPU
|
||||||
|
{76651DAE-FF27-44A4-AF84-34689E2FFDF2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{76651DAE-FF27-44A4-AF84-34689E2FFDF2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{76651DAE-FF27-44A4-AF84-34689E2FFDF2}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||||
|
{76651DAE-FF27-44A4-AF84-34689E2FFDF2}.Debug|ARM.Build.0 = Debug|Any CPU
|
||||||
|
{76651DAE-FF27-44A4-AF84-34689E2FFDF2}.Debug|iPhone.ActiveCfg = Debug|Any CPU
|
||||||
|
{76651DAE-FF27-44A4-AF84-34689E2FFDF2}.Debug|iPhone.Build.0 = Debug|Any CPU
|
||||||
|
{76651DAE-FF27-44A4-AF84-34689E2FFDF2}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
|
||||||
|
{76651DAE-FF27-44A4-AF84-34689E2FFDF2}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
|
||||||
|
{76651DAE-FF27-44A4-AF84-34689E2FFDF2}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{76651DAE-FF27-44A4-AF84-34689E2FFDF2}.Debug|x64.Build.0 = Debug|Any CPU
|
||||||
|
{76651DAE-FF27-44A4-AF84-34689E2FFDF2}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{76651DAE-FF27-44A4-AF84-34689E2FFDF2}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{76651DAE-FF27-44A4-AF84-34689E2FFDF2}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{76651DAE-FF27-44A4-AF84-34689E2FFDF2}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{76651DAE-FF27-44A4-AF84-34689E2FFDF2}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||||
|
{76651DAE-FF27-44A4-AF84-34689E2FFDF2}.Release|ARM.Build.0 = Release|Any CPU
|
||||||
|
{76651DAE-FF27-44A4-AF84-34689E2FFDF2}.Release|iPhone.ActiveCfg = Release|Any CPU
|
||||||
|
{76651DAE-FF27-44A4-AF84-34689E2FFDF2}.Release|iPhone.Build.0 = Release|Any CPU
|
||||||
|
{76651DAE-FF27-44A4-AF84-34689E2FFDF2}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
|
||||||
|
{76651DAE-FF27-44A4-AF84-34689E2FFDF2}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
|
||||||
|
{76651DAE-FF27-44A4-AF84-34689E2FFDF2}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{76651DAE-FF27-44A4-AF84-34689E2FFDF2}.Release|x64.Build.0 = Release|Any CPU
|
||||||
|
{76651DAE-FF27-44A4-AF84-34689E2FFDF2}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{76651DAE-FF27-44A4-AF84-34689E2FFDF2}.Release|x86.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
@ -1966,10 +1966,10 @@ Global
|
|||||||
{766D7E92-6AF0-476C-ADD5-282BF4D8C576} = {E279BF0F-7F66-4F3A-A3AB-2CDA66C1CD04}
|
{766D7E92-6AF0-476C-ADD5-282BF4D8C576} = {E279BF0F-7F66-4F3A-A3AB-2CDA66C1CD04}
|
||||||
{68F5041D-51F2-4630-94B6-B49789F5E51A} = {DB0EFB20-B024-4E5E-A75C-52143C131D25}
|
{68F5041D-51F2-4630-94B6-B49789F5E51A} = {DB0EFB20-B024-4E5E-A75C-52143C131D25}
|
||||||
{56C2EF0B-6BF2-41D9-BE07-6E6D08D06B35} = {68F5041D-51F2-4630-94B6-B49789F5E51A}
|
{56C2EF0B-6BF2-41D9-BE07-6E6D08D06B35} = {68F5041D-51F2-4630-94B6-B49789F5E51A}
|
||||||
{D2D53ADC-5230-4EF4-95B0-31FD734992F6} = {91CF7717-08AB-4E65-B10E-0B426F01E2E8}
|
|
||||||
{6CBF0D7F-7566-428E-B704-4059A10FFD52} = {D2D53ADC-5230-4EF4-95B0-31FD734992F6}
|
|
||||||
{71587505-2945-4286-BF0B-BA4C004B0BA7} = {91CF7717-08AB-4E65-B10E-0B426F01E2E8}
|
{71587505-2945-4286-BF0B-BA4C004B0BA7} = {91CF7717-08AB-4E65-B10E-0B426F01E2E8}
|
||||||
{9C101827-119D-44EE-B0F0-94E7ABA8AE6A} = {71587505-2945-4286-BF0B-BA4C004B0BA7}
|
{9C101827-119D-44EE-B0F0-94E7ABA8AE6A} = {71587505-2945-4286-BF0B-BA4C004B0BA7}
|
||||||
|
{773A0C2A-CA6F-4D4A-860B-C518EFA6FACB} = {91CF7717-08AB-4E65-B10E-0B426F01E2E8}
|
||||||
|
{76651DAE-FF27-44A4-AF84-34689E2FFDF2} = {773A0C2A-CA6F-4D4A-860B-C518EFA6FACB}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
SolutionGuid = {25728519-5F0F-4973-8A64-0A81EB4EA8D9}
|
SolutionGuid = {25728519-5F0F-4973-8A64-0A81EB4EA8D9}
|
||||||
|
@ -0,0 +1,74 @@
|
|||||||
|
using System.Threading.Tasks;
|
||||||
|
using System;
|
||||||
|
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events;
|
||||||
|
using System.Net;
|
||||||
|
using System.IO;
|
||||||
|
using System.Net.Http;
|
||||||
|
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
|
namespace Ordering.API.Application.IntegrationEvents.EventHandling
|
||||||
|
{
|
||||||
|
public abstract class AbstractIntegrationEventHandler<IIntegrationEvent>
|
||||||
|
{
|
||||||
|
private static String url = @"http://tenantmanager/";
|
||||||
|
private readonly IEventBus _eventBus;
|
||||||
|
//private readonly ILogger<AbstractIntegrationEventHandler<IIntegrationEvent>> _logger;
|
||||||
|
|
||||||
|
protected AbstractIntegrationEventHandler(IEventBus eventBus)
|
||||||
|
{
|
||||||
|
_eventBus = eventBus ?? throw new ArgumentNullException(nameof(eventBus));
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> CheckIfCustomised(IntegrationEvent @event)
|
||||||
|
{
|
||||||
|
if (!@event.CheckForCustomisation)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Boolean result = Get(@event);
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
CustomisationEvent customisationEvent = new CustomisationEvent(1, @event);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//_logger.LogInformation("----- Publishing integration event: {IntegrationEventId} from {AppName} - ({@IntegrationEvent})", eventMessage.Id, Program.AppName, eventMessage);
|
||||||
|
_eventBus.Publish(customisationEvent);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
//_logger.LogError(ex, "ERROR Publishing integration event: {IntegrationEventId} from {AppName}", eventMessage.Id, Program.AppName);
|
||||||
|
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Boolean Get(IntegrationEvent @event)
|
||||||
|
{
|
||||||
|
//TODO return true/false
|
||||||
|
Console.WriteLine("Making API Call...");
|
||||||
|
using (var client = new HttpClient(new HttpClientHandler { AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate }))
|
||||||
|
{
|
||||||
|
client.BaseAddress = new Uri(url);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
HttpResponseMessage response = client.GetAsync("api/tenants").Result;
|
||||||
|
response.EnsureSuccessStatusCode();
|
||||||
|
string result = response.Content.ReadAsStringAsync().Result;
|
||||||
|
Console.WriteLine("Result: " + result);
|
||||||
|
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
Console.WriteLine(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -9,4 +9,10 @@
|
|||||||
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
|
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="Microsoft.Extensions.Logging.Abstractions">
|
||||||
|
<HintPath>..\..\..\..\..\..\..\..\..\Program Files\dotnet\sdk\NuGetFallbackFolder\microsoft.extensions.logging.abstractions\2.2.0\lib\netstandard2.0\Microsoft.Extensions.Logging.Abstractions.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
@ -0,0 +1,20 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events
|
||||||
|
{
|
||||||
|
public class CustomisationEvent : IntegrationEvent
|
||||||
|
{
|
||||||
|
public CustomisationEvent(int tenantId, IntegrationEvent @event)
|
||||||
|
{
|
||||||
|
TenantId = tenantId;
|
||||||
|
this.@event = @event;
|
||||||
|
eventType = @event.GetType().Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int TenantId { get; set; }
|
||||||
|
public IntegrationEvent @event { get; set; }
|
||||||
|
public String eventType { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -9,6 +9,16 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events
|
|||||||
{
|
{
|
||||||
Id = Guid.NewGuid();
|
Id = Guid.NewGuid();
|
||||||
CreationDate = DateTime.UtcNow;
|
CreationDate = DateTime.UtcNow;
|
||||||
|
CheckForCustomisation = true;
|
||||||
|
TenantId = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IntegrationEvent(Boolean checkForCustomisation)
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid();
|
||||||
|
CreationDate = DateTime.UtcNow;
|
||||||
|
CheckForCustomisation = checkForCustomisation;
|
||||||
|
TenantId = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
[JsonConstructor]
|
[JsonConstructor]
|
||||||
@ -16,6 +26,7 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events
|
|||||||
{
|
{
|
||||||
Id = id;
|
Id = id;
|
||||||
CreationDate = createDate;
|
CreationDate = createDate;
|
||||||
|
TenantId = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
[JsonProperty]
|
[JsonProperty]
|
||||||
@ -23,5 +34,12 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events
|
|||||||
|
|
||||||
[JsonProperty]
|
[JsonProperty]
|
||||||
public DateTime CreationDate { get; private set; }
|
public DateTime CreationDate { get; private set; }
|
||||||
|
|
||||||
|
[JsonProperty]
|
||||||
|
public Boolean CheckForCustomisation { get; set; }
|
||||||
|
|
||||||
|
//TODO fix this somehow
|
||||||
|
[JsonProperty]
|
||||||
|
public int TenantId { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,9 +12,15 @@ using RabbitMQ.Client;
|
|||||||
using RabbitMQ.Client.Events;
|
using RabbitMQ.Client.Events;
|
||||||
using RabbitMQ.Client.Exceptions;
|
using RabbitMQ.Client.Exceptions;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Net;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Net.Mime;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using System.Web;
|
||||||
|
|
||||||
namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ
|
namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ
|
||||||
{
|
{
|
||||||
@ -27,15 +33,20 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ
|
|||||||
private readonly IEventBusSubscriptionsManager _subsManager;
|
private readonly IEventBusSubscriptionsManager _subsManager;
|
||||||
private readonly ILifetimeScope _autofac;
|
private readonly ILifetimeScope _autofac;
|
||||||
private readonly string AUTOFAC_SCOPE_NAME = "eshop_event_bus";
|
private readonly string AUTOFAC_SCOPE_NAME = "eshop_event_bus";
|
||||||
|
private static readonly String tenantACustomisationUrl = @"http://tenantacustomisation/";
|
||||||
|
private static readonly String tenantManagerUrl = @"http://tenantmanager/";
|
||||||
private readonly int _retryCount;
|
private readonly int _retryCount;
|
||||||
|
|
||||||
|
|
||||||
private IModel _consumerChannel;
|
private IModel _consumerChannel;
|
||||||
private string _queueName;
|
private string _queueName;
|
||||||
|
|
||||||
public EventBusRabbitMQ(IRabbitMQPersistentConnection persistentConnection, ILogger<EventBusRabbitMQ> logger,
|
public EventBusRabbitMQ(IRabbitMQPersistentConnection persistentConnection, ILogger<EventBusRabbitMQ> logger,
|
||||||
ILifetimeScope autofac, IEventBusSubscriptionsManager subsManager, string queueName = null, int retryCount = 5)
|
ILifetimeScope autofac, IEventBusSubscriptionsManager subsManager, string queueName = null,
|
||||||
|
int retryCount = 5)
|
||||||
{
|
{
|
||||||
_persistentConnection = persistentConnection ?? throw new ArgumentNullException(nameof(persistentConnection));
|
_persistentConnection =
|
||||||
|
persistentConnection ?? throw new ArgumentNullException(nameof(persistentConnection));
|
||||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||||
_subsManager = subsManager ?? new InMemoryEventBusSubscriptionsManager();
|
_subsManager = subsManager ?? new InMemoryEventBusSubscriptionsManager();
|
||||||
_queueName = queueName;
|
_queueName = queueName;
|
||||||
@ -75,19 +86,22 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ
|
|||||||
|
|
||||||
var policy = RetryPolicy.Handle<BrokerUnreachableException>()
|
var policy = RetryPolicy.Handle<BrokerUnreachableException>()
|
||||||
.Or<SocketException>()
|
.Or<SocketException>()
|
||||||
.WaitAndRetry(_retryCount, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)), (ex, time) =>
|
.WaitAndRetry(_retryCount, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)),
|
||||||
{
|
(ex, time) =>
|
||||||
_logger.LogWarning(ex, "Could not publish event: {EventId} after {Timeout}s ({ExceptionMessage})", @event.Id, $"{time.TotalSeconds:n1}", ex.Message);
|
{
|
||||||
});
|
_logger.LogWarning(ex,
|
||||||
|
"Could not publish event: {EventId} after {Timeout}s ({ExceptionMessage})", @event.Id,
|
||||||
|
$"{time.TotalSeconds:n1}", ex.Message);
|
||||||
|
});
|
||||||
|
|
||||||
var eventName = @event.GetType().Name;
|
var eventName = @event.GetType().Name;
|
||||||
|
|
||||||
_logger.LogTrace("Creating RabbitMQ channel to publish event: {EventId} ({EventName})", @event.Id, eventName);
|
_logger.LogWarning("Creating RabbitMQ channel to publish event: {EventId} ({EventName})", @event.Id,
|
||||||
|
eventName);
|
||||||
|
|
||||||
using (var channel = _persistentConnection.CreateModel())
|
using (var channel = _persistentConnection.CreateModel())
|
||||||
{
|
{
|
||||||
|
_logger.LogWarning("Declaring RabbitMQ exchange to publish event: {EventId}", @event.Id);
|
||||||
_logger.LogTrace("Declaring RabbitMQ exchange to publish event: {EventId}", @event.Id);
|
|
||||||
|
|
||||||
channel.ExchangeDeclare(exchange: BROKER_NAME, type: "direct");
|
channel.ExchangeDeclare(exchange: BROKER_NAME, type: "direct");
|
||||||
|
|
||||||
@ -99,7 +113,7 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ
|
|||||||
var properties = channel.CreateBasicProperties();
|
var properties = channel.CreateBasicProperties();
|
||||||
properties.DeliveryMode = 2; // persistent
|
properties.DeliveryMode = 2; // persistent
|
||||||
|
|
||||||
_logger.LogTrace("Publishing event to RabbitMQ: {EventId}", @event.Id);
|
_logger.LogWarning("Publishing event to RabbitMQ: {EventId}", @event.Id);
|
||||||
|
|
||||||
channel.BasicPublish(
|
channel.BasicPublish(
|
||||||
exchange: BROKER_NAME,
|
exchange: BROKER_NAME,
|
||||||
@ -114,7 +128,8 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ
|
|||||||
public void SubscribeDynamic<TH>(string eventName)
|
public void SubscribeDynamic<TH>(string eventName)
|
||||||
where TH : IDynamicIntegrationEventHandler
|
where TH : IDynamicIntegrationEventHandler
|
||||||
{
|
{
|
||||||
_logger.LogInformation("Subscribing to dynamic event {EventName} with {EventHandler}", eventName, typeof(TH).GetGenericTypeName());
|
_logger.LogInformation("Subscribing to dynamic event {EventName} with {EventHandler}", eventName,
|
||||||
|
typeof(TH).GetGenericTypeName());
|
||||||
|
|
||||||
DoInternalSubscription(eventName);
|
DoInternalSubscription(eventName);
|
||||||
_subsManager.AddDynamicSubscription<TH>(eventName);
|
_subsManager.AddDynamicSubscription<TH>(eventName);
|
||||||
@ -128,7 +143,8 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ
|
|||||||
var eventName = _subsManager.GetEventKey<T>();
|
var eventName = _subsManager.GetEventKey<T>();
|
||||||
DoInternalSubscription(eventName);
|
DoInternalSubscription(eventName);
|
||||||
|
|
||||||
_logger.LogInformation("Subscribing to event {EventName} with {EventHandler}", eventName, typeof(TH).GetGenericTypeName());
|
_logger.LogInformation("Subscribing to event {EventName} with {EventHandler}", eventName,
|
||||||
|
typeof(TH).GetGenericTypeName());
|
||||||
|
|
||||||
_subsManager.AddSubscription<T, TH>();
|
_subsManager.AddSubscription<T, TH>();
|
||||||
StartBasicConsume();
|
StartBasicConsume();
|
||||||
@ -147,8 +163,8 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ
|
|||||||
using (var channel = _persistentConnection.CreateModel())
|
using (var channel = _persistentConnection.CreateModel())
|
||||||
{
|
{
|
||||||
channel.QueueBind(queue: _queueName,
|
channel.QueueBind(queue: _queueName,
|
||||||
exchange: BROKER_NAME,
|
exchange: BROKER_NAME,
|
||||||
routingKey: eventName);
|
routingKey: eventName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -238,13 +254,13 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ
|
|||||||
var channel = _persistentConnection.CreateModel();
|
var channel = _persistentConnection.CreateModel();
|
||||||
|
|
||||||
channel.ExchangeDeclare(exchange: BROKER_NAME,
|
channel.ExchangeDeclare(exchange: BROKER_NAME,
|
||||||
type: "direct");
|
type: "direct");
|
||||||
|
|
||||||
channel.QueueDeclare(queue: _queueName,
|
channel.QueueDeclare(queue: _queueName,
|
||||||
durable: true,
|
durable: true,
|
||||||
exclusive: false,
|
exclusive: false,
|
||||||
autoDelete: false,
|
autoDelete: false,
|
||||||
arguments: null);
|
arguments: null);
|
||||||
|
|
||||||
channel.CallbackException += (sender, ea) =>
|
channel.CallbackException += (sender, ea) =>
|
||||||
{
|
{
|
||||||
@ -258,9 +274,69 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ
|
|||||||
return channel;
|
return channel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async void SendEventToTenant(String content, String id, String eventName)
|
||||||
|
{
|
||||||
|
var temp = new SavedEvent();
|
||||||
|
temp.Content = content;
|
||||||
|
temp.SavedEventId = id;
|
||||||
|
temp.EventName = eventName;
|
||||||
|
string myJson = JsonConvert.SerializeObject(temp);
|
||||||
|
using (var client = new HttpClient())
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//TODO replace URL with response from tenantmanager
|
||||||
|
var response = await client.PostAsync(
|
||||||
|
tenantACustomisationUrl + "api/SavedEvents",
|
||||||
|
new StringContent(myJson, Encoding.UTF8, "application/json"));
|
||||||
|
response.EnsureSuccessStatusCode();
|
||||||
|
_logger.LogInformation("----- Event sent to tenant{@id} -----", id);
|
||||||
|
}
|
||||||
|
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_logger.LogInformation("----- Exception{@e} -- Event{@id} -----", e, @id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<Boolean> IsEventCustomised(String eventName, int tenantId)
|
||||||
|
{
|
||||||
|
CustomisationInfo customisationInfo = new CustomisationInfo();
|
||||||
|
customisationInfo.EventName = eventName;
|
||||||
|
customisationInfo.TenantId = tenantId;
|
||||||
|
Boolean isCustomised = false;
|
||||||
|
|
||||||
|
var builder = new UriBuilder(tenantManagerUrl + "api/Customisations/IsCustomised");
|
||||||
|
builder.Port = -1;
|
||||||
|
var query = HttpUtility.ParseQueryString(builder.Query);
|
||||||
|
query["eventName"] = eventName;
|
||||||
|
query["tenantId"] = tenantId.ToString();
|
||||||
|
builder.Query = query.ToString();
|
||||||
|
string url = builder.ToString();
|
||||||
|
|
||||||
|
using (var client = new HttpClient())
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var response = await client.GetAsync(
|
||||||
|
url);
|
||||||
|
response.EnsureSuccessStatusCode();
|
||||||
|
isCustomised =
|
||||||
|
JsonConvert.DeserializeObject<Boolean>(response.Content.ReadAsStringAsync().Result);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_logger.LogInformation("----- Exception{@e}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return isCustomised;
|
||||||
|
}
|
||||||
|
|
||||||
private async Task ProcessEvent(string eventName, string message)
|
private async Task ProcessEvent(string eventName, string message)
|
||||||
{
|
{
|
||||||
_logger.LogTrace("Processing RabbitMQ event: {EventName}", eventName);
|
_logger.LogWarning("Processing RabbitMQ event: {EventName}", eventName);
|
||||||
|
|
||||||
if (_subsManager.HasSubscriptionsForEvent(eventName))
|
if (_subsManager.HasSubscriptionsForEvent(eventName))
|
||||||
{
|
{
|
||||||
@ -271,7 +347,9 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ
|
|||||||
{
|
{
|
||||||
if (subscription.IsDynamic)
|
if (subscription.IsDynamic)
|
||||||
{
|
{
|
||||||
var handler = scope.ResolveOptional(subscription.HandlerType) as IDynamicIntegrationEventHandler;
|
//TODO check if it is required here aswell
|
||||||
|
var handler =
|
||||||
|
scope.ResolveOptional(subscription.HandlerType) as IDynamicIntegrationEventHandler;
|
||||||
if (handler == null) continue;
|
if (handler == null) continue;
|
||||||
dynamic eventData = JObject.Parse(message);
|
dynamic eventData = JObject.Parse(message);
|
||||||
|
|
||||||
@ -281,13 +359,25 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
var handler = scope.ResolveOptional(subscription.HandlerType);
|
var handler = scope.ResolveOptional(subscription.HandlerType);
|
||||||
|
|
||||||
if (handler == null) continue;
|
if (handler == null) continue;
|
||||||
var eventType = _subsManager.GetEventTypeByName(eventName);
|
var eventType = _subsManager.GetEventTypeByName(eventName);
|
||||||
var integrationEvent = JsonConvert.DeserializeObject(message, eventType);
|
var integrationEvent = JsonConvert.DeserializeObject(message, eventType);
|
||||||
|
if (integrationEvent is IntegrationEvent evt && IsEventCustomised(eventName, evt.TenantId).Result) //TODO replace with tenantmanager
|
||||||
|
{
|
||||||
|
//Checking if event should be sent to tenant, or handled normally
|
||||||
|
if (evt.CheckForCustomisation)
|
||||||
|
{
|
||||||
|
SendEventToTenant(message, evt.Id.ToString(), eventName);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var concreteType = typeof(IIntegrationEventHandler<>).MakeGenericType(eventType);
|
var concreteType = typeof(IIntegrationEventHandler<>).MakeGenericType(eventType);
|
||||||
|
|
||||||
await Task.Yield();
|
await Task.Yield();
|
||||||
await (Task)concreteType.GetMethod("Handle").Invoke(handler, new object[] { integrationEvent });
|
await (Task) concreteType.GetMethod("Handle")
|
||||||
|
.Invoke(handler, new object[] {integrationEvent});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -299,3 +389,16 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class SavedEvent
|
||||||
|
{
|
||||||
|
public string SavedEventId { get; set; }
|
||||||
|
public string Content { get; set; }
|
||||||
|
public String EventName { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
class CustomisationInfo
|
||||||
|
{
|
||||||
|
public string EventName { get; set; }
|
||||||
|
public int TenantId { get; set; }
|
||||||
|
}
|
@ -15,14 +15,16 @@ namespace Ordering.API.Application.IntegrationEvents.EventHandling
|
|||||||
public class UserCheckoutAcceptedIntegrationEventHandler : IIntegrationEventHandler<UserCheckoutAcceptedIntegrationEvent>
|
public class UserCheckoutAcceptedIntegrationEventHandler : IIntegrationEventHandler<UserCheckoutAcceptedIntegrationEvent>
|
||||||
{
|
{
|
||||||
private readonly IMediator _mediator;
|
private readonly IMediator _mediator;
|
||||||
|
private readonly IEventBus _eventBus;
|
||||||
private readonly ILogger<UserCheckoutAcceptedIntegrationEventHandler> _logger;
|
private readonly ILogger<UserCheckoutAcceptedIntegrationEventHandler> _logger;
|
||||||
|
|
||||||
public UserCheckoutAcceptedIntegrationEventHandler(
|
public UserCheckoutAcceptedIntegrationEventHandler(
|
||||||
IMediator mediator,
|
IMediator mediator,
|
||||||
ILogger<UserCheckoutAcceptedIntegrationEventHandler> logger)
|
ILogger<UserCheckoutAcceptedIntegrationEventHandler> logger, IEventBus eventBus)
|
||||||
{
|
{
|
||||||
_mediator = mediator ?? throw new ArgumentNullException(nameof(mediator));
|
_mediator = mediator ?? throw new ArgumentNullException(nameof(mediator));
|
||||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||||
|
_eventBus = eventBus ?? throw new ArgumentNullException(nameof(eventBus));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -40,42 +42,46 @@ namespace Ordering.API.Application.IntegrationEvents.EventHandling
|
|||||||
{
|
{
|
||||||
_logger.LogInformation("----- Handling integration event: {IntegrationEventId} at {AppName} - ({@IntegrationEvent})", @event.Id, Program.AppName, @event);
|
_logger.LogInformation("----- Handling integration event: {IntegrationEventId} at {AppName} - ({@IntegrationEvent})", @event.Id, Program.AppName, @event);
|
||||||
|
|
||||||
var result = false;
|
//var customised = await CheckIfCustomised(@event);
|
||||||
|
//if (!customised)
|
||||||
|
//{
|
||||||
|
var result = false;
|
||||||
|
|
||||||
if (@event.RequestId != Guid.Empty)
|
if (@event.RequestId != Guid.Empty)
|
||||||
{
|
|
||||||
using (LogContext.PushProperty("IdentifiedCommandId", @event.RequestId))
|
|
||||||
{
|
{
|
||||||
var createOrderCommand = new CreateOrderCommand(@event.Basket.Items, @event.UserId, @event.UserName, @event.City, @event.Street,
|
using (LogContext.PushProperty("IdentifiedCommandId", @event.RequestId))
|
||||||
@event.State, @event.Country, @event.ZipCode,
|
|
||||||
@event.CardNumber, @event.CardHolderName, @event.CardExpiration,
|
|
||||||
@event.CardSecurityNumber, @event.CardTypeId);
|
|
||||||
|
|
||||||
var requestCreateOrder = new IdentifiedCommand<CreateOrderCommand, bool>(createOrderCommand, @event.RequestId);
|
|
||||||
|
|
||||||
_logger.LogInformation(
|
|
||||||
"----- Sending command: {CommandName} - {IdProperty}: {CommandId} ({@Command})",
|
|
||||||
requestCreateOrder.GetGenericTypeName(),
|
|
||||||
nameof(requestCreateOrder.Id),
|
|
||||||
requestCreateOrder.Id,
|
|
||||||
requestCreateOrder);
|
|
||||||
|
|
||||||
result = await _mediator.Send(requestCreateOrder);
|
|
||||||
|
|
||||||
if (result)
|
|
||||||
{
|
{
|
||||||
_logger.LogInformation("----- CreateOrderCommand suceeded - RequestId: {RequestId}", @event.RequestId);
|
var createOrderCommand = new CreateOrderCommand(@event.Basket.Items, @event.UserId, @event.UserName, @event.City, @event.Street,
|
||||||
}
|
@event.State, @event.Country, @event.ZipCode,
|
||||||
else
|
@event.CardNumber, @event.CardHolderName, @event.CardExpiration,
|
||||||
{
|
@event.CardSecurityNumber, @event.CardTypeId);
|
||||||
_logger.LogWarning("CreateOrderCommand failed - RequestId: {RequestId}", @event.RequestId);
|
|
||||||
|
var requestCreateOrder = new IdentifiedCommand<CreateOrderCommand, bool>(createOrderCommand, @event.RequestId);
|
||||||
|
|
||||||
|
_logger.LogInformation(
|
||||||
|
"----- Sending command: {CommandName} - {IdProperty}: {CommandId} ({@Command})",
|
||||||
|
requestCreateOrder.GetGenericTypeName(),
|
||||||
|
nameof(requestCreateOrder.Id),
|
||||||
|
requestCreateOrder.Id,
|
||||||
|
requestCreateOrder);
|
||||||
|
|
||||||
|
result = await _mediator.Send(requestCreateOrder);
|
||||||
|
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
_logger.LogInformation("----- CreateOrderCommand suceeded - RequestId: {RequestId}", @event.RequestId);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.LogWarning("CreateOrderCommand failed - RequestId: {RequestId}", @event.RequestId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
else
|
{
|
||||||
{
|
_logger.LogWarning("Invalid IntegrationEvent - RequestId is missing - {@IntegrationEvent}", @event);
|
||||||
_logger.LogWarning("Invalid IntegrationEvent - RequestId is missing - {@IntegrationEvent}", @event);
|
}
|
||||||
}
|
//}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,183 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
|
||||||
|
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using TenantACustomisations.Database;
|
||||||
|
using TenantACustomisations.IntegrationEvents.Events;
|
||||||
|
|
||||||
|
namespace TenantACustomisations.Controllers
|
||||||
|
{
|
||||||
|
[Route("api/[controller]")]
|
||||||
|
[ApiController]
|
||||||
|
public class SavedEventsController : ControllerBase
|
||||||
|
{
|
||||||
|
private readonly TenantAContext _context;
|
||||||
|
private readonly ILogger<SavedEventsController> _logger;
|
||||||
|
private readonly IEventBus _eventBus;
|
||||||
|
|
||||||
|
private List<Type> types = new List<Type>()
|
||||||
|
{
|
||||||
|
typeof(OrderStatusChangedToSubmittedIntegrationEvent),
|
||||||
|
typeof(OrderStatusChangedToAwaitingValidationIntegrationEvent)
|
||||||
|
};
|
||||||
|
|
||||||
|
public SavedEventsController(TenantAContext context, ILogger<SavedEventsController> logger, IEventBus eventBus)
|
||||||
|
{
|
||||||
|
_context = context;
|
||||||
|
_logger = logger;
|
||||||
|
_eventBus = eventBus;
|
||||||
|
}
|
||||||
|
|
||||||
|
// GET: api/SavedEvents
|
||||||
|
[HttpGet]
|
||||||
|
public async Task<ActionResult<IEnumerable<SavedEvent>>> GetSavedEvent(String orderId)
|
||||||
|
{
|
||||||
|
if (String.IsNullOrEmpty(orderId))
|
||||||
|
{
|
||||||
|
return await _context.SavedEvent.ToListAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
//Getting saved events
|
||||||
|
var savedEvents = await _context.SavedEvent.ToListAsync();
|
||||||
|
|
||||||
|
//Returning if list is empty
|
||||||
|
if (savedEvents.Count == 0)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
List<IntegrationEvent> events = new List<IntegrationEvent>();
|
||||||
|
|
||||||
|
//Converting events to actual type
|
||||||
|
savedEvents.ForEach(e =>
|
||||||
|
{
|
||||||
|
var integrationEvent =JsonConvert.DeserializeObject(e.Content, GetEventTypeByName(e.EventName));
|
||||||
|
IntegrationEvent evt = (IntegrationEvent)integrationEvent;
|
||||||
|
events.Add(evt);
|
||||||
|
});
|
||||||
|
|
||||||
|
bool found = false;
|
||||||
|
//Casting to class to check the orderId
|
||||||
|
events.ForEach(e =>
|
||||||
|
{
|
||||||
|
if(e is OrderStatusChangedToAwaitingValidationIntegrationEvent)
|
||||||
|
{
|
||||||
|
OrderStatusChangedToAwaitingValidationIntegrationEvent evt = (OrderStatusChangedToAwaitingValidationIntegrationEvent)e;
|
||||||
|
if (evt.OrderId == Int32.Parse(orderId))
|
||||||
|
{
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(e is OrderStatusChangedToSubmittedIntegrationEvent)
|
||||||
|
{
|
||||||
|
OrderStatusChangedToSubmittedIntegrationEvent evt = (OrderStatusChangedToSubmittedIntegrationEvent)e;
|
||||||
|
if (evt.OrderId == Int32.Parse(orderId))
|
||||||
|
{
|
||||||
|
found = true;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!found)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
return savedEvents;
|
||||||
|
}
|
||||||
|
|
||||||
|
// PUT: api/SavedEvents/5
|
||||||
|
[HttpPut("{id}")]
|
||||||
|
public async Task<IActionResult> PutSavedEvent(string id, SavedEvent savedEvent)
|
||||||
|
{
|
||||||
|
if (id != savedEvent.SavedEventId)
|
||||||
|
{
|
||||||
|
return BadRequest();
|
||||||
|
}
|
||||||
|
|
||||||
|
_context.Entry(savedEvent).State = EntityState.Modified;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
catch (DbUpdateConcurrencyException)
|
||||||
|
{
|
||||||
|
if (!SavedEventExists(id))
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NoContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
// POST: api/SavedEvents
|
||||||
|
[HttpPost]
|
||||||
|
public async Task<ActionResult<SavedEvent>> PostSavedEvent(SavedEvent savedEvent)
|
||||||
|
{
|
||||||
|
_context.SavedEvent.Add(savedEvent);
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
|
||||||
|
return CreatedAtAction("GetSavedEvent", new {id = savedEvent.SavedEventId}, savedEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
// DELETE: api/SavedEvents/5
|
||||||
|
[HttpDelete("{id}")]
|
||||||
|
public async Task<ActionResult<SavedEvent>> DeleteSavedEvent(string id)
|
||||||
|
{
|
||||||
|
var savedEvent = await _context.SavedEvent.FindAsync(id);
|
||||||
|
if (savedEvent == null)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
var integrationEvent =
|
||||||
|
JsonConvert.DeserializeObject(savedEvent.Content, GetEventTypeByName(savedEvent.EventName));
|
||||||
|
IntegrationEvent evt = (IntegrationEvent) integrationEvent;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_logger.LogInformation(
|
||||||
|
"----- Publishing integration event: {IntegrationEventId} from OrderStatusChangedToSubmittedIntegrationEventsController - ({@IntegrationEvent})",
|
||||||
|
evt.Id, evt);
|
||||||
|
evt.CheckForCustomisation = false;
|
||||||
|
_eventBus.Publish(evt);
|
||||||
|
_context.SavedEvent.Remove(savedEvent);
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
return savedEvent;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex,
|
||||||
|
"ERROR Publishing integration event: {IntegrationEventId} from OrderStatusChangedToSubmittedIntegrationEventsController",
|
||||||
|
evt.Id);
|
||||||
|
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
_context.SavedEvent.Remove(savedEvent);
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
|
||||||
|
return savedEvent;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool SavedEventExists(string id)
|
||||||
|
{
|
||||||
|
return _context.SavedEvent.Any(e => e.SavedEventId == id);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Type GetEventTypeByName(string eventName) => types.SingleOrDefault(t => t.Name == eventName);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,106 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using TenantACustomisations.Database;
|
||||||
|
using TenantACustomisations.ExternalServices;
|
||||||
|
|
||||||
|
namespace TenantACustomisations.Controllers
|
||||||
|
{
|
||||||
|
[Route("api/[controller]")]
|
||||||
|
[ApiController]
|
||||||
|
public class ShippingInformationsController : ControllerBase
|
||||||
|
{
|
||||||
|
private readonly TenantAContext _context;
|
||||||
|
|
||||||
|
public ShippingInformationsController(TenantAContext context)
|
||||||
|
{
|
||||||
|
_context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
// GET: api/ShippingInformations
|
||||||
|
[HttpGet]
|
||||||
|
public async Task<ActionResult<IEnumerable<ShippingInformation>>> GetShippingInformation()
|
||||||
|
{
|
||||||
|
return await _context.ShippingInformation.ToListAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
// GET: api/ShippingInformations/5
|
||||||
|
[HttpGet("{id}")]
|
||||||
|
public async Task<ActionResult<ShippingInformation>> GetShippingInformation(int id)
|
||||||
|
{
|
||||||
|
var shippingInformation = await _context.ShippingInformation.FindAsync(id);
|
||||||
|
|
||||||
|
if (shippingInformation == null)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
return shippingInformation;
|
||||||
|
}
|
||||||
|
|
||||||
|
// PUT: api/ShippingInformations/5
|
||||||
|
[HttpPut("{id}")]
|
||||||
|
public async Task<IActionResult> PutShippingInformation(int id, ShippingInformation shippingInformation)
|
||||||
|
{
|
||||||
|
if (id != shippingInformation.ShippingInformationId)
|
||||||
|
{
|
||||||
|
return BadRequest();
|
||||||
|
}
|
||||||
|
|
||||||
|
_context.Entry(shippingInformation).State = EntityState.Modified;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
catch (DbUpdateConcurrencyException)
|
||||||
|
{
|
||||||
|
if (!ShippingInformationExists(id))
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NoContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
// POST: api/ShippingInformations
|
||||||
|
[HttpPost]
|
||||||
|
public async Task<ActionResult<ShippingInformation>> PostShippingInformation(ShippingInformation shippingInformation)
|
||||||
|
{
|
||||||
|
_context.ShippingInformation.Add(shippingInformation);
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
|
||||||
|
return CreatedAtAction("GetShippingInformation", new { id = shippingInformation.ShippingInformationId }, shippingInformation);
|
||||||
|
}
|
||||||
|
|
||||||
|
// DELETE: api/ShippingInformations/5
|
||||||
|
[HttpDelete("{id}")]
|
||||||
|
public async Task<ActionResult<ShippingInformation>> DeleteShippingInformation(int id)
|
||||||
|
{
|
||||||
|
var shippingInformation = await _context.ShippingInformation.FindAsync(id);
|
||||||
|
if (shippingInformation == null)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
_context.ShippingInformation.Remove(shippingInformation);
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
|
||||||
|
return shippingInformation;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool ShippingInformationExists(int id)
|
||||||
|
{
|
||||||
|
return _context.ShippingInformation.Any(e => e.ShippingInformationId == id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,58 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using TenantACustomisations.Database;
|
||||||
|
using TenantACustomisations.ExternalServices;
|
||||||
|
|
||||||
|
namespace TenantACustomisations.Controllers
|
||||||
|
{
|
||||||
|
[Route("api/[controller]")]
|
||||||
|
[ApiController]
|
||||||
|
public class ValuesController : ControllerBase
|
||||||
|
{
|
||||||
|
|
||||||
|
private readonly TenantAContext _context;
|
||||||
|
|
||||||
|
public ValuesController(TenantAContext context)
|
||||||
|
{
|
||||||
|
_context = context ?? throw new ArgumentNullException(nameof(context));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// GET api/values
|
||||||
|
[HttpGet]
|
||||||
|
public async Task<ActionResult<IEnumerable<ShippingInformation>>> GetShippingInformation()
|
||||||
|
{
|
||||||
|
return await _context.ShippingInformation.ToListAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
// GET api/values/5
|
||||||
|
[HttpGet("{id}")]
|
||||||
|
public ActionResult<string> Get(int id)
|
||||||
|
{
|
||||||
|
return "value";
|
||||||
|
}
|
||||||
|
|
||||||
|
// POST api/values
|
||||||
|
[HttpPost]
|
||||||
|
public void Post([FromBody] string value)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// PUT api/values/5
|
||||||
|
[HttpPut("{id}")]
|
||||||
|
public void Put(int id, [FromBody] string value)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// DELETE api/values/5
|
||||||
|
[HttpDelete("{id}")]
|
||||||
|
public void Delete(int id)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using TenantACustomisations.ExternalServices;
|
||||||
|
|
||||||
|
namespace TenantACustomisations.Database
|
||||||
|
{
|
||||||
|
public class DbInitializer
|
||||||
|
{
|
||||||
|
public void Initialize(TenantAContext context)
|
||||||
|
{
|
||||||
|
context.Database.EnsureCreated();
|
||||||
|
|
||||||
|
if (context.ShippingInformation.Any())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ShippingInformation shippingInformation = new ShippingInformation();
|
||||||
|
shippingInformation.ShippingTime = DateTime.Today;
|
||||||
|
shippingInformation.ArrivalTime = DateTime.Today.AddDays(2);
|
||||||
|
shippingInformation.FragilityLevel = Fragility.Medium;
|
||||||
|
shippingInformation.PriorityLevel = Priority.High;
|
||||||
|
shippingInformation.ShippingInformationId = 1;
|
||||||
|
shippingInformation.OrderNumber = "1";
|
||||||
|
context.ShippingInformation.Add(shippingInformation);
|
||||||
|
|
||||||
|
context.SaveChanges();
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace TenantACustomisations.Database
|
||||||
|
{
|
||||||
|
public class SavedEvent
|
||||||
|
{
|
||||||
|
public string SavedEventId { get; set; }
|
||||||
|
public string Content { get; set; }
|
||||||
|
public String EventName { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Design;
|
||||||
|
using TenantACustomisations.ExternalServices;
|
||||||
|
using TenantACustomisations.IntegrationEvents.Events;
|
||||||
|
|
||||||
|
namespace TenantACustomisations.Database
|
||||||
|
{
|
||||||
|
public class TenantAContext : DbContext
|
||||||
|
{
|
||||||
|
public TenantAContext(DbContextOptions<TenantAContext> options)
|
||||||
|
: base(options)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public DbSet<ShippingInformation> ShippingInformation { get; set; }
|
||||||
|
|
||||||
|
public DbSet<SavedEvent> SavedEvent
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
set;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
public class TenantAContextDesignFactory : IDesignTimeDbContextFactory<TenantAContext>
|
||||||
|
{
|
||||||
|
public TenantAContext CreateDbContext(string[] args)
|
||||||
|
{
|
||||||
|
var optionsBuilder = new DbContextOptionsBuilder<TenantAContext>()
|
||||||
|
.UseSqlServer("Server=.;Initial Catalog=Microsoft.eShopOnContainers.Services.TenantADb;Integrated Security=true");
|
||||||
|
|
||||||
|
return new TenantAContext(optionsBuilder.Options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,59 @@
|
|||||||
|
FROM mcr.microsoft.com/dotnet/core/aspnet:2.2-stretch-slim AS base
|
||||||
|
WORKDIR /app
|
||||||
|
EXPOSE 80
|
||||||
|
|
||||||
|
FROM mcr.microsoft.com/dotnet/core/sdk:2.2-stretch AS build
|
||||||
|
WORKDIR /src
|
||||||
|
|
||||||
|
# Keep the project list and command dotnet restore identical in all Dockfiles to maximize image cache utilization
|
||||||
|
COPY eShopOnContainers-ServicesAndWebApps.sln .
|
||||||
|
COPY docker-compose.dcproj /src/
|
||||||
|
COPY src/ApiGateways/ApiGw-Base/OcelotApiGw.csproj src/ApiGateways/ApiGw-Base/
|
||||||
|
COPY src/ApiGateways/Mobile.Bff.Shopping/aggregator/Mobile.Shopping.HttpAggregator.csproj src/ApiGateways/Mobile.Bff.Shopping/aggregator/
|
||||||
|
COPY src/ApiGateways/Web.Bff.Shopping/aggregator/Web.Shopping.HttpAggregator.csproj src/ApiGateways/Web.Bff.Shopping/aggregator/
|
||||||
|
COPY src/BuildingBlocks/Devspaces.Support/Devspaces.Support.csproj src/BuildingBlocks/Devspaces.Support/
|
||||||
|
COPY src/BuildingBlocks/EventBus/EventBus/EventBus.csproj src/BuildingBlocks/EventBus/EventBus/
|
||||||
|
COPY src/BuildingBlocks/EventBus/EventBus.Tests/EventBus.Tests.csproj src/BuildingBlocks/EventBus/EventBus.Tests/
|
||||||
|
COPY src/BuildingBlocks/EventBus/EventBusRabbitMQ/EventBusRabbitMQ.csproj src/BuildingBlocks/EventBus/EventBusRabbitMQ/
|
||||||
|
COPY src/BuildingBlocks/EventBus/EventBusServiceBus/EventBusServiceBus.csproj src/BuildingBlocks/EventBus/EventBusServiceBus/
|
||||||
|
COPY src/BuildingBlocks/EventBus/IntegrationEventLogEF/IntegrationEventLogEF.csproj src/BuildingBlocks/EventBus/IntegrationEventLogEF/
|
||||||
|
COPY src/BuildingBlocks/WebHostCustomization/WebHost.Customization/WebHost.Customization.csproj src/BuildingBlocks/WebHostCustomization/WebHost.Customization/
|
||||||
|
COPY src/Services/Basket/Basket.API/Basket.API.csproj src/Services/Basket/Basket.API/
|
||||||
|
COPY src/Services/Basket/Basket.FunctionalTests/Basket.FunctionalTests.csproj src/Services/Basket/Basket.FunctionalTests/
|
||||||
|
COPY src/Services/Basket/Basket.UnitTests/Basket.UnitTests.csproj src/Services/Basket/Basket.UnitTests/
|
||||||
|
COPY src/Services/Catalog/Catalog.API/Catalog.API.csproj src/Services/Catalog/Catalog.API/
|
||||||
|
COPY src/Services/Catalog/Catalog.FunctionalTests/Catalog.FunctionalTests.csproj src/Services/Catalog/Catalog.FunctionalTests/
|
||||||
|
COPY src/Services/Catalog/Catalog.UnitTests/Catalog.UnitTests.csproj src/Services/Catalog/Catalog.UnitTests/
|
||||||
|
COPY src/Services/Identity/Identity.API/Identity.API.csproj src/Services/Identity/Identity.API/
|
||||||
|
COPY src/Services/Location/Locations.API/Locations.API.csproj src/Services/Location/Locations.API/
|
||||||
|
COPY src/Services/Location/Locations.FunctionalTests/Locations.FunctionalTests.csproj src/Services/Location/Locations.FunctionalTests/
|
||||||
|
COPY src/Services/Marketing/Marketing.API/Marketing.API.csproj src/Services/Marketing/Marketing.API/
|
||||||
|
COPY src/Services/Marketing/Marketing.FunctionalTests/Marketing.FunctionalTests.csproj src/Services/Marketing/Marketing.FunctionalTests/
|
||||||
|
COPY src/Services/Ordering/Ordering.API/Ordering.API.csproj src/Services/Ordering/Ordering.API/
|
||||||
|
COPY src/Services/Ordering/Ordering.BackgroundTasks/Ordering.BackgroundTasks.csproj src/Services/Ordering/Ordering.BackgroundTasks/
|
||||||
|
COPY src/Services/Ordering/Ordering.Domain/Ordering.Domain.csproj src/Services/Ordering/Ordering.Domain/
|
||||||
|
COPY src/Services/Ordering/Ordering.FunctionalTests/Ordering.FunctionalTests.csproj src/Services/Ordering/Ordering.FunctionalTests/
|
||||||
|
COPY src/Services/Ordering/Ordering.Infrastructure/Ordering.Infrastructure.csproj src/Services/Ordering/Ordering.Infrastructure/
|
||||||
|
COPY src/Services/Ordering/Ordering.SignalrHub/Ordering.SignalrHub.csproj src/Services/Ordering/Ordering.SignalrHub/
|
||||||
|
COPY src/Services/Ordering/Ordering.UnitTests/Ordering.UnitTests.csproj src/Services/Ordering/Ordering.UnitTests/
|
||||||
|
COPY src/Services/Payment/Payment.API/Payment.API.csproj src/Services/Payment/Payment.API/
|
||||||
|
COPY src/Services/Webhooks/Webhooks.API/Webhooks.API.csproj src/Services/Webhooks/Webhooks.API/
|
||||||
|
COPY src/Web/WebhookClient/WebhookClient.csproj src/Web/WebhookClient/
|
||||||
|
COPY src/Web/WebMVC/WebMVC.csproj src/Web/WebMVC/
|
||||||
|
COPY src/Web/WebSPA/WebSPA.csproj src/Web/WebSPA/
|
||||||
|
COPY src/Web/WebStatus/WebStatus.csproj src/Web/WebStatus/
|
||||||
|
COPY test/ServicesTests/Application.FunctionalTests/Application.FunctionalTests.csproj test/ServicesTests/Application.FunctionalTests/
|
||||||
|
COPY test/ServicesTests/LoadTest/LoadTest.csproj test/ServicesTests/LoadTest/
|
||||||
|
|
||||||
|
RUN dotnet restore eShopOnContainers-ServicesAndWebApps.sln
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
WORKDIR /src/src/Services/TenantCustomisations/TenantACustomisations
|
||||||
|
RUN dotnet publish --no-restore -c Release -o /app
|
||||||
|
|
||||||
|
FROM build AS publish
|
||||||
|
|
||||||
|
FROM base AS final
|
||||||
|
WORKDIR /app
|
||||||
|
COPY --from=publish /app .
|
||||||
|
ENTRYPOINT ["dotnet", "TenantACustomisations.dll"]
|
@ -0,0 +1,12 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace TenantACustomisations.ExternalServices
|
||||||
|
{
|
||||||
|
public interface IRFIDService
|
||||||
|
{
|
||||||
|
bool IsOrderRFIDTagged(int orderNumber);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
using Ordering.API.Application.Models;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace TenantACustomisations.ExternalServices
|
||||||
|
{
|
||||||
|
public interface IShippingService
|
||||||
|
{
|
||||||
|
ShippingInformation CalculateShippingInformation(int orderId);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Ordering.API.Application.Models;
|
||||||
|
|
||||||
|
namespace TenantACustomisations.ExternalServices
|
||||||
|
{
|
||||||
|
public class MockedShippingService : IShippingService
|
||||||
|
{
|
||||||
|
public ShippingInformation CalculateShippingInformation(int orderId)
|
||||||
|
{
|
||||||
|
ShippingInformation shippingInformation = new ShippingInformation();
|
||||||
|
shippingInformation.ShippingTime = DateTime.Today;
|
||||||
|
shippingInformation.ArrivalTime = DateTime.Today.AddDays(2);
|
||||||
|
shippingInformation.FragilityLevel = Fragility.Medium;
|
||||||
|
shippingInformation.PriorityLevel = Priority.High;
|
||||||
|
shippingInformation.OrderNumber = orderId.ToString();
|
||||||
|
|
||||||
|
return shippingInformation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace TenantACustomisations.ExternalServices
|
||||||
|
{
|
||||||
|
public enum Fragility
|
||||||
|
{
|
||||||
|
Low, Medium, High
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace TenantACustomisations.ExternalServices
|
||||||
|
{
|
||||||
|
public enum Priority
|
||||||
|
{
|
||||||
|
Low, Medium, High
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace TenantACustomisations.ExternalServices
|
||||||
|
{
|
||||||
|
public class ShippingInformation
|
||||||
|
{
|
||||||
|
public int ShippingInformationId { get; set; }
|
||||||
|
public DateTime ArrivalTime { get; set; }
|
||||||
|
public DateTime ShippingTime { get; set; }
|
||||||
|
public Priority PriorityLevel {get;set;}
|
||||||
|
public Fragility FragilityLevel { get; set; }
|
||||||
|
public String OrderNumber { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
using Autofac;
|
||||||
|
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
|
||||||
|
using System.Reflection;
|
||||||
|
using TenantACustomisations.ExternalServices;
|
||||||
|
using TenantACustomisations.IntegrationEvents.Events;
|
||||||
|
|
||||||
|
namespace Microsoft.eShopOnContainers.Services.TenantACustomisations.Infrastructure.AutofacModules
|
||||||
|
{
|
||||||
|
|
||||||
|
public class ApplicationModule
|
||||||
|
:Autofac.Module
|
||||||
|
{
|
||||||
|
|
||||||
|
public string QueriesConnectionString { get; }
|
||||||
|
|
||||||
|
public ApplicationModule(string qconstr)
|
||||||
|
{
|
||||||
|
QueriesConnectionString = qconstr;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Load(ContainerBuilder builder)
|
||||||
|
{
|
||||||
|
builder.RegisterAssemblyTypes(typeof(UserCheckoutAcceptedIntegrationEvent).GetTypeInfo().Assembly)
|
||||||
|
.AsClosedTypesOf(typeof(IIntegrationEventHandler<>));
|
||||||
|
|
||||||
|
|
||||||
|
builder.RegisterType<MockedShippingService>()
|
||||||
|
.As<IShippingService>()
|
||||||
|
.InstancePerLifetimeScope();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
using Autofac;
|
||||||
|
|
||||||
|
namespace Microsoft.eShopOnContainers.Services.TenantACustomisations.Infrastructure.AutofacModules
|
||||||
|
{
|
||||||
|
public class MediatorModule : Autofac.Module
|
||||||
|
{
|
||||||
|
protected override void Load(ContainerBuilder builder)
|
||||||
|
{
|
||||||
|
//TODO
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Swashbuckle.AspNetCore.Swagger;
|
||||||
|
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace TenantACustomisations.Infrastructure.Filters
|
||||||
|
{
|
||||||
|
public class AuthorizeCheckOperationFilter : IOperationFilter
|
||||||
|
{
|
||||||
|
public void Apply(Operation operation, OperationFilterContext context)
|
||||||
|
{
|
||||||
|
// Check for authorize attribute
|
||||||
|
var hasAuthorize = context.MethodInfo.DeclaringType.GetCustomAttributes(true).OfType<AuthorizeAttribute>().Any() ||
|
||||||
|
context.MethodInfo.GetCustomAttributes(true).OfType<AuthorizeAttribute>().Any();
|
||||||
|
|
||||||
|
if (!hasAuthorize) return;
|
||||||
|
|
||||||
|
operation.Responses.TryAdd("401", new Response { Description = "Unauthorized" });
|
||||||
|
operation.Responses.TryAdd("403", new Response { Description = "Forbidden" });
|
||||||
|
|
||||||
|
operation.Security = new List<IDictionary<string, IEnumerable<string>>>
|
||||||
|
{
|
||||||
|
new Dictionary<string, IEnumerable<string>>
|
||||||
|
{
|
||||||
|
{ "oauth2", new [] { "orderingapi" } }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,69 @@
|
|||||||
|
namespace Microsoft.eShopOnContainers.Services.TenantACustomisations.Infrastructure.Filters
|
||||||
|
{
|
||||||
|
using AspNetCore.Mvc;
|
||||||
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Mvc.Filters;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using System.Net;
|
||||||
|
|
||||||
|
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 (1==2)//TODO
|
||||||
|
{
|
||||||
|
var problemDetails = new ValidationProblemDetails()
|
||||||
|
{
|
||||||
|
Instance = context.HttpContext.Request.Path,
|
||||||
|
Status = StatusCodes.Status400BadRequest,
|
||||||
|
Detail = "Please refer to the errors property for additional details."
|
||||||
|
};
|
||||||
|
|
||||||
|
problemDetails.Errors.Add("DomainValidations", new string[] { context.Exception.Message.ToString() });
|
||||||
|
|
||||||
|
context.Result = new BadRequestObjectResult(problemDetails);
|
||||||
|
context.HttpContext.Response.StatusCode = (int)HttpStatusCode.BadRequest;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var json = new JsonErrorResponse
|
||||||
|
{
|
||||||
|
Messages = new[] { "An error occur.Try it again." }
|
||||||
|
};
|
||||||
|
|
||||||
|
if (env.IsDevelopment())
|
||||||
|
{
|
||||||
|
json.DeveloperMessage = 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
|
||||||
|
//TODO
|
||||||
|
//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 DeveloperMessage { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,49 @@
|
|||||||
|
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
|
||||||
|
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using Ordering.API.Application.IntegrationEvents.Events;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using TenantACustomisations.Services;
|
||||||
|
|
||||||
|
namespace TenantACustomisations.IntegrationEvents.EventHandling
|
||||||
|
{
|
||||||
|
public class CustomisationEventHandler : IIntegrationEventHandler<CustomisationEvent>
|
||||||
|
{
|
||||||
|
|
||||||
|
private readonly ILogger<CustomisationEventHandler> _logger;
|
||||||
|
private readonly IEventBus _eventBus;
|
||||||
|
private readonly IValidationService validationService;
|
||||||
|
|
||||||
|
public CustomisationEventHandler(ILogger<CustomisationEventHandler> logger, IEventBus eventBus)
|
||||||
|
{
|
||||||
|
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||||
|
_eventBus = eventBus ?? throw new ArgumentNullException(nameof(eventBus));
|
||||||
|
validationService = new ValidationService();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task Handle(CustomisationEvent @event)
|
||||||
|
{
|
||||||
|
_logger.LogInformation("----- Handling integration event: {IntegrationEventId} - ({@IntegrationEvent})", @event.Id, @event);
|
||||||
|
IntegrationEvent integrationEvent = @event.@event;
|
||||||
|
|
||||||
|
switch (integrationEvent.GetType().Name)
|
||||||
|
{
|
||||||
|
case "UserCheckoutAcceptedIntegrationEvent":
|
||||||
|
if (validationService.Validate((UserCheckoutAcceptedIntegrationEvent)integrationEvent))
|
||||||
|
{
|
||||||
|
integrationEvent.CheckForCustomisation = false;
|
||||||
|
_eventBus.Publish(integrationEvent);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
integrationEvent.CheckForCustomisation = false;
|
||||||
|
_eventBus.Publish(integrationEvent);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,45 @@
|
|||||||
|
using Microsoft.AspNetCore.SignalR;
|
||||||
|
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Serilog.Context;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using TenantACustomisations.Database;
|
||||||
|
using TenantACustomisations.ExternalServices;
|
||||||
|
using TenantACustomisations.IntegrationEvents.Events;
|
||||||
|
|
||||||
|
namespace TenantACustomisations.IntegrationEvents.EventHandling
|
||||||
|
{
|
||||||
|
public class OrderStatusChangedToSubmittedIntegrationEventHandler :
|
||||||
|
IIntegrationEventHandler<OrderStatusChangedToSubmittedIntegrationEvent>
|
||||||
|
{
|
||||||
|
private readonly ILogger<OrderStatusChangedToSubmittedIntegrationEventHandler> _logger;
|
||||||
|
private readonly IShippingService _shippingService;
|
||||||
|
private readonly TenantAContext _context;
|
||||||
|
|
||||||
|
public OrderStatusChangedToSubmittedIntegrationEventHandler(ILogger<OrderStatusChangedToSubmittedIntegrationEventHandler> logger, IShippingService shippingService, TenantAContext context)
|
||||||
|
{
|
||||||
|
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||||
|
_shippingService = shippingService ?? throw new ArgumentNullException(nameof(shippingService));
|
||||||
|
_context = context ?? throw new ArgumentNullException(nameof(shippingService));
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task Handle(OrderStatusChangedToSubmittedIntegrationEvent @event)
|
||||||
|
{
|
||||||
|
using (LogContext.PushProperty("IntegrationEventContext", $"{@event.Id}- TenantA"))
|
||||||
|
{
|
||||||
|
_logger.LogInformation("----- Handling integration event: {IntegrationEventId} at TenantA - ({@IntegrationEvent})", @event.Id, @event);
|
||||||
|
_logger.LogInformation("Hello");
|
||||||
|
//TODO
|
||||||
|
Debug.WriteLine(@event);
|
||||||
|
ShippingInformation shippingInformation = _shippingService.CalculateShippingInformation(@event.OrderId);
|
||||||
|
_context.ShippingInformation.Add(shippingInformation);
|
||||||
|
_logger.LogInformation("----- Saving shipping information: {IntegrationEventId} at TenantA - ({@IntegrationEvent}) - {@ShippingInformation}", @event.Id, @event, shippingInformation);
|
||||||
|
_context.SaveChanges();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,60 @@
|
|||||||
|
using MediatR;
|
||||||
|
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
|
||||||
|
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Extensions;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Ordering.API.Application.Behaviors;
|
||||||
|
using Serilog.Context;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using TenantACustomisations.IntegrationEvents.Events;
|
||||||
|
using TenantACustomisations.ExternalServices;
|
||||||
|
using TenantACustomisations.Database;
|
||||||
|
|
||||||
|
namespace TenantACustomisations.IntegrationEvents.EventHandling
|
||||||
|
{
|
||||||
|
public class TenantAUserCheckoutAcceptedIntegrationEventHandler :
|
||||||
|
IIntegrationEventHandler<UserCheckoutAcceptedIntegrationEvent>
|
||||||
|
{
|
||||||
|
private readonly IMediator _mediator;
|
||||||
|
private readonly IEventBus _eventBus;
|
||||||
|
private readonly ILogger<TenantAUserCheckoutAcceptedIntegrationEventHandler> _logger;
|
||||||
|
//private readonly TenantAContext _context;
|
||||||
|
//private readonly IShippingService _shippingService;
|
||||||
|
|
||||||
|
public TenantAUserCheckoutAcceptedIntegrationEventHandler(
|
||||||
|
IMediator mediator,
|
||||||
|
ILogger<TenantAUserCheckoutAcceptedIntegrationEventHandler> logger,
|
||||||
|
IEventBus eventBus
|
||||||
|
)
|
||||||
|
{
|
||||||
|
_mediator = mediator ?? throw new ArgumentNullException(nameof(mediator));
|
||||||
|
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||||
|
_eventBus = eventBus ?? throw new ArgumentNullException(nameof(eventBus));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Integration event handler which starts the create order process
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="@event">
|
||||||
|
/// Integration event message which is sent by the
|
||||||
|
/// basket.api once it has successfully process the
|
||||||
|
/// order items.
|
||||||
|
/// </param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task Handle(UserCheckoutAcceptedIntegrationEvent @event)
|
||||||
|
{
|
||||||
|
using (LogContext.PushProperty("IntegrationEventContext", $"{@event.Id}- TenantA"))
|
||||||
|
{
|
||||||
|
_logger.LogInformation("----- Handling integration event: {IntegrationEventId} at TenantA- ({@IntegrationEvent})", @event.Id, @event);
|
||||||
|
_logger.LogInformation("Hello");
|
||||||
|
|
||||||
|
//TODO
|
||||||
|
Debug.WriteLine(@event);
|
||||||
|
//Save shipping info
|
||||||
|
//Hard code view comp
|
||||||
|
//Retrieve shipping info and show
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events;
|
||||||
|
|
||||||
|
namespace TenantACustomisations.IntegrationEvents.Events
|
||||||
|
{
|
||||||
|
public class OrderStatusChangedToAwaitingValidationIntegrationEvent : IntegrationEvent
|
||||||
|
{
|
||||||
|
public int OrderId { get; }
|
||||||
|
public IEnumerable<OrderStockItem> OrderStockItems { get; }
|
||||||
|
|
||||||
|
public OrderStatusChangedToAwaitingValidationIntegrationEvent(int orderId,
|
||||||
|
IEnumerable<OrderStockItem> orderStockItems)
|
||||||
|
{
|
||||||
|
OrderId = orderId;
|
||||||
|
OrderStockItems = orderStockItems;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class OrderStockItem
|
||||||
|
{
|
||||||
|
public int ProductId { get; }
|
||||||
|
public int Units { get; }
|
||||||
|
|
||||||
|
public OrderStockItem(int productId, int units)
|
||||||
|
{
|
||||||
|
ProductId = productId;
|
||||||
|
Units = units;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,22 @@
|
|||||||
|
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace TenantACustomisations.IntegrationEvents.Events
|
||||||
|
{
|
||||||
|
public class OrderStatusChangedToSubmittedIntegrationEvent : IntegrationEvent
|
||||||
|
{
|
||||||
|
public int OrderId { get; set; }
|
||||||
|
public string OrderStatus { get; set; }
|
||||||
|
public string BuyerName { get; set; }
|
||||||
|
|
||||||
|
public OrderStatusChangedToSubmittedIntegrationEvent(int orderId, string orderStatus, string buyerName)
|
||||||
|
{
|
||||||
|
OrderId = orderId;
|
||||||
|
OrderStatus = orderStatus;
|
||||||
|
BuyerName = buyerName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,62 @@
|
|||||||
|
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events;
|
||||||
|
using Ordering.API.Application.Models;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace TenantACustomisations.IntegrationEvents.Events
|
||||||
|
{
|
||||||
|
public class UserCheckoutAcceptedIntegrationEvent : IntegrationEvent
|
||||||
|
{
|
||||||
|
public string UserId { get; }
|
||||||
|
|
||||||
|
public string UserName { get; }
|
||||||
|
|
||||||
|
public string City { get; set; }
|
||||||
|
|
||||||
|
public string Street { get; set; }
|
||||||
|
|
||||||
|
public string State { get; set; }
|
||||||
|
|
||||||
|
public string Country { get; set; }
|
||||||
|
|
||||||
|
public string ZipCode { get; set; }
|
||||||
|
|
||||||
|
public string CardNumber { get; set; }
|
||||||
|
|
||||||
|
public string CardHolderName { get; set; }
|
||||||
|
|
||||||
|
public DateTime CardExpiration { get; set; }
|
||||||
|
|
||||||
|
public string CardSecurityNumber { get; set; }
|
||||||
|
|
||||||
|
public int CardTypeId { get; set; }
|
||||||
|
|
||||||
|
public string Buyer { get; set; }
|
||||||
|
|
||||||
|
public Guid RequestId { get; set; }
|
||||||
|
|
||||||
|
public CustomerBasket Basket { get; }
|
||||||
|
|
||||||
|
public UserCheckoutAcceptedIntegrationEvent(string userId, string userName, string city, string street,
|
||||||
|
string state, string country, string zipCode, string cardNumber, string cardHolderName,
|
||||||
|
DateTime cardExpiration, string cardSecurityNumber, int cardTypeId, string buyer, Guid requestId,
|
||||||
|
CustomerBasket basket)
|
||||||
|
{
|
||||||
|
UserId = userId;
|
||||||
|
City = city;
|
||||||
|
Street = street;
|
||||||
|
State = state;
|
||||||
|
Country = country;
|
||||||
|
ZipCode = zipCode;
|
||||||
|
CardNumber = cardNumber;
|
||||||
|
CardHolderName = cardHolderName;
|
||||||
|
CardExpiration = cardExpiration;
|
||||||
|
CardSecurityNumber = cardSecurityNumber;
|
||||||
|
CardTypeId = cardTypeId;
|
||||||
|
Buyer = buyer;
|
||||||
|
Basket = basket;
|
||||||
|
RequestId = requestId;
|
||||||
|
UserName = userName;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,89 @@
|
|||||||
|
using Microsoft.AspNetCore;
|
||||||
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
using Microsoft.eShopOnContainers.Services.TenantACustomisations;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Serilog;
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using TenantACustomisations.Database;
|
||||||
|
|
||||||
|
namespace Microsoft.eShopOnContainers.Services.TenantACustomisations
|
||||||
|
{
|
||||||
|
public class Program
|
||||||
|
{
|
||||||
|
public static readonly string Namespace = typeof(Program).Namespace;
|
||||||
|
public static readonly string AppName = Namespace.Substring(Namespace.LastIndexOf('.', Namespace.LastIndexOf('.') - 1) + 1);
|
||||||
|
|
||||||
|
public static int Main(string[] args)
|
||||||
|
{
|
||||||
|
var configuration = GetConfiguration();
|
||||||
|
|
||||||
|
Log.Logger = CreateSerilogLogger(configuration);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Log.Information("Configuring web host ({ApplicationContext})...", AppName);
|
||||||
|
var host = BuildWebHost(configuration, args);
|
||||||
|
|
||||||
|
Log.Information("Starting web host ({ApplicationContext})...", AppName);
|
||||||
|
host.Run();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Fatal(ex, "Program terminated unexpectedly ({ApplicationContext})!", AppName);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Log.CloseAndFlush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IWebHost BuildWebHost(IConfiguration configuration, string[] args) =>
|
||||||
|
WebHost.CreateDefaultBuilder(args)
|
||||||
|
.CaptureStartupErrors(false)
|
||||||
|
.UseStartup<Startup>()
|
||||||
|
.UseApplicationInsights()
|
||||||
|
.UseContentRoot(Directory.GetCurrentDirectory())
|
||||||
|
.UseConfiguration(configuration)
|
||||||
|
.UseSerilog()
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
private static Serilog.ILogger CreateSerilogLogger(IConfiguration configuration)
|
||||||
|
{
|
||||||
|
var seqServerUrl = configuration["Serilog:SeqServerUrl"];
|
||||||
|
var logstashUrl = configuration["Serilog:LogstashgUrl"];
|
||||||
|
return new LoggerConfiguration()
|
||||||
|
.MinimumLevel.Verbose()
|
||||||
|
.Enrich.WithProperty("ApplicationContext", AppName)
|
||||||
|
.Enrich.FromLogContext()
|
||||||
|
.WriteTo.Console()
|
||||||
|
.WriteTo.Seq(string.IsNullOrWhiteSpace(seqServerUrl) ? "http://seq" : seqServerUrl)
|
||||||
|
.WriteTo.Http(string.IsNullOrWhiteSpace(logstashUrl) ? "http://logstash:8080" : logstashUrl)
|
||||||
|
.ReadFrom.Configuration(configuration)
|
||||||
|
.CreateLogger();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IConfiguration GetConfiguration()
|
||||||
|
{
|
||||||
|
var builder = new ConfigurationBuilder()
|
||||||
|
.SetBasePath(Directory.GetCurrentDirectory())
|
||||||
|
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
|
||||||
|
.AddEnvironmentVariables();
|
||||||
|
|
||||||
|
var config = builder.Build();
|
||||||
|
|
||||||
|
if (config.GetValue<bool>("UseVault", false))
|
||||||
|
{
|
||||||
|
builder.AddAzureKeyVault(
|
||||||
|
$"https://{config["Vault:Name"]}.vault.azure.net/",
|
||||||
|
config["Vault:ClientId"],
|
||||||
|
config["Vault:ClientSecret"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return builder.Build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json.schemastore.org/launchsettings.json",
|
||||||
|
"iisSettings": {
|
||||||
|
"windowsAuthentication": false,
|
||||||
|
"anonymousAuthentication": true,
|
||||||
|
"iisExpress": {
|
||||||
|
"applicationUrl": "http://localhost:57040",
|
||||||
|
"sslPort": 44328
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"profiles": {
|
||||||
|
"IIS Express": {
|
||||||
|
"commandName": "IISExpress",
|
||||||
|
"launchBrowser": true,
|
||||||
|
"launchUrl": "api/values",
|
||||||
|
"environmentVariables": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"TenantACustomisations": {
|
||||||
|
"commandName": "Project",
|
||||||
|
"launchBrowser": true,
|
||||||
|
"launchUrl": "api/values",
|
||||||
|
"applicationUrl": "https://localhost:5001;http://localhost:5000",
|
||||||
|
"environmentVariables": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events;
|
||||||
|
using Ordering.API.Application.IntegrationEvents.Events;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace TenantACustomisations.Services
|
||||||
|
{
|
||||||
|
interface IValidationService
|
||||||
|
{
|
||||||
|
Boolean Validate(UserCheckoutAcceptedIntegrationEvent @event);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
using Ordering.API.Application.IntegrationEvents.Events;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace TenantACustomisations.Services
|
||||||
|
{
|
||||||
|
public class ValidationService : IValidationService
|
||||||
|
{
|
||||||
|
public bool Validate(UserCheckoutAcceptedIntegrationEvent @event)
|
||||||
|
{
|
||||||
|
return @event.State == "Oslo";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,416 @@
|
|||||||
|
namespace Microsoft.eShopOnContainers.Services.TenantACustomisations
|
||||||
|
{
|
||||||
|
using AspNetCore.Http;
|
||||||
|
using Autofac;
|
||||||
|
using Autofac.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.ApplicationInsights.Extensibility;
|
||||||
|
using Microsoft.ApplicationInsights.ServiceFabric;
|
||||||
|
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||||
|
using Microsoft.AspNetCore.Builder;
|
||||||
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.Azure.ServiceBus;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus;
|
||||||
|
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
|
||||||
|
using Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ;
|
||||||
|
using Microsoft.eShopOnContainers.BuildingBlocks.EventBusServiceBus;
|
||||||
|
using Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF;
|
||||||
|
using Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF.Services;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using RabbitMQ.Client;
|
||||||
|
using Swashbuckle.AspNetCore.Swagger;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Data.Common;
|
||||||
|
using System.IdentityModel.Tokens.Jwt;
|
||||||
|
using System.Reflection;
|
||||||
|
using HealthChecks.UI.Client;
|
||||||
|
using Microsoft.AspNetCore.Diagnostics.HealthChecks;
|
||||||
|
using Microsoft.Extensions.Diagnostics.HealthChecks;
|
||||||
|
using Infrastructure.AutofacModules;
|
||||||
|
using Microsoft.eShopOnContainers.Services.TenantACustomisations.Infrastructure.Filters;
|
||||||
|
using global::TenantACustomisations.Infrastructure.Filters;
|
||||||
|
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events;
|
||||||
|
using global::TenantACustomisations.IntegrationEvents.EventHandling;
|
||||||
|
using global::TenantACustomisations.IntegrationEvents.Events;
|
||||||
|
using global::TenantACustomisations.ExternalServices;
|
||||||
|
using global::TenantACustomisations.Database;
|
||||||
|
|
||||||
|
public class Startup
|
||||||
|
{
|
||||||
|
public Startup(IConfiguration configuration)
|
||||||
|
{
|
||||||
|
Configuration = configuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IConfiguration Configuration { get; }
|
||||||
|
|
||||||
|
public IServiceProvider ConfigureServices(IServiceCollection services)
|
||||||
|
{
|
||||||
|
services.AddApplicationInsights(Configuration)
|
||||||
|
.AddCustomMvc()
|
||||||
|
.AddHealthChecks(Configuration)
|
||||||
|
.AddCustomDbContext(Configuration)
|
||||||
|
.AddCustomSwagger(Configuration)
|
||||||
|
.AddCustomIntegrations(Configuration)
|
||||||
|
.AddCustomConfiguration(Configuration)
|
||||||
|
.AddEventBus(Configuration)
|
||||||
|
.AddCustomAuthentication(Configuration);
|
||||||
|
|
||||||
|
//configure autofac
|
||||||
|
|
||||||
|
var container = new ContainerBuilder();
|
||||||
|
container.Populate(services);
|
||||||
|
|
||||||
|
container.RegisterModule(new MediatorModule());
|
||||||
|
container.RegisterModule(new ApplicationModule(Configuration["ConnectionString"]));
|
||||||
|
|
||||||
|
return new AutofacServiceProvider(container.Build());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory)
|
||||||
|
{
|
||||||
|
//loggerFactory.AddAzureWebAppDiagnostics();
|
||||||
|
//loggerFactory.AddApplicationInsights(app.ApplicationServices, LogLevel.Trace);
|
||||||
|
|
||||||
|
var pathBase = Configuration["PATH_BASE"];
|
||||||
|
if (!string.IsNullOrEmpty(pathBase))
|
||||||
|
{
|
||||||
|
loggerFactory.CreateLogger<Startup>().LogDebug("Using PATH BASE '{pathBase}'", pathBase);
|
||||||
|
app.UsePathBase(pathBase);
|
||||||
|
}
|
||||||
|
|
||||||
|
app.UseCors("CorsPolicy");
|
||||||
|
|
||||||
|
app.UseHealthChecks("/liveness", new HealthCheckOptions
|
||||||
|
{
|
||||||
|
Predicate = r => r.Name.Contains("self")
|
||||||
|
});
|
||||||
|
|
||||||
|
app.UseHealthChecks("/hc", new HealthCheckOptions()
|
||||||
|
{
|
||||||
|
Predicate = _ => true,
|
||||||
|
ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse
|
||||||
|
});
|
||||||
|
|
||||||
|
ConfigureAuth(app);
|
||||||
|
|
||||||
|
app.UseMvcWithDefaultRoute();
|
||||||
|
|
||||||
|
app.UseSwagger()
|
||||||
|
.UseSwaggerUI(c =>
|
||||||
|
{
|
||||||
|
c.SwaggerEndpoint($"{ (!string.IsNullOrEmpty(pathBase) ? pathBase : string.Empty) }/swagger/v1/swagger.json", "Ordering.API V1");
|
||||||
|
c.OAuthClientId("orderingswaggerui");
|
||||||
|
c.OAuthAppName("Ordering Swagger UI");
|
||||||
|
});
|
||||||
|
|
||||||
|
ConfigureEventBus(app);
|
||||||
|
using (var serviceScope = app.ApplicationServices.GetService<IServiceScopeFactory>().CreateScope())
|
||||||
|
{
|
||||||
|
var context = serviceScope.ServiceProvider.GetRequiredService<TenantAContext>();
|
||||||
|
context.Database.EnsureCreated();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void ConfigureEventBus(IApplicationBuilder app)
|
||||||
|
{
|
||||||
|
var eventBus = app.ApplicationServices.GetRequiredService<BuildingBlocks.EventBus.Abstractions.IEventBus>();
|
||||||
|
|
||||||
|
//eventBus.Subscribe<UserCheckoutAcceptedIntegrationEvent, IIntegrationEventHandler<UserCheckoutAcceptedIntegrationEvent>>();
|
||||||
|
eventBus.Subscribe<OrderStatusChangedToSubmittedIntegrationEvent, OrderStatusChangedToSubmittedIntegrationEventHandler>();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void ConfigureAuth(IApplicationBuilder app)
|
||||||
|
{
|
||||||
|
if (Configuration.GetValue<bool>("UseLoadTest"))
|
||||||
|
{
|
||||||
|
//app.UseMiddleware<ByPassAuthMiddleware>();
|
||||||
|
//TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
app.UseAuthentication();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class CustomExtensionsMethods
|
||||||
|
{
|
||||||
|
public static IServiceCollection AddApplicationInsights(this IServiceCollection services, IConfiguration configuration)
|
||||||
|
{
|
||||||
|
services.AddApplicationInsightsTelemetry(configuration);
|
||||||
|
var orchestratorType = configuration.GetValue<string>("OrchestratorType");
|
||||||
|
|
||||||
|
if (orchestratorType?.ToUpper() == "K8S")
|
||||||
|
{
|
||||||
|
// Enable K8s telemetry initializer
|
||||||
|
services.AddApplicationInsightsKubernetesEnricher();
|
||||||
|
}
|
||||||
|
if (orchestratorType?.ToUpper() == "SF")
|
||||||
|
{
|
||||||
|
// Enable SF telemetry initializer
|
||||||
|
services.AddSingleton<ITelemetryInitializer>((serviceProvider) =>
|
||||||
|
new FabricTelemetryInitializer());
|
||||||
|
}
|
||||||
|
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IServiceCollection AddCustomMvc(this IServiceCollection services)
|
||||||
|
{
|
||||||
|
// Add framework services.
|
||||||
|
services.AddMvc(options =>
|
||||||
|
{
|
||||||
|
options.Filters.Add(typeof(HttpGlobalExceptionFilter));
|
||||||
|
})
|
||||||
|
.SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
|
||||||
|
.AddControllersAsServices(); //Injecting Controllers themselves thru DI
|
||||||
|
//For further info see: http://docs.autofac.org/en/latest/integration/aspnetcore.html#controllers-as-services
|
||||||
|
|
||||||
|
services.AddCors(options =>
|
||||||
|
{
|
||||||
|
options.AddPolicy("CorsPolicy",
|
||||||
|
builder => builder
|
||||||
|
.SetIsOriginAllowed((host) => true)
|
||||||
|
.AllowAnyMethod()
|
||||||
|
.AllowAnyHeader()
|
||||||
|
.AllowCredentials());
|
||||||
|
});
|
||||||
|
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IServiceCollection AddHealthChecks(this IServiceCollection services, IConfiguration configuration)
|
||||||
|
{
|
||||||
|
var hcBuilder = services.AddHealthChecks();
|
||||||
|
|
||||||
|
hcBuilder.AddCheck("self", () => HealthCheckResult.Healthy());
|
||||||
|
|
||||||
|
hcBuilder
|
||||||
|
.AddSqlServer(
|
||||||
|
configuration["ConnectionString"],
|
||||||
|
name: "OrderingDB-check",
|
||||||
|
tags: new string[] { "orderingdb" });
|
||||||
|
|
||||||
|
if (configuration.GetValue<bool>("AzureServiceBusEnabled"))
|
||||||
|
{
|
||||||
|
hcBuilder
|
||||||
|
.AddAzureServiceBusTopic(
|
||||||
|
configuration["EventBusConnection"],
|
||||||
|
topicName: "eshop_event_bus",
|
||||||
|
name: "ordering-servicebus-check",
|
||||||
|
tags: new string[] { "servicebus" });
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
hcBuilder
|
||||||
|
.AddRabbitMQ(
|
||||||
|
$"amqp://{configuration["EventBusConnection"]}",
|
||||||
|
name: "ordering-rabbitmqbus-check",
|
||||||
|
tags: new string[] { "rabbitmqbus" });
|
||||||
|
}
|
||||||
|
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IServiceCollection AddCustomDbContext(this IServiceCollection services, IConfiguration configuration)
|
||||||
|
{
|
||||||
|
services.AddDbContext<TenantAContext>(options =>
|
||||||
|
options.UseSqlServer(configuration["ConnectionString"]));
|
||||||
|
|
||||||
|
services.AddDbContext<IntegrationEventLogContext>(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: 10, maxRetryDelay: TimeSpan.FromSeconds(30), errorNumbersToAdd: null);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IServiceCollection AddCustomSwagger(this IServiceCollection services, IConfiguration configuration)
|
||||||
|
{
|
||||||
|
services.AddSwaggerGen(options =>
|
||||||
|
{
|
||||||
|
options.DescribeAllEnumsAsStrings();
|
||||||
|
options.SwaggerDoc("v1", new Swashbuckle.AspNetCore.Swagger.Info
|
||||||
|
{
|
||||||
|
Title = "Ordering HTTP API",
|
||||||
|
Version = "v1",
|
||||||
|
Description = "The Ordering Service HTTP API",
|
||||||
|
TermsOfService = "Terms Of Service"
|
||||||
|
});
|
||||||
|
|
||||||
|
options.AddSecurityDefinition("oauth2", new OAuth2Scheme
|
||||||
|
{
|
||||||
|
Type = "oauth2",
|
||||||
|
Flow = "implicit",
|
||||||
|
AuthorizationUrl = $"{configuration.GetValue<string>("IdentityUrlExternal")}/connect/authorize",
|
||||||
|
TokenUrl = $"{configuration.GetValue<string>("IdentityUrlExternal")}/connect/token",
|
||||||
|
Scopes = new Dictionary<string, string>()
|
||||||
|
{
|
||||||
|
{ "orders", "Ordering API" }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
options.OperationFilter<AuthorizeCheckOperationFilter>();
|
||||||
|
});
|
||||||
|
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IServiceCollection AddCustomIntegrations(this IServiceCollection services, IConfiguration configuration)
|
||||||
|
{
|
||||||
|
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
|
||||||
|
//services.AddTransient<IIdentityService, IdentityService>();
|
||||||
|
services.AddTransient<Func<DbConnection, IIntegrationEventLogService>>(
|
||||||
|
sp => (DbConnection c) => new IntegrationEventLogService(c));
|
||||||
|
|
||||||
|
//services.AddTransient<IOrderingIntegrationEventService, OrderingIntegrationEventService>();
|
||||||
|
if (configuration.GetValue<bool>("AzureServiceBusEnabled"))
|
||||||
|
{
|
||||||
|
services.AddSingleton<IServiceBusPersisterConnection>(sp =>
|
||||||
|
{
|
||||||
|
var logger = sp.GetRequiredService<ILogger<DefaultServiceBusPersisterConnection>>();
|
||||||
|
|
||||||
|
var serviceBusConnectionString = configuration["EventBusConnection"];
|
||||||
|
var serviceBusConnection = new ServiceBusConnectionStringBuilder(serviceBusConnectionString);
|
||||||
|
|
||||||
|
return new DefaultServiceBusPersisterConnection(serviceBusConnection, logger);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
services.AddSingleton<IRabbitMQPersistentConnection>(sp =>
|
||||||
|
{
|
||||||
|
var logger = sp.GetRequiredService<ILogger<DefaultRabbitMQPersistentConnection>>();
|
||||||
|
|
||||||
|
|
||||||
|
var factory = new ConnectionFactory()
|
||||||
|
{
|
||||||
|
HostName = configuration["EventBusConnection"],
|
||||||
|
DispatchConsumersAsync = true
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(configuration["EventBusUserName"]))
|
||||||
|
{
|
||||||
|
factory.UserName = configuration["EventBusUserName"];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(configuration["EventBusPassword"]))
|
||||||
|
{
|
||||||
|
factory.Password = configuration["EventBusPassword"];
|
||||||
|
}
|
||||||
|
|
||||||
|
var retryCount = 5;
|
||||||
|
if (!string.IsNullOrEmpty(configuration["EventBusRetryCount"]))
|
||||||
|
{
|
||||||
|
retryCount = int.Parse(configuration["EventBusRetryCount"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new DefaultRabbitMQPersistentConnection(factory, logger, retryCount);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IServiceCollection AddCustomConfiguration(this IServiceCollection services, IConfiguration configuration)
|
||||||
|
{
|
||||||
|
services.AddOptions();
|
||||||
|
//services.Configure<OrderingSettings>(configuration);
|
||||||
|
services.Configure<ApiBehaviorOptions>(options =>
|
||||||
|
{
|
||||||
|
options.InvalidModelStateResponseFactory = context =>
|
||||||
|
{
|
||||||
|
var problemDetails = new ValidationProblemDetails(context.ModelState)
|
||||||
|
{
|
||||||
|
Instance = context.HttpContext.Request.Path,
|
||||||
|
Status = StatusCodes.Status400BadRequest,
|
||||||
|
Detail = "Please refer to the errors property for additional details."
|
||||||
|
};
|
||||||
|
|
||||||
|
return new BadRequestObjectResult(problemDetails)
|
||||||
|
{
|
||||||
|
ContentTypes = { "application/problem+json", "application/problem+xml" }
|
||||||
|
};
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IServiceCollection AddEventBus(this IServiceCollection services, IConfiguration configuration)
|
||||||
|
{
|
||||||
|
var subscriptionClientName = configuration["SubscriptionClientName"];
|
||||||
|
|
||||||
|
if (configuration.GetValue<bool>("AzureServiceBusEnabled"))
|
||||||
|
{
|
||||||
|
services.AddSingleton<IEventBus, EventBusServiceBus>(sp =>
|
||||||
|
{
|
||||||
|
var serviceBusPersisterConnection = sp.GetRequiredService<IServiceBusPersisterConnection>();
|
||||||
|
var iLifetimeScope = sp.GetRequiredService<ILifetimeScope>();
|
||||||
|
var logger = sp.GetRequiredService<ILogger<EventBusServiceBus>>();
|
||||||
|
var eventBusSubcriptionsManager = sp.GetRequiredService<IEventBusSubscriptionsManager>();
|
||||||
|
|
||||||
|
return new EventBusServiceBus(serviceBusPersisterConnection, logger,
|
||||||
|
eventBusSubcriptionsManager, subscriptionClientName, iLifetimeScope);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
services.AddSingleton<IEventBus, EventBusRabbitMQ>(sp =>
|
||||||
|
{
|
||||||
|
var rabbitMQPersistentConnection = sp.GetRequiredService<IRabbitMQPersistentConnection>();
|
||||||
|
var iLifetimeScope = sp.GetRequiredService<ILifetimeScope>();
|
||||||
|
var logger = sp.GetRequiredService<ILogger<EventBusRabbitMQ>>();
|
||||||
|
var eventBusSubcriptionsManager = sp.GetRequiredService<IEventBusSubscriptionsManager>();
|
||||||
|
|
||||||
|
var retryCount = 5;
|
||||||
|
if (!string.IsNullOrEmpty(configuration["EventBusRetryCount"]))
|
||||||
|
{
|
||||||
|
retryCount = int.Parse(configuration["EventBusRetryCount"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new EventBusRabbitMQ(rabbitMQPersistentConnection, logger, iLifetimeScope, eventBusSubcriptionsManager, subscriptionClientName, retryCount);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
services.AddSingleton<IEventBusSubscriptionsManager, InMemoryEventBusSubscriptionsManager>();
|
||||||
|
//services.AddTransient<TenantAUserCheckoutAcceptedIntegrationEventHandler>();
|
||||||
|
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IServiceCollection AddCustomAuthentication(this IServiceCollection services, IConfiguration configuration)
|
||||||
|
{
|
||||||
|
// prevent from mapping "sub" claim to nameidentifier.
|
||||||
|
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Remove("sub");
|
||||||
|
|
||||||
|
var identityUrl = configuration.GetValue<string>("IdentityUrl");
|
||||||
|
|
||||||
|
services.AddAuthentication(options =>
|
||||||
|
{
|
||||||
|
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
|
||||||
|
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
|
||||||
|
|
||||||
|
}).AddJwtBearer(options =>
|
||||||
|
{
|
||||||
|
options.Authority = identityUrl;
|
||||||
|
options.RequireHttpsMetadata = false;
|
||||||
|
options.Audience = "orders";
|
||||||
|
});
|
||||||
|
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,58 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>netcoreapp2.2</TargetFramework>
|
||||||
|
<AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>
|
||||||
|
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
||||||
|
<DockerfileContext>..\eShopOnContainersCustomised</DockerfileContext>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="AspNetCore.HealthChecks.AzureServiceBus" Version="2.2.0" />
|
||||||
|
<PackageReference Include="AspNetCore.HealthChecks.Rabbitmq" Version="2.2.0" />
|
||||||
|
<PackageReference Include="AspNetCore.HealthChecks.SqlServer" Version="2.2.0" />
|
||||||
|
<PackageReference Include="AspNetCore.HealthChecks.UI.Client" Version="2.2.4" />
|
||||||
|
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="4.2.1" />
|
||||||
|
<PackageReference Include="Dapper" Version="1.50.7" />
|
||||||
|
<PackageReference Include="FluentValidation.AspNetCore" Version="7.5.0" />
|
||||||
|
<PackageReference Include="MediatR" Version="5.1.0" />
|
||||||
|
<PackageReference Include="MediatR.Extensions.Microsoft.DependencyInjection" Version="5.1.0" />
|
||||||
|
<PackageReference Include="Microsoft.ApplicationInsights" Version="2.11.0" />
|
||||||
|
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.2.1" />
|
||||||
|
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.6.1" />
|
||||||
|
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="1.0.2" />
|
||||||
|
<PackageReference Include="Microsoft.ApplicationInsights.ServiceFabric" Version="2.2.2" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.App" Version="2.2.0" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.HealthChecks" Version="2.2.0" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.HealthChecks" Version="1.0.0" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Razor.Design" Version="2.2.0" PrivateAssets="All" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Configuration.AzureKeyVault" Version="2.2.0" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Logging.AzureAppServices" Version="2.2.0" />
|
||||||
|
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="2.2.4" />
|
||||||
|
<PackageReference Include="Polly" Version="6.0.1" />
|
||||||
|
<PackageReference Include="Serilog" Version="2.9.0" />
|
||||||
|
<PackageReference Include="Serilog.AspNetCore" Version="2.1.1" />
|
||||||
|
<PackageReference Include="Serilog.Enrichers.Environment" Version="2.1.3" />
|
||||||
|
<PackageReference Include="Serilog.Settings.Configuration" Version="3.0.1" />
|
||||||
|
<PackageReference Include="Serilog.Sinks.Console" Version="3.1.1" />
|
||||||
|
<PackageReference Include="Serilog.Sinks.Http" Version="4.2.1" />
|
||||||
|
<PackageReference Include="Serilog.Sinks.Seq" Version="4.0.0" />
|
||||||
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="3.0.0" />
|
||||||
|
<PackageReference Include="Swashbuckle.AspNetCore.Swagger" Version="4.0.1" />
|
||||||
|
<PackageReference Include="System.Reflection" Version="4.3.0" />
|
||||||
|
<PackageReference Include="System.ValueTuple" Version="4.5.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBusRabbitMQ\EventBusRabbitMQ.csproj" />
|
||||||
|
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBusServiceBus\EventBusServiceBus.csproj" />
|
||||||
|
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\EventBus\EventBus.csproj" />
|
||||||
|
<ProjectReference Include="..\..\..\BuildingBlocks\EventBus\IntegrationEventLogEF\IntegrationEventLogEF.csproj" />
|
||||||
|
<ProjectReference Include="..\..\Ordering\Ordering.API\Ordering.API.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Update="Microsoft.NETCore.App" Version="2.2.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"Logging": {
|
||||||
|
"LogLevel": {
|
||||||
|
"Default": "Debug",
|
||||||
|
"System": "Information",
|
||||||
|
"Microsoft": "Information"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
{
|
||||||
|
"Serilog": {
|
||||||
|
"SeqServerUrl": null,
|
||||||
|
"LogstashgUrl": null,
|
||||||
|
"MinimumLevel": {
|
||||||
|
"Default": "Information",
|
||||||
|
"Override": {
|
||||||
|
"Microsoft": "Warning",
|
||||||
|
"Microsoft.eShopOnContainers": "Information",
|
||||||
|
"System": "Warning"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"IdentityUrl": "http://localhost:5105",
|
||||||
|
//"ConnectionString": "127.0.0.1",
|
||||||
|
"ConnectionString": "Server=tcp:127.0.0.1,5433;Database=Microsoft.eShopOnContainers.Services.TenantADb;User Id=sa;Password=Pass@word;",
|
||||||
|
"AzureServiceBusEnabled": false,
|
||||||
|
"SubscriptionClientName": "TenantACustomisation",
|
||||||
|
"ApplicationInsights": {
|
||||||
|
"InstrumentationKey": ""
|
||||||
|
},
|
||||||
|
"EventBusRetryCount": 5,
|
||||||
|
"UseVault": false,
|
||||||
|
"Vault": {
|
||||||
|
"Name": "eshop",
|
||||||
|
"ClientId": "your-clien-id",
|
||||||
|
"ClientSecret": "your-client-secret"
|
||||||
|
}
|
||||||
|
}
|
@ -41,6 +41,20 @@ namespace TenantManager.Controllers
|
|||||||
|
|
||||||
return customisation;
|
return customisation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GET: api/Customisations/5
|
||||||
|
[HttpGet("isCustomised")]
|
||||||
|
public async Task<ActionResult<Boolean>> IsCustomised(String eventName, int tenantId)
|
||||||
|
{
|
||||||
|
var customisation = await _context.Customisation.Include(c => c.Method).Include(c => c.Tenant).Where(c => c.Method.MethodName.Equals(eventName) && c.TenantId == tenantId).FirstOrDefaultAsync();
|
||||||
|
|
||||||
|
if (customisation == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// PUT: api/Customisations/5
|
// PUT: api/Customisations/5
|
||||||
[HttpPut("{id}")]
|
[HttpPut("{id}")]
|
||||||
|
@ -1,7 +1,4 @@
|
|||||||
using System;
|
using System.Linq;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using TenantManager.Models;
|
using TenantManager.Models;
|
||||||
|
|
||||||
namespace TenantManager.Database
|
namespace TenantManager.Database
|
||||||
@ -17,28 +14,13 @@ namespace TenantManager.Database
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var tenant1 = new Tenant() { TenantName = "Tekna" };
|
var tenant1 = new Tenant { TenantName = "Tekna" };
|
||||||
var tenant2 = new Tenant() { TenantName = "NITO" };
|
context.Tenant.Add(tenant1);
|
||||||
var tenant3 = new Tenant() { TenantName = "LO" };
|
|
||||||
|
var method1 = new Method { MethodName = "OrderStatusChangedToSubmittedIntegrationEvent" };
|
||||||
|
var method2 = new Method { MethodName = "OrderStatusChangedToAwaitingValidationIntegrationEvent" };
|
||||||
|
|
||||||
var tenants = new Tenant[]
|
var methods = new[]
|
||||||
{
|
|
||||||
tenant1,
|
|
||||||
tenant2,
|
|
||||||
tenant3
|
|
||||||
};
|
|
||||||
|
|
||||||
foreach(Tenant t in tenants)
|
|
||||||
{
|
|
||||||
context.Tenant.Add(t);
|
|
||||||
}
|
|
||||||
|
|
||||||
context.SaveChanges();
|
|
||||||
|
|
||||||
var method1 = new Method() { MethodName = "GetPrice" };
|
|
||||||
var method2 = new Method() { MethodName = "GetItem" };
|
|
||||||
|
|
||||||
var methods = new Method[]
|
|
||||||
{
|
{
|
||||||
method1,
|
method1,
|
||||||
method2
|
method2
|
||||||
@ -48,14 +30,11 @@ namespace TenantManager.Database
|
|||||||
{
|
{
|
||||||
context.Method.Add(m);
|
context.Method.Add(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
context.SaveChanges();
|
var customisations = new[]
|
||||||
|
|
||||||
var customisations = new Customisation[]
|
|
||||||
{
|
{
|
||||||
new Customisation(){Tenant=tenant1, Method=method1 },
|
new Customisation {Tenant=tenant1, Method=method1 },
|
||||||
new Customisation(){Tenant=tenant1, Method=method2},
|
new Customisation {Tenant=tenant1, Method=method2}
|
||||||
new Customisation(){Tenant=tenant2, Method=method1 }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
foreach(Customisation c in customisations)
|
foreach(Customisation c in customisations)
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
@ -8,9 +9,15 @@ namespace TenantManager.Models
|
|||||||
public class Customisation
|
public class Customisation
|
||||||
{
|
{
|
||||||
public int CustomisationId { get; set; }
|
public int CustomisationId { get; set; }
|
||||||
|
|
||||||
|
//Foreign keys
|
||||||
public int TenantId { get; set; }
|
public int TenantId { get; set; }
|
||||||
public virtual Tenant Tenant { get; set; }
|
|
||||||
public int MethodId { get; set; }
|
public int MethodId { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
[ForeignKey("TenantId")]
|
||||||
|
public virtual Tenant Tenant { get; set; }
|
||||||
|
[ForeignKey("MethodId")]
|
||||||
public virtual Method Method { get; set; }
|
public virtual Method Method { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,6 @@ namespace TenantManager.Models
|
|||||||
{
|
{
|
||||||
public int MethodId { get; set; }
|
public int MethodId { get; set; }
|
||||||
public String MethodName { get; set; }
|
public String MethodName { get; set; }
|
||||||
public ICollection<Customisation> Customisations { get; set; }
|
public List<Customisation> Customisations { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ namespace TenantManager.Models
|
|||||||
{
|
{
|
||||||
public String TenantName { get; set; }
|
public String TenantName { get; set; }
|
||||||
[Key]
|
[Key]
|
||||||
public long TenantId { get; set; }
|
public int TenantId { get; set; }
|
||||||
public ICollection<Customisation> Customisations { get; set; }
|
public List<Customisation> Customisations { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,8 +2,17 @@ using Microsoft.AspNetCore.Authorization;
|
|||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.eShopOnContainers.WebMVC.Services;
|
using Microsoft.eShopOnContainers.WebMVC.Services;
|
||||||
using Microsoft.eShopOnContainers.WebMVC.ViewModels;
|
using Microsoft.eShopOnContainers.WebMVC.ViewModels;
|
||||||
|
using Microsoft.eShopOnContainers.WebMVC.ViewModels.Customisation;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Newtonsoft.Json;
|
||||||
using Polly.CircuitBreaker;
|
using Polly.CircuitBreaker;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
|
using System.Net.Http;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using System.Web;
|
||||||
|
|
||||||
namespace Microsoft.eShopOnContainers.WebMVC.Controllers
|
namespace Microsoft.eShopOnContainers.WebMVC.Controllers
|
||||||
{
|
{
|
||||||
@ -13,16 +22,21 @@ namespace Microsoft.eShopOnContainers.WebMVC.Controllers
|
|||||||
private IOrderingService _orderSvc;
|
private IOrderingService _orderSvc;
|
||||||
private IBasketService _basketSvc;
|
private IBasketService _basketSvc;
|
||||||
private readonly IIdentityParser<ApplicationUser> _appUserParser;
|
private readonly IIdentityParser<ApplicationUser> _appUserParser;
|
||||||
public OrderController(IOrderingService orderSvc, IBasketService basketSvc, IIdentityParser<ApplicationUser> appUserParser)
|
private static String tenantACustomisationsUrl = @"http://tenantacustomisation/";
|
||||||
|
private readonly ILogger<OrderController> _logger;
|
||||||
|
|
||||||
|
|
||||||
|
public OrderController(IOrderingService orderSvc, IBasketService basketSvc,
|
||||||
|
IIdentityParser<ApplicationUser> appUserParser, ILogger<OrderController> logger)
|
||||||
{
|
{
|
||||||
_appUserParser = appUserParser;
|
_appUserParser = appUserParser;
|
||||||
_orderSvc = orderSvc;
|
_orderSvc = orderSvc;
|
||||||
_basketSvc = basketSvc;
|
_basketSvc = basketSvc;
|
||||||
|
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IActionResult> Create()
|
public async Task<IActionResult> Create()
|
||||||
{
|
{
|
||||||
|
|
||||||
var user = _appUserParser.Parse(HttpContext.User);
|
var user = _appUserParser.Parse(HttpContext.User);
|
||||||
var order = await _basketSvc.GetOrderDraft(user.Id);
|
var order = await _basketSvc.GetOrderDraft(user.Id);
|
||||||
var vm = _orderSvc.MapUserInfoIntoOrder(user, order);
|
var vm = _orderSvc.MapUserInfoIntoOrder(user, order);
|
||||||
@ -49,7 +63,8 @@ namespace Microsoft.eShopOnContainers.WebMVC.Controllers
|
|||||||
}
|
}
|
||||||
catch (BrokenCircuitException)
|
catch (BrokenCircuitException)
|
||||||
{
|
{
|
||||||
ModelState.AddModelError("Error", "It was not possible to create a new order, please try later on. (Business Msg Due to Circuit-Breaker)");
|
ModelState.AddModelError("Error",
|
||||||
|
"It was not possible to create a new order, please try later on. (Business Msg Due to Circuit-Breaker)");
|
||||||
}
|
}
|
||||||
|
|
||||||
return View("Create", model);
|
return View("Create", model);
|
||||||
@ -66,6 +81,8 @@ namespace Microsoft.eShopOnContainers.WebMVC.Controllers
|
|||||||
public async Task<IActionResult> Detail(string orderId)
|
public async Task<IActionResult> Detail(string orderId)
|
||||||
{
|
{
|
||||||
var user = _appUserParser.Parse(HttpContext.User);
|
var user = _appUserParser.Parse(HttpContext.User);
|
||||||
|
Boolean RFIDScanned = await AllGoodsRFIDScanned(orderId);
|
||||||
|
ViewData["RFIDScanned"] = RFIDScanned;
|
||||||
|
|
||||||
var order = await _orderSvc.GetOrder(user, orderId);
|
var order = await _orderSvc.GetOrder(user, orderId);
|
||||||
return View(order);
|
return View(order);
|
||||||
@ -75,7 +92,68 @@ namespace Microsoft.eShopOnContainers.WebMVC.Controllers
|
|||||||
{
|
{
|
||||||
var user = _appUserParser.Parse(HttpContext.User);
|
var user = _appUserParser.Parse(HttpContext.User);
|
||||||
var vm = await _orderSvc.GetMyOrders(user);
|
var vm = await _orderSvc.GetMyOrders(user);
|
||||||
|
List<ShippingInformation> shippingInformation = GetShippingInfo(vm);
|
||||||
|
_logger.LogInformation("----- Shipping info{@ShippingInformation}", shippingInformation);
|
||||||
|
|
||||||
|
ViewData["ShippingInfo"] = shippingInformation;
|
||||||
return View(vm);
|
return View(vm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private async Task<Boolean> AllGoodsRFIDScanned(String orderId)
|
||||||
|
{
|
||||||
|
var builder = new UriBuilder(tenantACustomisationsUrl + "api/SavedEvents");
|
||||||
|
builder.Port = -1;
|
||||||
|
var query = HttpUtility.ParseQueryString(builder.Query);
|
||||||
|
query["orderId"] = orderId;
|
||||||
|
builder.Query = query.ToString();
|
||||||
|
string url = builder.ToString();
|
||||||
|
|
||||||
|
using (var client = new HttpClient())
|
||||||
|
{
|
||||||
|
var response = await client.GetAsync(
|
||||||
|
url);
|
||||||
|
if (response.StatusCode.Equals(HttpStatusCode.NotFound))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<ShippingInformation> GetShippingInfo(List<Order> orders)
|
||||||
|
{
|
||||||
|
List<ShippingInformation> shippingInformation = new List<ShippingInformation>();
|
||||||
|
using (var client = new HttpClient(new HttpClientHandler
|
||||||
|
{AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate}))
|
||||||
|
{
|
||||||
|
client.BaseAddress = new Uri(tenantACustomisationsUrl);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
HttpResponseMessage response = client.GetAsync("api/shippinginformations").Result;
|
||||||
|
response.EnsureSuccessStatusCode();
|
||||||
|
string result = response.Content.ReadAsStringAsync().Result;
|
||||||
|
_logger.LogInformation("----- Result{@result} -----", result);
|
||||||
|
|
||||||
|
List<ShippingInformation>
|
||||||
|
results = JsonConvert.DeserializeObject<List<ShippingInformation>>(result);
|
||||||
|
results.ForEach(s =>
|
||||||
|
{
|
||||||
|
if (orders.Any(item => item.OrderNumber.Equals(s.OrderNumber)))
|
||||||
|
{
|
||||||
|
shippingInformation.Add(s);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Console.WriteLine(e);
|
||||||
|
_logger.LogInformation("----- Exception{@e} -----", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return shippingInformation;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
12
src/Web/WebMVC/ViewModels/Customisation/Fragility.cs
Normal file
12
src/Web/WebMVC/ViewModels/Customisation/Fragility.cs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Microsoft.eShopOnContainers.WebMVC.ViewModels.Customisation
|
||||||
|
{
|
||||||
|
public enum Fragility
|
||||||
|
{
|
||||||
|
Low, Medium, High
|
||||||
|
}
|
||||||
|
}
|
12
src/Web/WebMVC/ViewModels/Customisation/Priority.cs
Normal file
12
src/Web/WebMVC/ViewModels/Customisation/Priority.cs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Microsoft.eShopOnContainers.WebMVC.ViewModels.Customisation
|
||||||
|
{
|
||||||
|
public enum Priority
|
||||||
|
{
|
||||||
|
Low, Medium, High
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Microsoft.eShopOnContainers.WebMVC.ViewModels.Customisation
|
||||||
|
{
|
||||||
|
public class ShippingInformation
|
||||||
|
{
|
||||||
|
public int ShippingInformationId { get; set; }
|
||||||
|
public DateTime ArrivalTime { get; set; }
|
||||||
|
public DateTime ShippingTime { get; set; }
|
||||||
|
public Priority PriorityLevel { get; set; }
|
||||||
|
public Fragility FragilityLevel { get; set; }
|
||||||
|
public String OrderNumber { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -3,9 +3,12 @@
|
|||||||
@model Microsoft.eShopOnContainers.WebMVC.ViewModels.Order
|
@model Microsoft.eShopOnContainers.WebMVC.ViewModels.Order
|
||||||
|
|
||||||
@{
|
@{
|
||||||
ViewData["Title"] = "Order Detail";
|
ViewData["Title"] = "Order Detail";
|
||||||
var headerList= new List<Header>() {
|
var headerList = new List<Header>()
|
||||||
new Header() { Controller = "Catalog", Text = "Back to catalog" } };
|
{
|
||||||
|
new Header() {Controller = "Catalog", Text = "Back to catalog"}
|
||||||
|
};
|
||||||
|
var rfidScanned = ViewData["RFIDScanned"];
|
||||||
}
|
}
|
||||||
|
|
||||||
<div class="esh-orders_detail">
|
<div class="esh-orders_detail">
|
||||||
@ -14,20 +17,22 @@
|
|||||||
<div class="container">
|
<div class="container">
|
||||||
<section class="esh-orders_detail-section">
|
<section class="esh-orders_detail-section">
|
||||||
<article class="esh-orders_detail-titles row">
|
<article class="esh-orders_detail-titles row">
|
||||||
<section class="esh-orders_detail-title col-3">Order number</section>
|
<section class="esh-orders_detail-title col-2">Order number</section>
|
||||||
<section class="esh-orders_detail-title col-3">Date</section>
|
<section class="esh-orders_detail-title col-2">Date</section>
|
||||||
<section class="esh-orders_detail-title col-3">Total</section>
|
<section class="esh-orders_detail-title col-2">Total</section>
|
||||||
<section class="esh-orders_detail-title col-3">Status</section>
|
<section class="esh-orders_detail-title col-2">Status</section>
|
||||||
|
<section class="esh-orders_detail-title col-2">RFID Scanned</section>
|
||||||
</article>
|
</article>
|
||||||
|
|
||||||
<article class="esh-orders_detail-items row">
|
<article class="esh-orders_detail-items row">
|
||||||
<section class="esh-orders_detail-item col-3">@Model.OrderNumber</section>
|
<section class="esh-orders_detail-item col-2">$@Model.Total</section>
|
||||||
<section class="esh-orders_detail-item col-3">@Model.Date</section>
|
<section class="esh-orders_detail-item col-2">@Model.OrderNumber</section>
|
||||||
<section class="esh-orders_detail-item col-3">$@Model.Total</section>
|
<section class="esh-orders_detail-item col-2">@Model.Date</section>
|
||||||
<section class="esh-orders_detail-title col-3">@Model.Status</section>
|
<section class="esh-orders_detail-title col-2">@Model.Status</section>
|
||||||
|
<section class="esh-orders_detail-title col-2">@rfidScanned</section>
|
||||||
</article>
|
</article>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="esh-orders_detail-section">
|
<section class="esh-orders_detail-section">
|
||||||
<article class="esh-orders_detail-titles row">
|
<article class="esh-orders_detail-titles row">
|
||||||
<section class="esh-orders_detail-title col-12">Description</section>
|
<section class="esh-orders_detail-title col-12">Description</section>
|
||||||
@ -88,4 +93,4 @@
|
|||||||
</article>
|
</article>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
@ -1,35 +1,63 @@
|
|||||||
@using Microsoft.eShopOnContainers.WebMVC.ViewModels
|
@using Microsoft.eShopOnContainers.WebMVC.ViewModels
|
||||||
|
@using Microsoft.eShopOnContainers.WebMVC.ViewModels.Customisation
|
||||||
|
|
||||||
@model IEnumerable<Microsoft.eShopOnContainers.WebMVC.ViewModels.Order>
|
@model IEnumerable<Microsoft.eShopOnContainers.WebMVC.ViewModels.Order>
|
||||||
|
|
||||||
@{
|
@{
|
||||||
ViewData["Title"] = "My Orders";
|
ViewData["Title"] = "My Orders";
|
||||||
var headerList= new List<Header>() {
|
var headerList = new List<Header>() {
|
||||||
new Header() { Controller = "Catalog", Text = "Back to catalog" },
|
new Header() { Controller = "Catalog", Text = "Back to catalog" },
|
||||||
new Header() { Text = " / " },
|
new Header() { Text = " / " },
|
||||||
new Header() { Controller = "OrderManagement", Text = "Orders Management" } };
|
new Header() { Controller = "OrderManagement", Text = "Orders Management" } };
|
||||||
|
var shippingInfo = ViewData["ShippingInfo"] as List<ShippingInformation>;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
<div class="esh-orders">
|
<div class="esh-orders">
|
||||||
<partial name="_Header" model="headerList"/>
|
<partial name="_Header" model="headerList" />
|
||||||
|
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<article class="esh-orders-titles row">
|
<article class="esh-orders-titles row">
|
||||||
<section class="esh-orders-title col-2">Order number</section>
|
<section class="esh-orders-title col-1">Order number</section>
|
||||||
<section class="esh-orders-title col-4">Date</section>
|
<section class="esh-orders-title col-2">Date</section>
|
||||||
<section class="esh-orders-title col-2">Total</section>
|
<section class="esh-orders-title col-1">Total</section>
|
||||||
<section class="esh-orders-title col-2">Status</section>
|
<section class="esh-orders-title col-1">Status</section>
|
||||||
|
<section class="esh-orders-title col-2">Shipping date</section>
|
||||||
|
<section class="esh-orders-title col-2">Estimated arrival date</section>
|
||||||
<section class="esh-orders-title col-2"></section>
|
<section class="esh-orders-title col-2"></section>
|
||||||
|
|
||||||
</article>
|
</article>
|
||||||
@if (Model != null && Model.Any())
|
@if (Model != null && Model.Any())
|
||||||
{
|
{
|
||||||
foreach (var item in Model)
|
foreach (var item in Model)
|
||||||
{
|
{
|
||||||
<article class="esh-orders-items row">
|
<article class="esh-orders-items row">
|
||||||
<section class="esh-orders-item col-2">@Html.DisplayFor(modelItem => item.OrderNumber)</section>
|
<section class="esh-orders-item col-1">@Html.DisplayFor(modelItem => item.OrderNumber)</section>
|
||||||
<section class="esh-orders-item col-4">@Html.DisplayFor(modelItem => item.Date)</section>
|
<section class="esh-orders-item col-2">@item.Date.ToShortDateString()</section>
|
||||||
<section class="esh-orders-item col-2">$ @Html.DisplayFor(modelItem => item.Total)</section>
|
<section class="esh-orders-item col-1">$ @Html.DisplayFor(modelItem => item.Total)</section>
|
||||||
<section class="esh-orders-item col-2">@Html.DisplayFor(modelItem => item.Status)</section>
|
<section class="esh-orders-item col-1">@Html.DisplayFor(modelItem => item.Status)</section>
|
||||||
|
<section class="esh-orders-item col-2">
|
||||||
|
@for (var i = 0; i < shippingInfo.Count(); i++)
|
||||||
|
{
|
||||||
|
var si = shippingInfo[i];
|
||||||
|
if (si.OrderNumber.Equals(item.OrderNumber))
|
||||||
|
{
|
||||||
|
@si.ShippingTime.ToShortDateString();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</section>
|
||||||
|
<section class="esh-orders-item col-2">
|
||||||
|
@for (var i = 0; i < shippingInfo.Count(); i++)
|
||||||
|
{
|
||||||
|
var si = shippingInfo[i];
|
||||||
|
if (si.OrderNumber.Equals(item.OrderNumber))
|
||||||
|
{
|
||||||
|
@si.ArrivalTime.ToShortDateString();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</section>
|
||||||
<section class="esh-orders-item col-1">
|
<section class="esh-orders-item col-1">
|
||||||
<a class="esh-orders-link" asp-controller="Order" asp-action="Detail" asp-route-orderId="@item.OrderNumber">Detail</a>
|
<a class="esh-orders-link" asp-controller="Order" asp-action="Detail" asp-route-orderId="@item.OrderNumber">Detail</a>
|
||||||
</section>
|
</section>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user