Browse Source

Added missing Task.Background service docker-compose configuration

Added signalr client for MVC
Added signalr hub
Added signalr events when order status changes
pull/702/merge
Ramón Tomás 6 years ago
parent
commit
f1f17798da
48 changed files with 4324 additions and 95 deletions
  1. +19
    -0
      docker-compose.override.yml
  2. +8
    -0
      docker-compose.yml
  3. +51
    -0
      eShopOnContainers-ServicesAndWebApps.sln
  4. +11
    -0
      package-lock.json
  5. +3
    -1
      src/Services/Basket/Basket.API/Controllers/BasketController.cs
  6. +4
    -1
      src/Services/Basket/Basket.API/IntegrationEvents/Events/UserCheckoutAcceptedIntegrationEvent.cs
  7. +3
    -1
      src/Services/Identity/Identity.API/Services/ProfileService.cs
  8. +5
    -1
      src/Services/Ordering/Ordering.API/Application/Commands/CreateOrderCommand.cs
  9. +1
    -1
      src/Services/Ordering/Ordering.API/Application/Commands/CreateOrderCommandHandler.cs
  10. +50
    -0
      src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderCancelled/OrderCancelledDomainEventHandler.cs
  11. +20
    -1
      src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderGracePeriodConfirmed/OrderStatusChangedToAwaitingValidationDomainEventHandler.cs
  12. +18
    -2
      src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderPaid/OrderStatusChangedToPaidDomainEventHandler.cs
  13. +50
    -0
      src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderShipped/OrderShippedDomainEventHandler.cs
  14. +6
    -3
      src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderStartedEvent/ValidateOrAddBuyerAggregateWhenOrderStartedDomainEventHandler.cs
  15. +18
    -1
      src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderStockConfirmed/OrderStatusChangedToStockConfirmedDomainEventHandler.cs
  16. +1
    -1
      src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/UserCheckoutAcceptedIntegrationEventHandler.cs
  17. +4
    -1
      src/Services/Ordering/Ordering.API/Application/IntegrationEvents/Events/UserCheckoutAcceptedIntegrationEvent.cs
  18. +27
    -0
      src/Services/Ordering/Ordering.API/Infrastructure/Hubs/NotificationsHub.cs
  19. +238
    -0
      src/Services/Ordering/Ordering.API/Infrastructure/Migrations/20180412143935_NamePropertyInBuyer.Designer.cs
  20. +86
    -0
      src/Services/Ordering/Ordering.API/Infrastructure/Migrations/20180412143935_NamePropertyInBuyer.cs
  21. +15
    -28
      src/Services/Ordering/Ordering.API/Infrastructure/Migrations/OrderingContextModelSnapshot.cs
  22. +2
    -0
      src/Services/Ordering/Ordering.API/Infrastructure/Services/IIdentityService.cs
  23. +5
    -0
      src/Services/Ordering/Ordering.API/Infrastructure/Services/IdentityService.cs
  24. +1
    -0
      src/Services/Ordering/Ordering.API/Ordering.API.csproj
  25. +15
    -3
      src/Services/Ordering/Ordering.API/Startup.cs
  26. +2
    -1
      src/Services/Ordering/Ordering.API/settings.json
  27. +4
    -1
      src/Services/Ordering/Ordering.Domain/AggregatesModel/BuyerAggregate/Buyer.cs
  28. +1
    -0
      src/Services/Ordering/Ordering.Domain/AggregatesModel/BuyerAggregate/IBuyerRepository.cs
  29. +7
    -4
      src/Services/Ordering/Ordering.Domain/AggregatesModel/OrderAggregate/Order.cs
  30. +18
    -0
      src/Services/Ordering/Ordering.Domain/Events/OrderCancelledDomainEvent.cs
  31. +15
    -0
      src/Services/Ordering/Ordering.Domain/Events/OrderShippedDomainEvent.cs
  32. +3
    -1
      src/Services/Ordering/Ordering.Domain/Events/OrderStartedDomainEvent.cs
  33. +2
    -0
      src/Services/Ordering/Ordering.Infrastructure/EntityConfigurations/BuyerEntityTYpeConfiguration.cs
  34. +10
    -0
      src/Services/Ordering/Ordering.Infrastructure/Repositories/BuyerRepository.cs
  35. +1
    -0
      src/Web/WebMVC/AppSettings.cs
  36. +26
    -27
      src/Web/WebMVC/Views/Order/Index.cshtml
  37. +51
    -0
      src/Web/WebMVC/Views/Shared/_Layout.cshtml
  38. +1
    -0
      src/Web/WebMVC/WebMVC.csproj
  39. +2
    -1
      src/Web/WebMVC/bower.json
  40. +16
    -1
      src/Web/WebMVC/bundleconfig.json
  41. +26
    -0
      src/Web/WebMVC/package-lock.json
  42. +10
    -0
      src/Web/WebMVC/package.json
  43. +3319
    -1
      src/Web/WebMVC/wwwroot/js/site.js
  44. +13
    -0
      src/Web/WebMVC/wwwroot/js/site.min.js
  45. +115
    -0
      src/Web/WebSPA/WebSPA.csproj
  46. +2
    -2
      test/Services/UnitTest/Ordering/Application/NewOrderCommandHandlerTest.cs
  47. +11
    -7
      test/Services/UnitTest/Ordering/Application/OrdersWebApiTest.cs
  48. +8
    -4
      test/Services/UnitTest/Ordering/Domain/BuyerAggregateTest.cs

+ 19
- 0
docker-compose.override.yml View File

@ -145,6 +145,7 @@ services:
- BasketUrlHC=http://basket.api/hc - BasketUrlHC=http://basket.api/hc
- MarketingUrlHC=http://marketing.api/hc - MarketingUrlHC=http://marketing.api/hc
- PaymentUrlHC=http://payment.api/hc - PaymentUrlHC=http://payment.api/hc
- ExternalPurchaseUrl=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5202
- UseCustomizationData=True - UseCustomizationData=True
- ApplicationInsights__InstrumentationKey=${INSTRUMENTATION_KEY} - ApplicationInsights__InstrumentationKey=${INSTRUMENTATION_KEY}
- OrchestratorType=${ORCHESTRATOR_TYPE} - OrchestratorType=${ORCHESTRATOR_TYPE}
@ -202,6 +203,24 @@ services:
ports: ports:
- "5109:80" # Important: In a production environment your should remove the external port (5109) kept here for microservice debugging purposes. - "5109:80" # Important: In a production environment your should remove the external port (5109) kept here for microservice debugging purposes.
# The API Gateway redirects and access through the internal port (80). # The API Gateway redirects and access through the internal port (80).
ordering.backgroundtasks:
environment:
- ASPNETCORE_ENVIRONMENT=Development
- ASPNETCORE_URLS=http://0.0.0.0:80
- ConnectionString=${ESHOP_AZURE_ORDERING_DB:-Server=sql.data;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word}
- EventBusConnection=${ESHOP_AZURE_SERVICE_BUS:-rabbitmq}
- EventBusUserName=${ESHOP_SERVICE_BUS_USERNAME}
- EventBusPassword=${ESHOP_SERVICE_BUS_PASSWORD}
- UseCustomizationData=True
- AzureServiceBusEnabled=False
- CheckUpdateTime=30000
- GracePeriodTime=1
- ApplicationInsights__InstrumentationKey=${INSTRUMENTATION_KEY}
- OrchestratorType=${ORCHESTRATOR_TYPE}
- UseLoadTest=${USE_LOADTEST:-False}
ports:
- "5111:80"
sql.data: sql.data:
environment: environment:


+ 8
- 0
docker-compose.yml View File

@ -144,3 +144,11 @@ services:
context: . context: .
dockerfile: src/ApiGateways/Web.Bff.Shopping/aggregator/Dockerfile dockerfile: src/ApiGateways/Web.Bff.Shopping/aggregator/Dockerfile
ordering.backgroundtasks:
image: eshop/ordering.backgroundtasks:${TAG:-latest}
build:
context: .
dockerfile: src/Services/Ordering/Ordering.BackgroundTasks/Dockerfile
depends_on:
- sql.data
- rabbitmq

+ 51
- 0
eShopOnContainers-ServicesAndWebApps.sln View File

@ -128,6 +128,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Mobile.Shopping.HttpAggrega
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Web.Shopping.HttpAggregator", "src\ApiGateways\Web.Bff.Shopping\aggregator\Web.Shopping.HttpAggregator.csproj", "{AF0828DB-8BDD-411A-AEEF-B780FBB8D8C1}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Web.Shopping.HttpAggregator", "src\ApiGateways\Web.Bff.Shopping\aggregator\Web.Shopping.HttpAggregator.csproj", "{AF0828DB-8BDD-411A-AEEF-B780FBB8D8C1}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ordering.BackgroundTasks", "src\Services\Ordering\Ordering.BackgroundTasks\Ordering.BackgroundTasks.csproj", "{7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}"
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
@ -1486,6 +1488,54 @@ Global
{AF0828DB-8BDD-411A-AEEF-B780FBB8D8C1}.Release|x64.Build.0 = Release|Any CPU {AF0828DB-8BDD-411A-AEEF-B780FBB8D8C1}.Release|x64.Build.0 = Release|Any CPU
{AF0828DB-8BDD-411A-AEEF-B780FBB8D8C1}.Release|x86.ActiveCfg = Release|Any CPU {AF0828DB-8BDD-411A-AEEF-B780FBB8D8C1}.Release|x86.ActiveCfg = Release|Any CPU
{AF0828DB-8BDD-411A-AEEF-B780FBB8D8C1}.Release|x86.Build.0 = Release|Any CPU {AF0828DB-8BDD-411A-AEEF-B780FBB8D8C1}.Release|x86.Build.0 = Release|Any CPU
{7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
{7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
{7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU
{7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU
{7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
{7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
{7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
{7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU
{7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Ad-Hoc|x64.Build.0 = Debug|Any CPU
{7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU
{7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Ad-Hoc|x86.Build.0 = Debug|Any CPU
{7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
{7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.AppStore|Any CPU.Build.0 = Debug|Any CPU
{7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.AppStore|ARM.ActiveCfg = Debug|Any CPU
{7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.AppStore|ARM.Build.0 = Debug|Any CPU
{7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
{7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.AppStore|iPhone.Build.0 = Debug|Any CPU
{7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
{7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.AppStore|x64.ActiveCfg = Debug|Any CPU
{7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.AppStore|x64.Build.0 = Debug|Any CPU
{7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.AppStore|x86.ActiveCfg = Debug|Any CPU
{7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.AppStore|x86.Build.0 = Debug|Any CPU
{7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Debug|ARM.ActiveCfg = Debug|Any CPU
{7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Debug|ARM.Build.0 = Debug|Any CPU
{7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Debug|iPhone.Build.0 = Debug|Any CPU
{7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Debug|x64.ActiveCfg = Debug|Any CPU
{7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Debug|x64.Build.0 = Debug|Any CPU
{7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Debug|x86.ActiveCfg = Debug|Any CPU
{7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Debug|x86.Build.0 = Debug|Any CPU
{7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Release|Any CPU.Build.0 = Release|Any CPU
{7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Release|ARM.ActiveCfg = Release|Any CPU
{7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Release|ARM.Build.0 = Release|Any CPU
{7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Release|iPhone.ActiveCfg = Release|Any CPU
{7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Release|iPhone.Build.0 = Release|Any CPU
{7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Release|x64.ActiveCfg = Release|Any CPU
{7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Release|x64.Build.0 = Release|Any CPU
{7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Release|x86.ActiveCfg = Release|Any CPU
{7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@ -1541,6 +1591,7 @@ Global
{3F79558C-485D-49E1-BD3E-E12538D3D308} = {EC91ADE9-3D66-4AB2-9FB4-2B585E1F3531} {3F79558C-485D-49E1-BD3E-E12538D3D308} = {EC91ADE9-3D66-4AB2-9FB4-2B585E1F3531}
{BEA37D6D-4CF2-4AE8-9575-72388E54FBD0} = {0189E4FB-6E2B-4F2E-9B1D-5473D23FC6DB} {BEA37D6D-4CF2-4AE8-9575-72388E54FBD0} = {0189E4FB-6E2B-4F2E-9B1D-5473D23FC6DB}
{AF0828DB-8BDD-411A-AEEF-B780FBB8D8C1} = {28C0F5C8-4849-4035-80AB-45639424E73F} {AF0828DB-8BDD-411A-AEEF-B780FBB8D8C1} = {28C0F5C8-4849-4035-80AB-45639424E73F}
{7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931} = {0BD0DB92-2D98-44D9-9AC0-C59186D59B0B}
EndGlobalSection EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {25728519-5F0F-4973-8A64-0A81EB4EA8D9} SolutionGuid = {25728519-5F0F-4973-8A64-0A81EB4EA8D9}


+ 11
- 0
package-lock.json View File

@ -0,0 +1,11 @@
{
"requires": true,
"lockfileVersion": 1,
"dependencies": {
"@aspnet/signalr": {
"version": "1.0.0-preview1-update1",
"resolved": "https://registry.npmjs.org/@aspnet/signalr/-/signalr-1.0.0-preview1-update1.tgz",
"integrity": "sha512-TGFCoLa2svN37Ew5ue0kGFxbkmQzq2I9N5TMLFBWRrpTYF4txlE3yPX0EaPt/NToKBaK1A+VK8Q+1MGSYtnqUw=="
}
}
}

+ 3
- 1
src/Services/Basket/Basket.API/Controllers/BasketController.cs View File

@ -59,6 +59,8 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.Controllers
public async Task<IActionResult> Checkout([FromBody]BasketCheckout basketCheckout, [FromHeader(Name = "x-requestid")] string requestId) public async Task<IActionResult> Checkout([FromBody]BasketCheckout basketCheckout, [FromHeader(Name = "x-requestid")] string requestId)
{ {
var userId = _identitySvc.GetUserIdentity(); var userId = _identitySvc.GetUserIdentity();
var userName = User.FindFirst(x => x.Type == "unique_name").Value;
basketCheckout.RequestId = (Guid.TryParse(requestId, out Guid guid) && guid != Guid.Empty) ? basketCheckout.RequestId = (Guid.TryParse(requestId, out Guid guid) && guid != Guid.Empty) ?
guid : basketCheckout.RequestId; guid : basketCheckout.RequestId;
@ -69,7 +71,7 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.Controllers
return BadRequest(); return BadRequest();
} }
var eventMessage = new UserCheckoutAcceptedIntegrationEvent(userId, basketCheckout.City, basketCheckout.Street,
var eventMessage = new UserCheckoutAcceptedIntegrationEvent(userId, userName, basketCheckout.City, basketCheckout.Street,
basketCheckout.State, basketCheckout.Country, basketCheckout.ZipCode, basketCheckout.CardNumber, basketCheckout.CardHolderName, basketCheckout.State, basketCheckout.Country, basketCheckout.ZipCode, basketCheckout.CardNumber, basketCheckout.CardHolderName,
basketCheckout.CardExpiration, basketCheckout.CardSecurityNumber, basketCheckout.CardTypeId, basketCheckout.Buyer, basketCheckout.RequestId, basket); basketCheckout.CardExpiration, basketCheckout.CardSecurityNumber, basketCheckout.CardTypeId, basketCheckout.Buyer, basketCheckout.RequestId, basket);


+ 4
- 1
src/Services/Basket/Basket.API/IntegrationEvents/Events/UserCheckoutAcceptedIntegrationEvent.cs View File

@ -8,6 +8,8 @@ namespace Basket.API.IntegrationEvents.Events
{ {
public string UserId { get; } public string UserId { get; }
public string UserName { get; }
public int OrderNumber { get; set; } public int OrderNumber { get; set; }
public string City { get; set; } public string City { get; set; }
@ -36,12 +38,13 @@ namespace Basket.API.IntegrationEvents.Events
public CustomerBasket Basket { get; } public CustomerBasket Basket { get; }
public UserCheckoutAcceptedIntegrationEvent(string userId, string city, string street,
public UserCheckoutAcceptedIntegrationEvent(string userId, string userName, string city, string street,
string state, string country, string zipCode, string cardNumber, string cardHolderName, string state, string country, string zipCode, string cardNumber, string cardHolderName,
DateTime cardExpiration, string cardSecurityNumber, int cardTypeId, string buyer, Guid requestId, DateTime cardExpiration, string cardSecurityNumber, int cardTypeId, string buyer, Guid requestId,
CustomerBasket basket) CustomerBasket basket)
{ {
UserId = userId; UserId = userId;
UserName = userName;
City = city; City = city;
Street = street; Street = street;
State = state; State = state;


+ 3
- 1
src/Services/Identity/Identity.API/Services/ProfileService.cs View File

@ -5,6 +5,7 @@ using Microsoft.AspNetCore.Identity;
using Microsoft.eShopOnContainers.Services.Identity.API.Models; using Microsoft.eShopOnContainers.Services.Identity.API.Models;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq; using System.Linq;
using System.Security.Claims; using System.Security.Claims;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -68,7 +69,8 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API.Services
var claims = new List<Claim> var claims = new List<Claim>
{ {
new Claim(JwtClaimTypes.Subject, user.Id), new Claim(JwtClaimTypes.Subject, user.Id),
new Claim(JwtClaimTypes.PreferredUserName, user.UserName)
new Claim(JwtClaimTypes.PreferredUserName, user.UserName),
new Claim(JwtRegisteredClaimNames.UniqueName, user.UserName)
}; };
if (!string.IsNullOrWhiteSpace(user.Name)) if (!string.IsNullOrWhiteSpace(user.Name))


+ 5
- 1
src/Services/Ordering/Ordering.API/Application/Commands/CreateOrderCommand.cs View File

@ -27,6 +27,9 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands
[DataMember] [DataMember]
public string UserId { get; private set; } public string UserId { get; private set; }
[DataMember]
public string UserName { get; private set; }
[DataMember] [DataMember]
public string City { get; private set; } public string City { get; private set; }
@ -65,12 +68,13 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands
_orderItems = new List<OrderItemDTO>(); _orderItems = new List<OrderItemDTO>();
} }
public CreateOrderCommand(List<BasketItem> basketItems, string userId, string city, string street, string state, string country, string zipcode,
public CreateOrderCommand(List<BasketItem> basketItems, string userId, string userName, string city, string street, string state, string country, string zipcode,
string cardNumber, string cardHolderName, DateTime cardExpiration, string cardNumber, string cardHolderName, DateTime cardExpiration,
string cardSecurityNumber, int cardTypeId) : this() string cardSecurityNumber, int cardTypeId) : this()
{ {
_orderItems = basketItems.ToOrderItemsDTO().ToList(); _orderItems = basketItems.ToOrderItemsDTO().ToList();
UserId = userId; UserId = userId;
UserName = userName;
City = city; City = city;
Street = street; Street = street;
State = state; State = state;


+ 1
- 1
src/Services/Ordering/Ordering.API/Application/Commands/CreateOrderCommandHandler.cs View File

@ -31,7 +31,7 @@
// methods and constructor so validations, invariants and business logic // methods and constructor so validations, invariants and business logic
// make sure that consistency is preserved across the whole aggregate // make sure that consistency is preserved across the whole aggregate
var address = new Address(message.Street, message.City, message.State, message.Country, message.ZipCode); var address = new Address(message.Street, message.City, message.State, message.Country, message.ZipCode);
var order = new Order(message.UserId, address, message.CardTypeId, message.CardNumber, message.CardSecurityNumber, message.CardHolderName, message.CardExpiration);
var order = new Order(message.UserId, message.UserName, address, message.CardTypeId, message.CardNumber, message.CardSecurityNumber, message.CardHolderName, message.CardExpiration);
foreach (var item in message.OrderItems) foreach (var item in message.OrderItems)
{ {


+ 50
- 0
src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderCancelled/OrderCancelledDomainEventHandler.cs View File

@ -0,0 +1,50 @@
using MediatR;
using Microsoft.AspNetCore.SignalR;
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate;
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate;
using Microsoft.Extensions.Logging;
using Ordering.API.Infrastructure.Hubs;
using Ordering.Domain.Events;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace Ordering.API.Application.DomainEventHandlers.OrderCancelled
{
public class OrderCancelledDomainEventHandler
: INotificationHandler<OrderCancelledDomainEvent>
{
private readonly IOrderRepository _orderRepository;
private readonly IBuyerRepository _buyerRepository;
private readonly ILoggerFactory _logger;
private readonly IHubContext<NotificationsHub> _hubContext;
public OrderCancelledDomainEventHandler(
IOrderRepository orderRepository,
ILoggerFactory logger,
IBuyerRepository buyerRepository,
IHubContext<NotificationsHub> hubContext)
{
_orderRepository = orderRepository ?? throw new ArgumentNullException(nameof(orderRepository));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_buyerRepository = buyerRepository ?? throw new ArgumentNullException(nameof(buyerRepository));
_hubContext = hubContext ?? throw new ArgumentNullException(nameof(hubContext));
}
public async Task Handle(OrderCancelledDomainEvent orderCancelledDomainEvent, CancellationToken cancellationToken)
{
_logger.CreateLogger(nameof(OrderCancelledDomainEvent))
.LogTrace($"Order with Id: {orderCancelledDomainEvent.Order.Id} has been successfully updated with " +
$"a status order id: {OrderStatus.Shipped.Id}");
var order = await _orderRepository.GetAsync(orderCancelledDomainEvent.Order.Id);
var buyer = await _buyerRepository.FindByIdAsync(order.GetBuyerId.Value.ToString());
await _hubContext.Clients
.Group(buyer.Name)
.SendAsync("UpdatedOrderState", new { OrderId = order.Id, Status = order.OrderStatus.Name });
}
}
}

+ 20
- 1
src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderGracePeriodConfirmed/OrderStatusChangedToAwaitingValidationDomainEventHandler.cs View File

@ -10,21 +10,32 @@
using System.Linq; using System.Linq;
using Ordering.API.Application.IntegrationEvents.Events; using Ordering.API.Application.IntegrationEvents.Events;
using System.Threading; using System.Threading;
using Microsoft.AspNetCore.SignalR;
using Ordering.API.Infrastructure.Hubs;
using Microsoft.AspNetCore.Http;
using Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure.Services;
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate;
public class OrderStatusChangedToAwaitingValidationDomainEventHandler public class OrderStatusChangedToAwaitingValidationDomainEventHandler
: INotificationHandler<OrderStatusChangedToAwaitingValidationDomainEvent> : INotificationHandler<OrderStatusChangedToAwaitingValidationDomainEvent>
{ {
private readonly IOrderRepository _orderRepository; private readonly IOrderRepository _orderRepository;
private readonly ILoggerFactory _logger; private readonly ILoggerFactory _logger;
private readonly IBuyerRepository _buyerRepository;
private readonly IOrderingIntegrationEventService _orderingIntegrationEventService; private readonly IOrderingIntegrationEventService _orderingIntegrationEventService;
private readonly IHubContext<NotificationsHub> _hubContext;
public OrderStatusChangedToAwaitingValidationDomainEventHandler( public OrderStatusChangedToAwaitingValidationDomainEventHandler(
IOrderRepository orderRepository, ILoggerFactory logger, IOrderRepository orderRepository, ILoggerFactory logger,
IOrderingIntegrationEventService orderingIntegrationEventService)
IBuyerRepository buyerRepository,
IOrderingIntegrationEventService orderingIntegrationEventService,
IHubContext<NotificationsHub> hubContext)
{ {
_orderRepository = orderRepository ?? throw new ArgumentNullException(nameof(orderRepository)); _orderRepository = orderRepository ?? throw new ArgumentNullException(nameof(orderRepository));
_logger = logger ?? throw new ArgumentNullException(nameof(logger)); _logger = logger ?? throw new ArgumentNullException(nameof(logger));
_buyerRepository = buyerRepository;
_orderingIntegrationEventService = orderingIntegrationEventService; _orderingIntegrationEventService = orderingIntegrationEventService;
_hubContext = hubContext ?? throw new ArgumentNullException(nameof(hubContext));
} }
public async Task Handle(OrderStatusChangedToAwaitingValidationDomainEvent orderStatusChangedToAwaitingValidationDomainEvent, CancellationToken cancellationToken) public async Task Handle(OrderStatusChangedToAwaitingValidationDomainEvent orderStatusChangedToAwaitingValidationDomainEvent, CancellationToken cancellationToken)
@ -33,12 +44,20 @@
.LogTrace($"Order with Id: {orderStatusChangedToAwaitingValidationDomainEvent.OrderId} has been successfully updated with " + .LogTrace($"Order with Id: {orderStatusChangedToAwaitingValidationDomainEvent.OrderId} has been successfully updated with " +
$"a status order id: {OrderStatus.AwaitingValidation.Id}"); $"a status order id: {OrderStatus.AwaitingValidation.Id}");
var order = await _orderRepository.GetAsync(orderStatusChangedToAwaitingValidationDomainEvent.OrderId);
var buyer = await _buyerRepository.FindByIdAsync(order.GetBuyerId.Value.ToString());
var orderStockList = orderStatusChangedToAwaitingValidationDomainEvent.OrderItems var orderStockList = orderStatusChangedToAwaitingValidationDomainEvent.OrderItems
.Select(orderItem => new OrderStockItem(orderItem.ProductId, orderItem.GetUnits())); .Select(orderItem => new OrderStockItem(orderItem.ProductId, orderItem.GetUnits()));
var orderStatusChangedToAwaitingValidationIntegrationEvent = new OrderStatusChangedToAwaitingValidationIntegrationEvent( var orderStatusChangedToAwaitingValidationIntegrationEvent = new OrderStatusChangedToAwaitingValidationIntegrationEvent(
orderStatusChangedToAwaitingValidationDomainEvent.OrderId, orderStockList); orderStatusChangedToAwaitingValidationDomainEvent.OrderId, orderStockList);
await _orderingIntegrationEventService.PublishThroughEventBusAsync(orderStatusChangedToAwaitingValidationIntegrationEvent); await _orderingIntegrationEventService.PublishThroughEventBusAsync(orderStatusChangedToAwaitingValidationIntegrationEvent);
await _hubContext.Clients
.Group(buyer.Name)
.SendAsync("UpdatedOrderState", new { OrderId = order.Id, Status = order.OrderStatus.Name });
} }
} }
} }

+ 18
- 2
src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderPaid/OrderStatusChangedToPaidDomainEventHandler.cs View File

@ -10,21 +10,30 @@
using System.Linq; using System.Linq;
using Ordering.API.Application.IntegrationEvents.Events; using Ordering.API.Application.IntegrationEvents.Events;
using System.Threading; using System.Threading;
using Microsoft.AspNetCore.SignalR;
using Ordering.API.Infrastructure.Hubs;
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate;
public class OrderStatusChangedToPaidDomainEventHandler public class OrderStatusChangedToPaidDomainEventHandler
: INotificationHandler<OrderStatusChangedToPaidDomainEvent> : INotificationHandler<OrderStatusChangedToPaidDomainEvent>
{ {
private readonly IOrderRepository _orderRepository; private readonly IOrderRepository _orderRepository;
private readonly ILoggerFactory _logger; private readonly ILoggerFactory _logger;
private readonly IBuyerRepository _buyerRepository;
private readonly IOrderingIntegrationEventService _orderingIntegrationEventService; private readonly IOrderingIntegrationEventService _orderingIntegrationEventService;
private readonly IHubContext<NotificationsHub> _hubContext;
public OrderStatusChangedToPaidDomainEventHandler( public OrderStatusChangedToPaidDomainEventHandler(
IOrderRepository orderRepository, ILoggerFactory logger, IOrderRepository orderRepository, ILoggerFactory logger,
IOrderingIntegrationEventService orderingIntegrationEventService)
IBuyerRepository buyerRepository,
IOrderingIntegrationEventService orderingIntegrationEventService,
IHubContext<NotificationsHub> hubContext)
{ {
_orderRepository = orderRepository ?? throw new ArgumentNullException(nameof(orderRepository)); _orderRepository = orderRepository ?? throw new ArgumentNullException(nameof(orderRepository));
_logger = logger ?? throw new ArgumentNullException(nameof(logger)); _logger = logger ?? throw new ArgumentNullException(nameof(logger));
_orderingIntegrationEventService = orderingIntegrationEventService;
_buyerRepository = buyerRepository ?? throw new ArgumentNullException(nameof(buyerRepository));
_orderingIntegrationEventService = orderingIntegrationEventService ?? throw new ArgumentNullException(nameof(orderingIntegrationEventService));
_hubContext = hubContext ?? throw new ArgumentNullException(nameof(hubContext));
} }
public async Task Handle(OrderStatusChangedToPaidDomainEvent orderStatusChangedToPaidDomainEvent, CancellationToken cancellationToken) public async Task Handle(OrderStatusChangedToPaidDomainEvent orderStatusChangedToPaidDomainEvent, CancellationToken cancellationToken)
@ -33,12 +42,19 @@
.LogTrace($"Order with Id: {orderStatusChangedToPaidDomainEvent.OrderId} has been successfully updated with " + .LogTrace($"Order with Id: {orderStatusChangedToPaidDomainEvent.OrderId} has been successfully updated with " +
$"a status order id: {OrderStatus.Paid.Id}"); $"a status order id: {OrderStatus.Paid.Id}");
var order = await _orderRepository.GetAsync(orderStatusChangedToPaidDomainEvent.OrderId);
var buyer = await _buyerRepository.FindByIdAsync(order.GetBuyerId.Value.ToString());
var orderStockList = orderStatusChangedToPaidDomainEvent.OrderItems var orderStockList = orderStatusChangedToPaidDomainEvent.OrderItems
.Select(orderItem => new OrderStockItem(orderItem.ProductId, orderItem.GetUnits())); .Select(orderItem => new OrderStockItem(orderItem.ProductId, orderItem.GetUnits()));
var orderStatusChangedToPaidIntegrationEvent = new OrderStatusChangedToPaidIntegrationEvent(orderStatusChangedToPaidDomainEvent.OrderId, var orderStatusChangedToPaidIntegrationEvent = new OrderStatusChangedToPaidIntegrationEvent(orderStatusChangedToPaidDomainEvent.OrderId,
orderStockList); orderStockList);
await _orderingIntegrationEventService.PublishThroughEventBusAsync(orderStatusChangedToPaidIntegrationEvent); await _orderingIntegrationEventService.PublishThroughEventBusAsync(orderStatusChangedToPaidIntegrationEvent);
await _hubContext.Clients
.Group(buyer.Name)
.SendAsync("UpdatedOrderState", new { OrderId = order.Id, Status = order.OrderStatus.Name });
} }
} }
} }

+ 50
- 0
src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderShipped/OrderShippedDomainEventHandler.cs View File

@ -0,0 +1,50 @@
using MediatR;
using Microsoft.AspNetCore.SignalR;
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate;
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate;
using Microsoft.Extensions.Logging;
using Ordering.API.Infrastructure.Hubs;
using Ordering.Domain.Events;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace Ordering.API.Application.DomainEventHandlers.OrderShipped
{
public class OrderShippedDomainEventHandler
: INotificationHandler<OrderShippedDomainEvent>
{
private readonly IOrderRepository _orderRepository;
private readonly IBuyerRepository _buyerRepository;
private readonly ILoggerFactory _logger;
private readonly IHubContext<NotificationsHub> _hubContext;
public OrderShippedDomainEventHandler(
IOrderRepository orderRepository,
ILoggerFactory logger,
IBuyerRepository buyerRepository,
IHubContext<NotificationsHub> hubContext)
{
_orderRepository = orderRepository ?? throw new ArgumentNullException(nameof(orderRepository));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_buyerRepository = buyerRepository ?? throw new ArgumentNullException(nameof(buyerRepository));
_hubContext = hubContext ?? throw new ArgumentNullException(nameof(hubContext));
}
public async Task Handle(OrderShippedDomainEvent orderShippedDomainEvent, CancellationToken cancellationToken)
{
_logger.CreateLogger(nameof(OrderShippedDomainEvent))
.LogTrace($"Order with Id: {orderShippedDomainEvent.Order.Id} has been successfully updated with " +
$"a status order id: {OrderStatus.Shipped.Id}");
var order = await _orderRepository.GetAsync(orderShippedDomainEvent.Order.Id);
var buyer = await _buyerRepository.FindByIdAsync(order.GetBuyerId.Value.ToString());
await _hubContext.Clients
.Group(buyer.Name)
.SendAsync("UpdatedOrderState", new { OrderId = order.Id, Status = order.OrderStatus.Name });
}
}
}

+ 6
- 3
src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderStartedEvent/ValidateOrAddBuyerAggregateWhenOrderStartedDomainEventHandler.cs View File

@ -1,4 +1,5 @@
using MediatR; using MediatR;
using Microsoft.AspNetCore.Http;
using Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure.Services; using Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure.Services;
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate; using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
@ -24,14 +25,14 @@ namespace Ordering.API.Application.DomainEventHandlers.OrderStartedEvent
} }
public async Task Handle(OrderStartedDomainEvent orderStartedEvent, CancellationToken cancellationToken) public async Task Handle(OrderStartedDomainEvent orderStartedEvent, CancellationToken cancellationToken)
{
{
var cardTypeId = (orderStartedEvent.CardTypeId != 0) ? orderStartedEvent.CardTypeId : 1; var cardTypeId = (orderStartedEvent.CardTypeId != 0) ? orderStartedEvent.CardTypeId : 1;
var buyer = await _buyerRepository.FindAsync(orderStartedEvent.UserId); var buyer = await _buyerRepository.FindAsync(orderStartedEvent.UserId);
bool buyerOriginallyExisted = (buyer == null) ? false : true; bool buyerOriginallyExisted = (buyer == null) ? false : true;
if (!buyerOriginallyExisted) if (!buyerOriginallyExisted)
{ {
buyer = new Buyer(orderStartedEvent.UserId);
buyer = new Buyer(orderStartedEvent.UserId, orderStartedEvent.UserName);
} }
buyer.VerifyOrAddPaymentMethod(cardTypeId, buyer.VerifyOrAddPaymentMethod(cardTypeId,
@ -42,7 +43,9 @@ namespace Ordering.API.Application.DomainEventHandlers.OrderStartedEvent
orderStartedEvent.CardExpiration, orderStartedEvent.CardExpiration,
orderStartedEvent.Order.Id); orderStartedEvent.Order.Id);
var buyerUpdated = buyerOriginallyExisted ? _buyerRepository.Update(buyer) : _buyerRepository.Add(buyer);
var buyerUpdated = buyerOriginallyExisted ?
_buyerRepository.Update(buyer) :
_buyerRepository.Add(buyer);
await _buyerRepository.UnitOfWork await _buyerRepository.UnitOfWork
.SaveEntitiesAsync(); .SaveEntitiesAsync();


+ 18
- 1
src/Services/Ordering/Ordering.API/Application/DomainEventHandlers/OrderStockConfirmed/OrderStatusChangedToStockConfirmedDomainEventHandler.cs View File

@ -9,20 +9,30 @@
using Ordering.API.Application.IntegrationEvents; using Ordering.API.Application.IntegrationEvents;
using Ordering.API.Application.IntegrationEvents.Events; using Ordering.API.Application.IntegrationEvents.Events;
using System.Threading; using System.Threading;
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate;
using Microsoft.AspNetCore.SignalR;
using Ordering.API.Infrastructure.Hubs;
public class OrderStatusChangedToStockConfirmedDomainEventHandler public class OrderStatusChangedToStockConfirmedDomainEventHandler
: INotificationHandler<OrderStatusChangedToStockConfirmedDomainEvent> : INotificationHandler<OrderStatusChangedToStockConfirmedDomainEvent>
{ {
private readonly IOrderRepository _orderRepository; private readonly IOrderRepository _orderRepository;
private readonly IBuyerRepository _buyerRepository;
private readonly ILoggerFactory _logger; private readonly ILoggerFactory _logger;
private readonly IHubContext<NotificationsHub> _hubContext;
private readonly IOrderingIntegrationEventService _orderingIntegrationEventService; private readonly IOrderingIntegrationEventService _orderingIntegrationEventService;
public OrderStatusChangedToStockConfirmedDomainEventHandler( public OrderStatusChangedToStockConfirmedDomainEventHandler(
IOrderRepository orderRepository, ILoggerFactory logger,
IOrderRepository orderRepository,
IBuyerRepository buyerRepository,
ILoggerFactory logger,
IHubContext<NotificationsHub> hubContext,
IOrderingIntegrationEventService orderingIntegrationEventService) IOrderingIntegrationEventService orderingIntegrationEventService)
{ {
_orderRepository = orderRepository ?? throw new ArgumentNullException(nameof(orderRepository)); _orderRepository = orderRepository ?? throw new ArgumentNullException(nameof(orderRepository));
_buyerRepository = buyerRepository ?? throw new ArgumentNullException(nameof(buyerRepository));
_logger = logger ?? throw new ArgumentNullException(nameof(logger)); _logger = logger ?? throw new ArgumentNullException(nameof(logger));
_hubContext = hubContext ?? throw new ArgumentNullException(nameof(hubContext));
_orderingIntegrationEventService = orderingIntegrationEventService; _orderingIntegrationEventService = orderingIntegrationEventService;
} }
@ -32,8 +42,15 @@
.LogTrace($"Order with Id: {orderStatusChangedToStockConfirmedDomainEvent.OrderId} has been successfully updated with " + .LogTrace($"Order with Id: {orderStatusChangedToStockConfirmedDomainEvent.OrderId} has been successfully updated with " +
$"a status order id: {OrderStatus.StockConfirmed.Id}"); $"a status order id: {OrderStatus.StockConfirmed.Id}");
var order = await _orderRepository.GetAsync(orderStatusChangedToStockConfirmedDomainEvent.OrderId);
var buyer = await _buyerRepository.FindByIdAsync(order.GetBuyerId.Value.ToString());
var orderStatusChangedToStockConfirmedIntegrationEvent = new OrderStatusChangedToStockConfirmedIntegrationEvent(orderStatusChangedToStockConfirmedDomainEvent.OrderId); var orderStatusChangedToStockConfirmedIntegrationEvent = new OrderStatusChangedToStockConfirmedIntegrationEvent(orderStatusChangedToStockConfirmedDomainEvent.OrderId);
await _orderingIntegrationEventService.PublishThroughEventBusAsync(orderStatusChangedToStockConfirmedIntegrationEvent); await _orderingIntegrationEventService.PublishThroughEventBusAsync(orderStatusChangedToStockConfirmedIntegrationEvent);
await _hubContext.Clients
.Group(buyer.Name)
.SendAsync("UpdatedOrderState", new { OrderId = order.Id, Status = order.OrderStatus.Name });
} }
} }
} }

+ 1
- 1
src/Services/Ordering/Ordering.API/Application/IntegrationEvents/EventHandling/UserCheckoutAcceptedIntegrationEventHandler.cs View File

@ -41,7 +41,7 @@ namespace Ordering.API.Application.IntegrationEvents.EventHandling
if (eventMsg.RequestId != Guid.Empty) if (eventMsg.RequestId != Guid.Empty)
{ {
var createOrderCommand = new CreateOrderCommand(eventMsg.Basket.Items, eventMsg.UserId, eventMsg.City, eventMsg.Street,
var createOrderCommand = new CreateOrderCommand(eventMsg.Basket.Items, eventMsg.UserId, eventMsg.UserName, eventMsg.City, eventMsg.Street,
eventMsg.State, eventMsg.Country, eventMsg.ZipCode, eventMsg.State, eventMsg.Country, eventMsg.ZipCode,
eventMsg.CardNumber, eventMsg.CardHolderName, eventMsg.CardExpiration, eventMsg.CardNumber, eventMsg.CardHolderName, eventMsg.CardExpiration,
eventMsg.CardSecurityNumber, eventMsg.CardTypeId); eventMsg.CardSecurityNumber, eventMsg.CardTypeId);


+ 4
- 1
src/Services/Ordering/Ordering.API/Application/IntegrationEvents/Events/UserCheckoutAcceptedIntegrationEvent.cs View File

@ -8,6 +8,8 @@ namespace Ordering.API.Application.IntegrationEvents.Events
{ {
public string UserId { get; } public string UserId { get; }
public string UserName { get; }
public string City { get; set; } public string City { get; set; }
public string Street { get; set; } public string Street { get; set; }
@ -34,7 +36,7 @@ namespace Ordering.API.Application.IntegrationEvents.Events
public CustomerBasket Basket { get; } public CustomerBasket Basket { get; }
public UserCheckoutAcceptedIntegrationEvent(string userId, string city, string street,
public UserCheckoutAcceptedIntegrationEvent(string userId, string userName, string city, string street,
string state, string country, string zipCode, string cardNumber, string cardHolderName, string state, string country, string zipCode, string cardNumber, string cardHolderName,
DateTime cardExpiration, string cardSecurityNumber, int cardTypeId, string buyer, Guid requestId, DateTime cardExpiration, string cardSecurityNumber, int cardTypeId, string buyer, Guid requestId,
CustomerBasket basket) CustomerBasket basket)
@ -53,6 +55,7 @@ namespace Ordering.API.Application.IntegrationEvents.Events
Buyer = buyer; Buyer = buyer;
Basket = basket; Basket = basket;
RequestId = requestId; RequestId = requestId;
UserName = userName;
} }
} }


+ 27
- 0
src/Services/Ordering/Ordering.API/Infrastructure/Hubs/NotificationsHub.cs View File

@ -0,0 +1,27 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.SignalR;
using Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure.Services;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Ordering.API.Infrastructure.Hubs
{
[Authorize]
public class NotificationsHub : Hub
{
public override async Task OnConnectedAsync()
{
await Groups.AddAsync(Context.ConnectionId, Context.User.Identity.Name);
await base.OnConnectedAsync();
}
public override async Task OnDisconnectedAsync(Exception ex)
{
await Groups.RemoveAsync(Context.ConnectionId, Context.User.Identity.Name);
await base.OnDisconnectedAsync(ex);
}
}
}

+ 238
- 0
src/Services/Ordering/Ordering.API/Infrastructure/Migrations/20180412143935_NamePropertyInBuyer.Designer.cs View File

@ -0,0 +1,238 @@
// <auto-generated />
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage;
using Microsoft.EntityFrameworkCore.Storage.Internal;
using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure;
using System;
namespace Ordering.API.Infrastructure.Migrations
{
[DbContext(typeof(OrderingContext))]
[Migration("20180412143935_NamePropertyInBuyer")]
partial class NamePropertyInBuyer
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "2.0.1-rtm-125")
.HasAnnotation("Relational:Sequence:.orderitemseq", "'orderitemseq', '', '1', '10', '', '', 'Int64', 'False'")
.HasAnnotation("Relational:Sequence:ordering.buyerseq", "'buyerseq', 'ordering', '1', '10', '', '', 'Int64', 'False'")
.HasAnnotation("Relational:Sequence:ordering.orderseq", "'orderseq', 'ordering', '1', '10', '', '', 'Int64', 'False'")
.HasAnnotation("Relational:Sequence:ordering.paymentseq", "'paymentseq', 'ordering', '1', '10', '', '', 'Int64', 'False'")
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate.Buyer", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasAnnotation("SqlServer:HiLoSequenceName", "buyerseq")
.HasAnnotation("SqlServer:HiLoSequenceSchema", "ordering")
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.SequenceHiLo);
b.Property<string>("IdentityGuid")
.IsRequired()
.HasMaxLength(200);
b.Property<string>("Name");
b.HasKey("Id");
b.HasIndex("IdentityGuid")
.IsUnique();
b.ToTable("buyers","ordering");
});
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate.CardType", b =>
{
b.Property<int>("Id")
.HasDefaultValue(1);
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(200);
b.HasKey("Id");
b.ToTable("cardtypes","ordering");
});
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate.PaymentMethod", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasAnnotation("SqlServer:HiLoSequenceName", "paymentseq")
.HasAnnotation("SqlServer:HiLoSequenceSchema", "ordering")
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.SequenceHiLo);
b.Property<string>("Alias")
.IsRequired()
.HasMaxLength(200);
b.Property<int>("BuyerId");
b.Property<string>("CardHolderName")
.IsRequired()
.HasMaxLength(200);
b.Property<string>("CardNumber")
.IsRequired()
.HasMaxLength(25);
b.Property<int>("CardTypeId");
b.Property<DateTime>("Expiration");
b.HasKey("Id");
b.HasIndex("BuyerId");
b.HasIndex("CardTypeId");
b.ToTable("paymentmethods","ordering");
});
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.Order", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasAnnotation("SqlServer:HiLoSequenceName", "orderseq")
.HasAnnotation("SqlServer:HiLoSequenceSchema", "ordering")
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.SequenceHiLo);
b.Property<int?>("BuyerId");
b.Property<string>("Description");
b.Property<DateTime>("OrderDate");
b.Property<int>("OrderStatusId");
b.Property<int?>("PaymentMethodId");
b.HasKey("Id");
b.HasIndex("BuyerId");
b.HasIndex("OrderStatusId");
b.HasIndex("PaymentMethodId");
b.ToTable("orders","ordering");
});
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.OrderItem", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasAnnotation("SqlServer:HiLoSequenceName", "orderitemseq")
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.SequenceHiLo);
b.Property<decimal>("Discount");
b.Property<int>("OrderId");
b.Property<string>("PictureUrl");
b.Property<int>("ProductId");
b.Property<string>("ProductName")
.IsRequired();
b.Property<decimal>("UnitPrice");
b.Property<int>("Units");
b.HasKey("Id");
b.HasIndex("OrderId");
b.ToTable("orderItems","ordering");
});
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.OrderStatus", b =>
{
b.Property<int>("Id")
.HasDefaultValue(1);
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(200);
b.HasKey("Id");
b.ToTable("orderstatus","ordering");
});
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Idempotency.ClientRequest", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("Name")
.IsRequired();
b.Property<DateTime>("Time");
b.HasKey("Id");
b.ToTable("requests","ordering");
});
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate.PaymentMethod", b =>
{
b.HasOne("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate.Buyer")
.WithMany("PaymentMethods")
.HasForeignKey("BuyerId")
.OnDelete(DeleteBehavior.Cascade);
b.HasOne("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate.CardType", "CardType")
.WithMany()
.HasForeignKey("CardTypeId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.Order", b =>
{
b.HasOne("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate.Buyer")
.WithMany()
.HasForeignKey("BuyerId");
b.HasOne("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.OrderStatus", "OrderStatus")
.WithMany()
.HasForeignKey("OrderStatusId")
.OnDelete(DeleteBehavior.Cascade);
b.HasOne("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate.PaymentMethod")
.WithMany()
.HasForeignKey("PaymentMethodId")
.OnDelete(DeleteBehavior.Restrict);
b.OwnsOne("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.Address", "Address", b1 =>
{
b1.Property<int>("OrderId");
b1.ToTable("orders","ordering");
b1.HasOne("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.Order")
.WithOne("Address")
.HasForeignKey("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.Address", "OrderId")
.OnDelete(DeleteBehavior.Cascade);
});
});
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.OrderItem", b =>
{
b.HasOne("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.Order")
.WithMany("OrderItems")
.HasForeignKey("OrderId")
.OnDelete(DeleteBehavior.Cascade);
});
#pragma warning restore 612, 618
}
}
}

+ 86
- 0
src/Services/Ordering/Ordering.API/Infrastructure/Migrations/20180412143935_NamePropertyInBuyer.cs View File

@ -0,0 +1,86 @@
using Microsoft.EntityFrameworkCore.Migrations;
using System;
using System.Collections.Generic;
namespace Ordering.API.Infrastructure.Migrations
{
public partial class NamePropertyInBuyer : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_orderItems_orders_OrderId",
schema: "ordering",
table: "orderItems");
migrationBuilder.AddColumn<string>(
name: "Name",
schema: "ordering",
table: "buyers",
nullable: true);
migrationBuilder.AddForeignKey(
name: "FK_orderItems_orders_OrderId",
schema: "ordering",
table: "orderItems",
column: "OrderId",
principalSchema: "ordering",
principalTable: "orders",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_orderItems_orders_OrderId",
schema: "ordering",
table: "orderItems");
migrationBuilder.DropColumn(
name: "Name",
schema: "ordering",
table: "buyers");
migrationBuilder.AddColumn<string>(
name: "City",
schema: "ordering",
table: "orders",
nullable: true);
migrationBuilder.AddColumn<string>(
name: "Country",
schema: "ordering",
table: "orders",
nullable: true);
migrationBuilder.AddColumn<string>(
name: "State",
schema: "ordering",
table: "orders",
nullable: true);
migrationBuilder.AddColumn<string>(
name: "Street",
schema: "ordering",
table: "orders",
nullable: true);
migrationBuilder.AddColumn<string>(
name: "ZipCode",
schema: "ordering",
table: "orders",
nullable: true);
migrationBuilder.AddForeignKey(
name: "FK_orderItems_orders_OrderId",
schema: "ordering",
table: "orderItems",
column: "OrderId",
principalSchema: "ordering",
principalTable: "orders",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
}
}
}

+ 15
- 28
src/Services/Ordering/Ordering.API/Infrastructure/Migrations/OrderingContextModelSnapshot.cs View File

@ -17,7 +17,7 @@ namespace Ordering.API.Migrations
{ {
#pragma warning disable 612, 618 #pragma warning disable 612, 618
modelBuilder modelBuilder
.HasAnnotation("ProductVersion", "2.0.0-preview2-25794")
.HasAnnotation("ProductVersion", "2.0.1-rtm-125")
.HasAnnotation("Relational:Sequence:.orderitemseq", "'orderitemseq', '', '1', '10', '', '', 'Int64', 'False'") .HasAnnotation("Relational:Sequence:.orderitemseq", "'orderitemseq', '', '1', '10', '', '', 'Int64', 'False'")
.HasAnnotation("Relational:Sequence:ordering.buyerseq", "'buyerseq', 'ordering', '1', '10', '', '', 'Int64', 'False'") .HasAnnotation("Relational:Sequence:ordering.buyerseq", "'buyerseq', 'ordering', '1', '10', '', '', 'Int64', 'False'")
.HasAnnotation("Relational:Sequence:ordering.orderseq", "'orderseq', 'ordering', '1', '10', '', '', 'Int64', 'False'") .HasAnnotation("Relational:Sequence:ordering.orderseq", "'orderseq', 'ordering', '1', '10', '', '', 'Int64', 'False'")
@ -36,6 +36,8 @@ namespace Ordering.API.Migrations
.IsRequired() .IsRequired()
.HasMaxLength(200); .HasMaxLength(200);
b.Property<string>("Name");
b.HasKey("Id"); b.HasKey("Id");
b.HasIndex("IdentityGuid") b.HasIndex("IdentityGuid")
@ -180,25 +182,6 @@ namespace Ordering.API.Migrations
b.ToTable("requests","ordering"); b.ToTable("requests","ordering");
}); });
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.Address", b =>
{
b.Property<int?>("OrderId");
b.Property<string>("City");
b.Property<string>("Country");
b.Property<string>("State");
b.Property<string>("Street");
b.Property<string>("ZipCode");
b.HasKey("OrderId");
b.ToTable("orders","ordering");
});
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate.PaymentMethod", b => modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate.PaymentMethod", b =>
{ {
b.HasOne("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate.Buyer") b.HasOne("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate.Buyer")
@ -227,6 +210,18 @@ namespace Ordering.API.Migrations
.WithMany() .WithMany()
.HasForeignKey("PaymentMethodId") .HasForeignKey("PaymentMethodId")
.OnDelete(DeleteBehavior.Restrict); .OnDelete(DeleteBehavior.Restrict);
b.OwnsOne("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.Address", "Address", b1 =>
{
b1.Property<int>("OrderId");
b1.ToTable("orders","ordering");
b1.HasOne("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.Order")
.WithOne("Address")
.HasForeignKey("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.Address", "OrderId")
.OnDelete(DeleteBehavior.Cascade);
});
}); });
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.OrderItem", b => modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.OrderItem", b =>
@ -236,14 +231,6 @@ namespace Ordering.API.Migrations
.HasForeignKey("OrderId") .HasForeignKey("OrderId")
.OnDelete(DeleteBehavior.Cascade); .OnDelete(DeleteBehavior.Cascade);
}); });
modelBuilder.Entity("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.Address", b =>
{
b.HasOne("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.Order")
.WithOne("Address")
.HasForeignKey("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate.Address", "OrderId")
.OnDelete(DeleteBehavior.Cascade);
});
#pragma warning restore 612, 618 #pragma warning restore 612, 618
} }
} }


+ 2
- 0
src/Services/Ordering/Ordering.API/Infrastructure/Services/IIdentityService.cs View File

@ -8,5 +8,7 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure.Servi
public interface IIdentityService public interface IIdentityService
{ {
string GetUserIdentity(); string GetUserIdentity();
string GetUserName();
} }
} }

+ 5
- 0
src/Services/Ordering/Ordering.API/Infrastructure/Services/IdentityService.cs View File

@ -20,5 +20,10 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure.Servi
{ {
return _context.HttpContext.User.FindFirst("sub").Value; return _context.HttpContext.User.FindFirst("sub").Value;
} }
public string GetUserName()
{
return _context.HttpContext.User.Identity.Name;
}
} }
} }

+ 1
- 0
src/Services/Ordering/Ordering.API/Ordering.API.csproj View File

@ -39,6 +39,7 @@
<PackageReference Include="Microsoft.ApplicationInsights.ServiceFabric" Version="2.0.1-beta1" /> <PackageReference Include="Microsoft.ApplicationInsights.ServiceFabric" Version="2.0.1-beta1" />
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.5" /> <PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.5" />
<PackageReference Include="MediatR" Version="4.0.1" /> <PackageReference Include="MediatR" Version="4.0.1" />
<PackageReference Include="Microsoft.AspNetCore.SignalR" Version="1.0.0-preview2-final" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="2.2.0" /> <PackageReference Include="Swashbuckle.AspNetCore" Version="2.2.0" />
<PackageReference Include="System.Reflection" Version="4.3.0" /> <PackageReference Include="System.Reflection" Version="4.3.0" />
<PackageReference Include="Dapper" Version="1.50.4" /> <PackageReference Include="Dapper" Version="1.50.4" />


+ 15
- 3
src/Services/Ordering/Ordering.API/Startup.cs View File

@ -6,6 +6,7 @@
using global::Ordering.API.Application.IntegrationEvents; using global::Ordering.API.Application.IntegrationEvents;
using global::Ordering.API.Application.IntegrationEvents.Events; using global::Ordering.API.Application.IntegrationEvents.Events;
using global::Ordering.API.Infrastructure.Filters; using global::Ordering.API.Infrastructure.Filters;
using global::Ordering.API.Infrastructure.Hubs;
using global::Ordering.API.Infrastructure.Middlewares; using global::Ordering.API.Infrastructure.Middlewares;
using Infrastructure.AutofacModules; using Infrastructure.AutofacModules;
using Infrastructure.Filters; using Infrastructure.Filters;
@ -28,6 +29,8 @@
using Microsoft.Extensions.HealthChecks; using Microsoft.Extensions.HealthChecks;
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Primitives;
using Microsoft.IdentityModel.Tokens;
using Ordering.Infrastructure; using Ordering.Infrastructure;
using RabbitMQ.Client; using RabbitMQ.Client;
using Swashbuckle.AspNetCore.Swagger; using Swashbuckle.AspNetCore.Swagger;
@ -36,6 +39,7 @@
using System.Data.Common; using System.Data.Common;
using System.IdentityModel.Tokens.Jwt; using System.IdentityModel.Tokens.Jwt;
using System.Reflection; using System.Reflection;
using System.Threading.Tasks;
public class Startup public class Startup
{ {
@ -186,6 +190,7 @@
RegisterEventBus(services); RegisterEventBus(services);
ConfigureAuthService(services); ConfigureAuthService(services);
services.AddOptions(); services.AddOptions();
services.AddSignalR();
//configure autofac //configure autofac
@ -199,7 +204,7 @@
} }
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory)
{ {
loggerFactory.AddConsole(Configuration.GetSection("Logging")); loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug(); loggerFactory.AddDebug();
@ -220,6 +225,13 @@
app.UseCors("CorsPolicy"); app.UseCors("CorsPolicy");
ConfigureAuth(app); ConfigureAuth(app);
app.UseSignalR(routes =>
{
routes.MapHub<NotificationsHub>("/notificationhub", options =>
options.Transports = AspNetCore.Http.Connections.TransportType.All);
});
app.UseMvcWithDefaultRoute(); app.UseMvcWithDefaultRoute();
app.UseSwagger() app.UseSwagger()
@ -266,7 +278,7 @@
private void ConfigureAuthService(IServiceCollection services) private void ConfigureAuthService(IServiceCollection services)
{ {
// prevent from mapping "sub" claim to nameidentifier. // prevent from mapping "sub" claim to nameidentifier.
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Remove("sub");
var identityUrl = Configuration.GetValue<string>("IdentityUrl"); var identityUrl = Configuration.GetValue<string>("IdentityUrl");
@ -279,7 +291,7 @@
{ {
options.Authority = identityUrl; options.Authority = identityUrl;
options.RequireHttpsMetadata = false; options.RequireHttpsMetadata = false;
options.Audience = "orders";
options.Audience = "orders";
}); });
} }


+ 2
- 1
src/Services/Ordering/Ordering.API/settings.json View File

@ -17,5 +17,6 @@
"ApplicationInsights": { "ApplicationInsights": {
"InstrumentationKey": "" "InstrumentationKey": ""
}, },
"EventBusRetryCount": 5
"EventBusRetryCount": 5,
"EventBusConnection": "localhost"
} }

+ 4
- 1
src/Services/Ordering/Ordering.Domain/AggregatesModel/BuyerAggregate/Buyer.cs View File

@ -11,6 +11,8 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.B
{ {
public string IdentityGuid { get; private set; } public string IdentityGuid { get; private set; }
public string Name { get; private set; }
private List<PaymentMethod> _paymentMethods; private List<PaymentMethod> _paymentMethods;
public IEnumerable<PaymentMethod> PaymentMethods => _paymentMethods.AsReadOnly(); public IEnumerable<PaymentMethod> PaymentMethods => _paymentMethods.AsReadOnly();
@ -20,9 +22,10 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.B
_paymentMethods = new List<PaymentMethod>(); _paymentMethods = new List<PaymentMethod>();
} }
public Buyer(string identity) : this()
public Buyer(string identity, string name) : this()
{ {
IdentityGuid = !string.IsNullOrWhiteSpace(identity) ? identity : throw new ArgumentNullException(nameof(identity)); IdentityGuid = !string.IsNullOrWhiteSpace(identity) ? identity : throw new ArgumentNullException(nameof(identity));
Name = !string.IsNullOrWhiteSpace(name) ? name : throw new ArgumentNullException(nameof(name));
} }
public PaymentMethod VerifyOrAddPaymentMethod( public PaymentMethod VerifyOrAddPaymentMethod(


+ 1
- 0
src/Services/Ordering/Ordering.Domain/AggregatesModel/BuyerAggregate/IBuyerRepository.cs View File

@ -11,5 +11,6 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.B
Buyer Add(Buyer buyer); Buyer Add(Buyer buyer);
Buyer Update(Buyer buyer); Buyer Update(Buyer buyer);
Task<Buyer> FindAsync(string BuyerIdentityGuid); Task<Buyer> FindAsync(string BuyerIdentityGuid);
Task<Buyer> FindByIdAsync(string id);
} }
} }

+ 7
- 4
src/Services/Ordering/Ordering.Domain/AggregatesModel/OrderAggregate/Order.cs View File

@ -18,6 +18,7 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.O
// Address is a Value Object pattern example persisted as EF Core 2.0 owned entity // Address is a Value Object pattern example persisted as EF Core 2.0 owned entity
public Address Address { get; private set; } public Address Address { get; private set; }
public int? GetBuyerId => _buyerId;
private int? _buyerId; private int? _buyerId;
public OrderStatus OrderStatus { get; private set; } public OrderStatus OrderStatus { get; private set; }
@ -50,7 +51,7 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.O
_isDraft = false; _isDraft = false;
} }
public Order(string userId, Address address, int cardTypeId, string cardNumber, string cardSecurityNumber,
public Order(string userId, string userName, Address address, int cardTypeId, string cardNumber, string cardSecurityNumber,
string cardHolderName, DateTime cardExpiration, int? buyerId = null, int? paymentMethodId = null) : this() string cardHolderName, DateTime cardExpiration, int? buyerId = null, int? paymentMethodId = null) : this()
{ {
_buyerId = buyerId; _buyerId = buyerId;
@ -61,7 +62,7 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.O
// Add the OrderStarterDomainEvent to the domain events collection // Add the OrderStarterDomainEvent to the domain events collection
// to be raised/dispatched when comitting changes into the Database [ After DbContext.SaveChanges() ] // to be raised/dispatched when comitting changes into the Database [ After DbContext.SaveChanges() ]
AddOrderStartedDomainEvent(userId, cardTypeId, cardNumber,
AddOrderStartedDomainEvent(userId, userName, cardTypeId, cardNumber,
cardSecurityNumber, cardHolderName, cardExpiration); cardSecurityNumber, cardHolderName, cardExpiration);
} }
@ -144,6 +145,7 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.O
_orderStatusId = OrderStatus.Shipped.Id; _orderStatusId = OrderStatus.Shipped.Id;
_description = "The order was shipped."; _description = "The order was shipped.";
AddDomainEvent(new OrderShippedDomainEvent(this));
} }
public void SetCancelledStatus() public void SetCancelledStatus()
@ -156,6 +158,7 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.O
_orderStatusId = OrderStatus.Cancelled.Id; _orderStatusId = OrderStatus.Cancelled.Id;
_description = $"The order was cancelled."; _description = $"The order was cancelled.";
AddDomainEvent(new OrderCancelledDomainEvent(this));
} }
public void SetCancelledStatusWhenStockIsRejected(IEnumerable<int> orderStockRejectedItems) public void SetCancelledStatusWhenStockIsRejected(IEnumerable<int> orderStockRejectedItems)
@ -173,10 +176,10 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.O
} }
} }
private void AddOrderStartedDomainEvent(string userId, int cardTypeId, string cardNumber,
private void AddOrderStartedDomainEvent(string userId, string userName, int cardTypeId, string cardNumber,
string cardSecurityNumber, string cardHolderName, DateTime cardExpiration) string cardSecurityNumber, string cardHolderName, DateTime cardExpiration)
{ {
var orderStartedDomainEvent = new OrderStartedDomainEvent(this, userId, cardTypeId,
var orderStartedDomainEvent = new OrderStartedDomainEvent(this, userId, userName, cardTypeId,
cardNumber, cardSecurityNumber, cardNumber, cardSecurityNumber,
cardHolderName, cardExpiration); cardHolderName, cardExpiration);


+ 18
- 0
src/Services/Ordering/Ordering.Domain/Events/OrderCancelledDomainEvent.cs View File

@ -0,0 +1,18 @@
using MediatR;
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate;
using System;
using System.Collections.Generic;
using System.Text;
namespace Ordering.Domain.Events
{
public class OrderCancelledDomainEvent : INotification
{
public Order Order { get; }
public OrderCancelledDomainEvent(Order order)
{
Order = order;
}
}
}

+ 15
- 0
src/Services/Ordering/Ordering.Domain/Events/OrderShippedDomainEvent.cs View File

@ -0,0 +1,15 @@
using MediatR;
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate;
namespace Ordering.Domain.Events
{
public class OrderShippedDomainEvent : INotification
{
public Order Order { get; }
public OrderShippedDomainEvent(Order order)
{
Order = order;
}
}
}

+ 3
- 1
src/Services/Ordering/Ordering.Domain/Events/OrderStartedDomainEvent.cs View File

@ -12,6 +12,7 @@ namespace Ordering.Domain.Events
public class OrderStartedDomainEvent : INotification public class OrderStartedDomainEvent : INotification
{ {
public string UserId { get; } public string UserId { get; }
public string UserName { get; }
public int CardTypeId { get; } public int CardTypeId { get; }
public string CardNumber { get; } public string CardNumber { get; }
public string CardSecurityNumber { get; } public string CardSecurityNumber { get; }
@ -19,13 +20,14 @@ namespace Ordering.Domain.Events
public DateTime CardExpiration { get; } public DateTime CardExpiration { get; }
public Order Order { get; } public Order Order { get; }
public OrderStartedDomainEvent(Order order, string userId,
public OrderStartedDomainEvent(Order order, string userId, string userName,
int cardTypeId, string cardNumber, int cardTypeId, string cardNumber,
string cardSecurityNumber, string cardHolderName, string cardSecurityNumber, string cardHolderName,
DateTime cardExpiration) DateTime cardExpiration)
{ {
Order = order; Order = order;
UserId = userId; UserId = userId;
UserName = userName;
CardTypeId = cardTypeId; CardTypeId = cardTypeId;
CardNumber = cardNumber; CardNumber = cardNumber;
CardSecurityNumber = cardSecurityNumber; CardSecurityNumber = cardSecurityNumber;


+ 2
- 0
src/Services/Ordering/Ordering.Infrastructure/EntityConfigurations/BuyerEntityTYpeConfiguration.cs View File

@ -26,6 +26,8 @@ namespace Ordering.Infrastructure.EntityConfigurations
buyerConfiguration.HasIndex("IdentityGuid") buyerConfiguration.HasIndex("IdentityGuid")
.IsUnique(true); .IsUnique(true);
buyerConfiguration.Property(b => b.Name);
buyerConfiguration.HasMany(b => b.PaymentMethods) buyerConfiguration.HasMany(b => b.PaymentMethods)
.WithOne() .WithOne()
.HasForeignKey("BuyerId") .HasForeignKey("BuyerId")


+ 10
- 0
src/Services/Ordering/Ordering.Infrastructure/Repositories/BuyerRepository.cs View File

@ -54,5 +54,15 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Repositor
return buyer; return buyer;
} }
public async Task<Buyer> FindByIdAsync(string id)
{
var buyer = await _context.Buyers
.Include(b => b.PaymentMethods)
.Where(b => b.Id == int.Parse(id))
.SingleOrDefaultAsync();
return buyer;
}
} }
} }

+ 1
- 0
src/Web/WebMVC/AppSettings.cs View File

@ -11,6 +11,7 @@ namespace Microsoft.eShopOnContainers.WebMVC
public string MarketingUrl { get; set; } public string MarketingUrl { get; set; }
public string PurchaseUrl { get; set; } public string PurchaseUrl { get; set; }
public string ExternalPurchaseUrl { get; set; }
public bool ActivateCampaignDetailFunction { get; set; } public bool ActivateCampaignDetailFunction { get; set; }
public Logging Logging { get; set; } public Logging Logging { get; set; }
public bool UseCustomizationData { get; set; } public bool UseCustomizationData { get; set; }


+ 26
- 27
src/Web/WebMVC/Views/Order/Index.cshtml View File

@ -8,9 +8,9 @@
<div class="esh-orders"> <div class="esh-orders">
@Html.Partial("_Header", new List<Header>() { @Html.Partial("_Header", new List<Header>() {
new Header() { Controller = "Catalog", Text = "Back to catalog" },
new Header() { Text = " / " },
new Header() { Controller = "OrderManagement", Text = "Orders Management" } })
new Header() { Controller = "Catalog", Text = "Back to catalog" },
new Header() { Text = " / " },
new Header() { Controller = "OrderManagement", Text = "Orders Management" } })
<div class="container"> <div class="container">
<article class="esh-orders-titles row"> <article class="esh-orders-titles row">
@ -20,31 +20,30 @@
<section class="esh-orders-title col-xs-2">Status</section> <section class="esh-orders-title col-xs-2">Status</section>
<section class="esh-orders-title col-xs-2"></section> <section class="esh-orders-title col-xs-2"></section>
</article> </article>
@if (Model != null && Model.Any())
{
foreach (var item in Model)
@if (Model != null && Model.Any())
{ {
<article class="esh-orders-items row">
<section class="esh-orders-item col-xs-2">@Html.DisplayFor(modelItem => item.OrderNumber)</section>
<section class="esh-orders-item col-xs-4">@Html.DisplayFor(modelItem => item.Date)</section>
<section class="esh-orders-item col-xs-2">$ @Html.DisplayFor(modelItem => item.Total)</section>
<section class="esh-orders-item col-xs-2">@Html.DisplayFor(modelItem => item.Status)</section>
<section class="esh-orders-item col-xs-1">
<a class="esh-orders-link" asp-controller="Order" asp-action="Detail" asp-route-orderId="@item.OrderNumber">Detail</a>
</section>
<section class="esh-orders-item col-xs-1">
@if (item.Status.ToLower() == "submitted")
{
<a class="esh-orders-link" asp-controller="Order" asp-action="cancel" asp-route-orderId="@item.OrderNumber">Cancel</a>
}
</section>
</article>
foreach (var item in Model)
{
<article class="esh-orders-items row">
<section class="esh-orders-item col-xs-2">@Html.DisplayFor(modelItem => item.OrderNumber)</section>
<section class="esh-orders-item col-xs-4">@Html.DisplayFor(modelItem => item.Date)</section>
<section class="esh-orders-item col-xs-2">$ @Html.DisplayFor(modelItem => item.Total)</section>
<section class="esh-orders-item col-xs-2">@Html.DisplayFor(modelItem => item.Status)</section>
<section class="esh-orders-item col-xs-1">
<a class="esh-orders-link" asp-controller="Order" asp-action="Detail" asp-route-orderId="@item.OrderNumber">Detail</a>
</section>
<section class="esh-orders-item col-xs-1">
@if (item.Status.ToLower() == "submitted")
{
<a class="esh-orders-link" asp-controller="Order" asp-action="cancel" asp-route-orderId="@item.OrderNumber">Cancel</a>
}
</section>
</article>
}
} }
}
</div> </div>
</div> </div>
<script>
setTimeout(function () {
window.location.reload(true);
}, 5000);
</script>

+ 51
- 0
src/Web/WebMVC/Views/Shared/_Layout.cshtml View File

@ -20,6 +20,8 @@
<link rel="stylesheet" href="~/css/orders/orders-detail/orders-detail.component.css" /> <link rel="stylesheet" href="~/css/orders/orders-detail/orders-detail.component.css" />
<link rel="stylesheet" href="~/css/orders/orders-new/orders-new.component.css" /> <link rel="stylesheet" href="~/css/orders/orders-new/orders-new.component.css" />
<link rel="stylesheet" href="~/css/override.css" type="text/css" /> <link rel="stylesheet" href="~/css/override.css" type="text/css" />
<link rel="stylesheet" href="~/css/site.min.css" type="text/css" />
</environment> </environment>
<environment names="Staging,Production"> <environment names="Staging,Production">
<link rel="stylesheet" href="https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.7/css/bootstrap.min.css" <link rel="stylesheet" href="https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.7/css/bootstrap.min.css"
@ -84,5 +86,54 @@
</environment> </environment>
@RenderSection("scripts", required: false) @RenderSection("scripts", required: false)
@using Microsoft.AspNetCore.Authentication;
@using Microsoft.Extensions.Options
@inject IOptions<AppSettings> settings
<script type="text/javascript">
if ('@User.Identity.IsAuthenticated' === 'True') {
var timerId;
let connection = stablishConnection();
connection.start().then(function () {
console.log('User Registered to Signalr Hub');
});
registerNotificationHandlers(connection);
}
function stablishConnection() {
let hubHttpConnection = new signalR.HttpConnection('@settings.Value.ExternalPurchaseUrl/orders-api/notificationhub', {
transport: signalR.TransportType.LongPolling,
accessTokenFactory: () => {
return "Authorization", getToken();
}
});
return new signalR.HubConnection(hubHttpConnection);
}
function registerNotificationHandlers(connection) {
connection.on("UpdatedOrderState", (message) => {
toastr.success('Updated to status: ' + message.status, 'Order Id: ' + message.orderId);
if (window.location.pathname === '/Order') {
refreshOrderList();
}
});
}
function getToken() {
return '@Context.GetTokenAsync("access_token").Result';
}
function refreshOrderList() {
clearTimeout(timerId);
timerId = setTimeout(function () {
window.location.reload();
}, 5000);
}
</script>
</body> </body>
</html> </html>

+ 1
- 0
src/Web/WebMVC/WebMVC.csproj View File

@ -18,6 +18,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="BuildBundlerMinifier" Version="2.6.375" />
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.2.1" /> <PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.2.1" />
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.5.1" /> <PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.5.1" />
<PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="1.0.0-beta5" /> <PackageReference Include="Microsoft.ApplicationInsights.Kubernetes" Version="1.0.0-beta5" />


+ 2
- 1
src/Web/WebMVC/bower.json View File

@ -5,6 +5,7 @@
"bootstrap": "v3.3.7", "bootstrap": "v3.3.7",
"jquery": "2.2.0", "jquery": "2.2.0",
"jquery-validation": "1.14.0", "jquery-validation": "1.14.0",
"jquery-validation-unobtrusive": "3.2.6"
"jquery-validation-unobtrusive": "3.2.6",
"signalr": "2.2.0"
} }
} }

+ 16
- 1
src/Web/WebMVC/bundleconfig.json View File

@ -5,9 +5,24 @@
"outputFileName": "wwwroot/css/site.min.css", "outputFileName": "wwwroot/css/site.min.css",
// An array of relative input file paths. Globbing patterns supported // An array of relative input file paths. Globbing patterns supported
"inputFiles": [ "inputFiles": [
"wwwroot/css/**/*.css"
"wwwroot/css/**/*.css",
"node_modules/toastr/build/toastr.css"
] ]
}, },
{
"outputFileName": "wwwroot/js/site.js",
"inputFiles": [
"node_modules/@aspnet/signalr/dist/browser/signalr.js",
"node_modules/toastr/toastr.js"
],
// Optionally specify minification options
"minify": {
"enabled": false,
"renameLocals": true
},
// Optinally generate .map file
"sourceMap": false
},
{ {
"outputFileName": "wwwroot/js/site.min.js", "outputFileName": "wwwroot/js/site.min.js",
"inputFiles": [ "inputFiles": [


+ 26
- 0
src/Web/WebMVC/package-lock.json View File

@ -0,0 +1,26 @@
{
"name": "asp.net",
"version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"@aspnet/signalr": {
"version": "1.0.0-preview2-final",
"resolved": "https://registry.npmjs.org/@aspnet/signalr/-/signalr-1.0.0-preview2-final.tgz",
"integrity": "sha512-XbqGbAG9Ow4L5Sc4n81A2S8lHSlxBNTjFm3WZQA94cIolPnW0bPK2u14UMooXRXxzjBtJViJMN/aoxWRwTWxig=="
},
"jquery": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/jquery/-/jquery-3.3.1.tgz",
"integrity": "sha512-Ubldcmxp5np52/ENotGxlLe6aGMvmF4R8S6tZjsP6Knsaxd/xp3Zrh50cG93lR6nPXyUFwzN3ZSOQI0wRJNdGg=="
},
"toastr": {
"version": "2.1.4",
"resolved": "https://registry.npmjs.org/toastr/-/toastr-2.1.4.tgz",
"integrity": "sha1-i0O+ZPudDEFIcURvLbjoyk6V8YE=",
"requires": {
"jquery": "3.3.1"
}
}
}
}

+ 10
- 0
src/Web/WebMVC/package.json View File

@ -0,0 +1,10 @@
{
"version": "1.0.0",
"name": "asp.net",
"private": true,
"devDependencies": {},
"dependencies": {
"@aspnet/signalr": "^1.0.0-preview2-final",
"toastr": "^2.1.4"
}
}

+ 3319
- 1
src/Web/WebMVC/wwwroot/js/site.js
File diff suppressed because it is too large
View File


+ 13
- 0
src/Web/WebMVC/wwwroot/js/site.min.js
File diff suppressed because it is too large
View File


+ 115
- 0
src/Web/WebSPA/WebSPA.csproj View File

@ -12,6 +12,62 @@
<ItemGroup> <ItemGroup>
<Compile Remove="node_modules\**\*;Client\**\*" /> <Compile Remove="node_modules\**\*;Client\**\*" />
<None Remove="Client\environments\environment.prod.ts" />
<None Remove="Client\environments\environment.ts" />
<None Remove="Client\guid.ts" />
<None Remove="Client\main.ts" />
<None Remove="Client\modules\app.component.ts" />
<None Remove="Client\modules\app.module.ts" />
<None Remove="Client\modules\app.routes.ts" />
<None Remove="Client\modules\app.service.ts" />
<None Remove="Client\modules\basket\basket-status\basket-status.component.ts" />
<None Remove="Client\modules\basket\basket.component.ts" />
<None Remove="Client\modules\basket\basket.module.ts" />
<None Remove="Client\modules\basket\basket.service.ts" />
<None Remove="Client\modules\campaigns\campaigns-detail\campaigns-detail.component.ts" />
<None Remove="Client\modules\campaigns\campaigns.component.ts" />
<None Remove="Client\modules\campaigns\campaigns.module.ts" />
<None Remove="Client\modules\campaigns\campaigns.service.ts" />
<None Remove="Client\modules\catalog\catalog.component.ts" />
<None Remove="Client\modules\catalog\catalog.module.ts" />
<None Remove="Client\modules\catalog\catalog.service.ts" />
<None Remove="Client\modules\orders\orders-detail\orders-detail.component.ts" />
<None Remove="Client\modules\orders\orders-new\orders-new.component.ts" />
<None Remove="Client\modules\orders\orders.component.ts" />
<None Remove="Client\modules\orders\orders.module.ts" />
<None Remove="Client\modules\orders\orders.service.ts" />
<None Remove="Client\modules\shared\components\header\header.ts" />
<None Remove="Client\modules\shared\components\identity\identity.ts" />
<None Remove="Client\modules\shared\components\page-not-found\page-not-found.component.spec.ts" />
<None Remove="Client\modules\shared\components\page-not-found\page-not-found.component.ts" />
<None Remove="Client\modules\shared\components\pager\pager.ts" />
<None Remove="Client\modules\shared\models\basket.model.ts" />
<None Remove="Client\modules\shared\models\basketCheckout.model.ts" />
<None Remove="Client\modules\shared\models\basketItem.model.ts" />
<None Remove="Client\modules\shared\models\campaign.model.ts" />
<None Remove="Client\modules\shared\models\campaignItem.model.ts" />
<None Remove="Client\modules\shared\models\catalog.model.ts" />
<None Remove="Client\modules\shared\models\catalogBrand.model.ts" />
<None Remove="Client\modules\shared\models\catalogItem.model.ts" />
<None Remove="Client\modules\shared\models\catalogType.model.ts" />
<None Remove="Client\modules\shared\models\configuration.model.ts" />
<None Remove="Client\modules\shared\models\identity.model.ts" />
<None Remove="Client\modules\shared\models\order-detail.model.ts" />
<None Remove="Client\modules\shared\models\order.model.ts" />
<None Remove="Client\modules\shared\models\orderItem.model.ts" />
<None Remove="Client\modules\shared\models\pager.model.ts" />
<None Remove="Client\modules\shared\pipes\uppercase.pipe.spec.ts" />
<None Remove="Client\modules\shared\pipes\uppercase.pipe.ts" />
<None Remove="Client\modules\shared\services\basket.wrapper.service.ts" />
<None Remove="Client\modules\shared\services\configuration.service.ts" />
<None Remove="Client\modules\shared\services\data.service.ts" />
<None Remove="Client\modules\shared\services\notification.service.ts" />
<None Remove="Client\modules\shared\services\security.service.ts" />
<None Remove="Client\modules\shared\services\storage.service.ts" />
<None Remove="Client\modules\shared\shared.module.ts" />
<None Remove="Client\polyfills.ts" />
<None Remove="Client\test.ts" />
<None Remove="Client\typings.d.ts" />
<Content Include="Setup\images.zip"> <Content Include="Setup\images.zip">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory> <CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content> </Content>
@ -70,6 +126,65 @@
<Folder Include="wwwroot\assets\" /> <Folder Include="wwwroot\assets\" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<TypeScriptCompile Include="Client\environments\environment.prod.ts" />
<TypeScriptCompile Include="Client\environments\environment.ts" />
<TypeScriptCompile Include="Client\guid.ts" />
<TypeScriptCompile Include="Client\main.ts" />
<TypeScriptCompile Include="Client\modules\app.component.ts" />
<TypeScriptCompile Include="Client\modules\app.module.ts" />
<TypeScriptCompile Include="Client\modules\app.routes.ts" />
<TypeScriptCompile Include="Client\modules\app.service.ts" />
<TypeScriptCompile Include="Client\modules\basket\basket-status\basket-status.component.ts" />
<TypeScriptCompile Include="Client\modules\basket\basket.component.ts" />
<TypeScriptCompile Include="Client\modules\basket\basket.module.ts" />
<TypeScriptCompile Include="Client\modules\basket\basket.service.ts" />
<TypeScriptCompile Include="Client\modules\campaigns\campaigns-detail\campaigns-detail.component.ts" />
<TypeScriptCompile Include="Client\modules\campaigns\campaigns.component.ts" />
<TypeScriptCompile Include="Client\modules\campaigns\campaigns.module.ts" />
<TypeScriptCompile Include="Client\modules\campaigns\campaigns.service.ts" />
<TypeScriptCompile Include="Client\modules\catalog\catalog.component.ts" />
<TypeScriptCompile Include="Client\modules\catalog\catalog.module.ts" />
<TypeScriptCompile Include="Client\modules\catalog\catalog.service.ts" />
<TypeScriptCompile Include="Client\modules\orders\orders-detail\orders-detail.component.ts" />
<TypeScriptCompile Include="Client\modules\orders\orders-new\orders-new.component.ts" />
<TypeScriptCompile Include="Client\modules\orders\orders.component.ts" />
<TypeScriptCompile Include="Client\modules\orders\orders.module.ts" />
<TypeScriptCompile Include="Client\modules\orders\orders.service.ts" />
<TypeScriptCompile Include="Client\modules\shared\components\header\header.ts" />
<TypeScriptCompile Include="Client\modules\shared\components\identity\identity.ts" />
<TypeScriptCompile Include="Client\modules\shared\components\page-not-found\page-not-found.component.spec.ts" />
<TypeScriptCompile Include="Client\modules\shared\components\page-not-found\page-not-found.component.ts" />
<TypeScriptCompile Include="Client\modules\shared\components\pager\pager.ts" />
<TypeScriptCompile Include="Client\modules\shared\models\basket.model.ts" />
<TypeScriptCompile Include="Client\modules\shared\models\basketCheckout.model.ts" />
<TypeScriptCompile Include="Client\modules\shared\models\basketItem.model.ts" />
<TypeScriptCompile Include="Client\modules\shared\models\campaign.model.ts" />
<TypeScriptCompile Include="Client\modules\shared\models\campaignItem.model.ts" />
<TypeScriptCompile Include="Client\modules\shared\models\catalog.model.ts" />
<TypeScriptCompile Include="Client\modules\shared\models\catalogBrand.model.ts" />
<TypeScriptCompile Include="Client\modules\shared\models\catalogItem.model.ts" />
<TypeScriptCompile Include="Client\modules\shared\models\catalogType.model.ts" />
<TypeScriptCompile Include="Client\modules\shared\models\configuration.model.ts" />
<TypeScriptCompile Include="Client\modules\shared\models\identity.model.ts" />
<TypeScriptCompile Include="Client\modules\shared\models\order-detail.model.ts" />
<TypeScriptCompile Include="Client\modules\shared\models\order.model.ts" />
<TypeScriptCompile Include="Client\modules\shared\models\orderItem.model.ts" />
<TypeScriptCompile Include="Client\modules\shared\models\pager.model.ts" />
<TypeScriptCompile Include="Client\modules\shared\pipes\uppercase.pipe.spec.ts" />
<TypeScriptCompile Include="Client\modules\shared\pipes\uppercase.pipe.ts" />
<TypeScriptCompile Include="Client\modules\shared\services\basket.wrapper.service.ts" />
<TypeScriptCompile Include="Client\modules\shared\services\configuration.service.ts" />
<TypeScriptCompile Include="Client\modules\shared\services\data.service.ts" />
<TypeScriptCompile Include="Client\modules\shared\services\notification.service.ts" />
<TypeScriptCompile Include="Client\modules\shared\services\security.service.ts" />
<TypeScriptCompile Include="Client\modules\shared\services\storage.service.ts" />
<TypeScriptCompile Include="Client\modules\shared\shared.module.ts" />
<TypeScriptCompile Include="Client\polyfills.ts" />
<TypeScriptCompile Include="Client\test.ts" />
<TypeScriptCompile Include="Client\typings.d.ts" />
</ItemGroup>
<ProjectExtensions><VisualStudio><UserProperties package-lock_1json__JSONSchema="http://json.schemastore.org/bower" /></VisualStudio></ProjectExtensions> <ProjectExtensions><VisualStudio><UserProperties package-lock_1json__JSONSchema="http://json.schemastore.org/bower" /></VisualStudio></ProjectExtensions>
</Project> </Project>

+ 2
- 2
test/Services/UnitTest/Ordering/Application/NewOrderCommandHandlerTest.cs View File

@ -60,12 +60,12 @@ namespace UnitTest.Ordering.Application
public void Handle_throws_exception_when_no_buyerId() public void Handle_throws_exception_when_no_buyerId()
{ {
//Assert //Assert
Assert.Throws<ArgumentNullException>(() => new Buyer(string.Empty));
Assert.Throws<ArgumentNullException>(() => new Buyer(string.Empty, string.Empty));
} }
private Buyer FakeBuyer() private Buyer FakeBuyer()
{ {
return new Buyer(Guid.NewGuid().ToString());
return new Buyer(Guid.NewGuid().ToString(), "1");
} }
private Order FakeOrder() private Order FakeOrder()


+ 11
- 7
test/Services/UnitTest/Ordering/Application/OrdersWebApiTest.cs View File

@ -1,11 +1,13 @@
using MediatR; using MediatR;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.SignalR;
using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands; using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands;
using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Queries; using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Queries;
using Microsoft.eShopOnContainers.Services.Ordering.API.Controllers; using Microsoft.eShopOnContainers.Services.Ordering.API.Controllers;
using Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure.Services; using Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure.Services;
using Moq; using Moq;
using Ordering.API.Application.Commands; using Ordering.API.Application.Commands;
using Ordering.API.Infrastructure.Hubs;
using System; using System;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
@ -19,12 +21,14 @@ namespace UnitTest.Ordering.Application
private readonly Mock<IMediator> _mediatorMock; private readonly Mock<IMediator> _mediatorMock;
private readonly Mock<IOrderQueries> _orderQueriesMock; private readonly Mock<IOrderQueries> _orderQueriesMock;
private readonly Mock<IIdentityService> _identityServiceMock; private readonly Mock<IIdentityService> _identityServiceMock;
private readonly Mock<IHubContext<NotificationsHub>> _hubContextMock;
public OrdersWebApiTest() public OrdersWebApiTest()
{ {
_mediatorMock = new Mock<IMediator>(); _mediatorMock = new Mock<IMediator>();
_orderQueriesMock = new Mock<IOrderQueries>(); _orderQueriesMock = new Mock<IOrderQueries>();
_identityServiceMock = new Mock<IIdentityService>(); _identityServiceMock = new Mock<IIdentityService>();
_hubContextMock = new Mock<IHubContext<NotificationsHub>>();
} }
[Fact] [Fact]
@ -35,7 +39,7 @@ namespace UnitTest.Ordering.Application
.Returns(Task.FromResult(true)); .Returns(Task.FromResult(true));
//Act //Act
var orderController = new OrdersController(_mediatorMock.Object, _orderQueriesMock.Object, _identityServiceMock.Object);
var orderController = new OrdersController(_mediatorMock.Object, _orderQueriesMock.Object, _identityServiceMock.Object, _hubContextMock.Object);
var actionResult = await orderController.CancelOrder(new CancelOrderCommand(1), Guid.NewGuid().ToString()) as OkResult; var actionResult = await orderController.CancelOrder(new CancelOrderCommand(1), Guid.NewGuid().ToString()) as OkResult;
//Assert //Assert
@ -51,7 +55,7 @@ namespace UnitTest.Ordering.Application
.Returns(Task.FromResult(true)); .Returns(Task.FromResult(true));
//Act //Act
var orderController = new OrdersController(_mediatorMock.Object, _orderQueriesMock.Object, _identityServiceMock.Object);
var orderController = new OrdersController(_mediatorMock.Object, _orderQueriesMock.Object, _identityServiceMock.Object, _hubContextMock.Object);
var actionResult = await orderController.CancelOrder(new CancelOrderCommand(1), String.Empty) as BadRequestResult; var actionResult = await orderController.CancelOrder(new CancelOrderCommand(1), String.Empty) as BadRequestResult;
//Assert //Assert
@ -66,7 +70,7 @@ namespace UnitTest.Ordering.Application
.Returns(Task.FromResult(true)); .Returns(Task.FromResult(true));
//Act //Act
var orderController = new OrdersController(_mediatorMock.Object, _orderQueriesMock.Object, _identityServiceMock.Object);
var orderController = new OrdersController(_mediatorMock.Object, _orderQueriesMock.Object, _identityServiceMock.Object, _hubContextMock.Object);
var actionResult = await orderController.ShipOrder(new ShipOrderCommand(1), Guid.NewGuid().ToString()) as OkResult; var actionResult = await orderController.ShipOrder(new ShipOrderCommand(1), Guid.NewGuid().ToString()) as OkResult;
//Assert //Assert
@ -82,7 +86,7 @@ namespace UnitTest.Ordering.Application
.Returns(Task.FromResult(true)); .Returns(Task.FromResult(true));
//Act //Act
var orderController = new OrdersController(_mediatorMock.Object, _orderQueriesMock.Object, _identityServiceMock.Object);
var orderController = new OrdersController(_mediatorMock.Object, _orderQueriesMock.Object, _identityServiceMock.Object, _hubContextMock.Object);
var actionResult = await orderController.ShipOrder(new ShipOrderCommand(1), String.Empty) as BadRequestResult; var actionResult = await orderController.ShipOrder(new ShipOrderCommand(1), String.Empty) as BadRequestResult;
//Assert //Assert
@ -98,7 +102,7 @@ namespace UnitTest.Ordering.Application
.Returns(Task.FromResult(fakeDynamicResult)); .Returns(Task.FromResult(fakeDynamicResult));
//Act //Act
var orderController = new OrdersController(_mediatorMock.Object, _orderQueriesMock.Object, _identityServiceMock.Object);
var orderController = new OrdersController(_mediatorMock.Object, _orderQueriesMock.Object, _identityServiceMock.Object, _hubContextMock.Object);
var actionResult = await orderController.GetOrders() as OkObjectResult; var actionResult = await orderController.GetOrders() as OkObjectResult;
//Assert //Assert
@ -115,7 +119,7 @@ namespace UnitTest.Ordering.Application
.Returns(Task.FromResult(fakeDynamicResult)); .Returns(Task.FromResult(fakeDynamicResult));
//Act //Act
var orderController = new OrdersController(_mediatorMock.Object, _orderQueriesMock.Object, _identityServiceMock.Object);
var orderController = new OrdersController(_mediatorMock.Object, _orderQueriesMock.Object, _identityServiceMock.Object, _hubContextMock.Object);
var actionResult = await orderController.GetOrder(fakeOrderId) as OkObjectResult; var actionResult = await orderController.GetOrder(fakeOrderId) as OkObjectResult;
//Assert //Assert
@ -131,7 +135,7 @@ namespace UnitTest.Ordering.Application
.Returns(Task.FromResult(fakeDynamicResult)); .Returns(Task.FromResult(fakeDynamicResult));
//Act //Act
var orderController = new OrdersController(_mediatorMock.Object, _orderQueriesMock.Object, _identityServiceMock.Object);
var orderController = new OrdersController(_mediatorMock.Object, _orderQueriesMock.Object, _identityServiceMock.Object, _hubContextMock.Object);
var actionResult = await orderController.GetCardTypes() as OkObjectResult; var actionResult = await orderController.GetCardTypes() as OkObjectResult;
//Assert //Assert


+ 8
- 4
test/Services/UnitTest/Ordering/Domain/BuyerAggregateTest.cs View File

@ -13,9 +13,10 @@ public class BuyerAggregateTest
{ {
//Arrange //Arrange
var identity = new Guid().ToString(); var identity = new Guid().ToString();
var name = "fakeUser";
//Act //Act
var fakeBuyerItem = new Buyer(identity);
var fakeBuyerItem = new Buyer(identity, name);
//Assert //Assert
Assert.NotNull(fakeBuyerItem); Assert.NotNull(fakeBuyerItem);
@ -26,9 +27,10 @@ public class BuyerAggregateTest
{ {
//Arrange //Arrange
var identity = string.Empty; var identity = string.Empty;
var name = "fakeUser";
//Act - Assert //Act - Assert
Assert.Throws<ArgumentNullException>(() => new Buyer(identity));
Assert.Throws<ArgumentNullException>(() => new Buyer(identity, name));
} }
[Fact] [Fact]
@ -42,8 +44,9 @@ public class BuyerAggregateTest
var cardHolderName = "FakeHolderNAme"; var cardHolderName = "FakeHolderNAme";
var expiration = DateTime.Now.AddYears(1); var expiration = DateTime.Now.AddYears(1);
var orderId = 1; var orderId = 1;
var name = "fakeUser";
var identity = new Guid().ToString(); var identity = new Guid().ToString();
var fakeBuyerItem = new Buyer(identity);
var fakeBuyerItem = new Buyer(identity, name);
//Act //Act
var result = fakeBuyerItem.VerifyOrAddPaymentMethod(cardTypeId, alias, cardNumber, securityNumber, cardHolderName, expiration, orderId); var result = fakeBuyerItem.VerifyOrAddPaymentMethod(cardTypeId, alias, cardNumber, securityNumber, cardHolderName, expiration, orderId);
@ -117,9 +120,10 @@ public class BuyerAggregateTest
var cardHolderName = "FakeName"; var cardHolderName = "FakeName";
var cardExpiration = DateTime.Now.AddYears(1); var cardExpiration = DateTime.Now.AddYears(1);
var expectedResult = 1; var expectedResult = 1;
var name = "fakeUser";
//Act //Act
var fakeBuyer = new Buyer(Guid.NewGuid().ToString());
var fakeBuyer = new Buyer(Guid.NewGuid().ToString(), name);
fakeBuyer.VerifyOrAddPaymentMethod(cardTypeId, alias, cardNumber, cardSecurityNumber, cardHolderName, cardExpiration, orderId); fakeBuyer.VerifyOrAddPaymentMethod(cardTypeId, alias, cardNumber, cardSecurityNumber, cardHolderName, cardExpiration, orderId);
//Assert //Assert


Loading…
Cancel
Save