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
- MarketingUrlHC=http://marketing.api/hc
- PaymentUrlHC=http://payment.api/hc
- ExternalPurchaseUrl=http://${ESHOP_EXTERNAL_DNS_NAME_OR_IP}:5202
- UseCustomizationData=True
- ApplicationInsights__InstrumentationKey=${INSTRUMENTATION_KEY}
- OrchestratorType=${ORCHESTRATOR_TYPE}
@ -202,6 +203,24 @@ services:
ports:
- "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).
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:
environment:


+ 8
- 0
docker-compose.yml View File

@ -144,3 +144,11 @@ services:
context: .
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
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
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ordering.BackgroundTasks", "src\Services\Ordering\Ordering.BackgroundTasks\Ordering.BackgroundTasks.csproj", "{7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
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|x86.ActiveCfg = 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
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -1541,6 +1591,7 @@ Global
{3F79558C-485D-49E1-BD3E-E12538D3D308} = {EC91ADE9-3D66-4AB2-9FB4-2B585E1F3531}
{BEA37D6D-4CF2-4AE8-9575-72388E54FBD0} = {0189E4FB-6E2B-4F2E-9B1D-5473D23FC6DB}
{AF0828DB-8BDD-411A-AEEF-B780FBB8D8C1} = {28C0F5C8-4849-4035-80AB-45639424E73F}
{7D63ED4A-3EDA-4BBA-8BBA-F46BD6430931} = {0BD0DB92-2D98-44D9-9AC0-C59186D59B0B}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
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)
{
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) ?
guid : basketCheckout.RequestId;
@ -69,7 +71,7 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API.Controllers
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.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 UserName { get; }
public int OrderNumber { get; set; }
public string City { get; set; }
@ -36,12 +38,13 @@ namespace Basket.API.IntegrationEvents.Events
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,
DateTime cardExpiration, string cardSecurityNumber, int cardTypeId, string buyer, Guid requestId,
CustomerBasket basket)
{
UserId = userId;
UserName = userName;
City = city;
Street = street;
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 System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
@ -68,7 +69,8 @@ namespace Microsoft.eShopOnContainers.Services.Identity.API.Services
var claims = new List<Claim>
{
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))


+ 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]
public string UserId { get; private set; }
[DataMember]
public string UserName { get; private set; }
[DataMember]
public string City { get; private set; }
@ -65,12 +68,13 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands
_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 cardSecurityNumber, int cardTypeId) : this()
{
_orderItems = basketItems.ToOrderItemsDTO().ToList();
UserId = userId;
UserName = userName;
City = city;
Street = street;
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
// 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 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)
{


+ 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 Ordering.API.Application.IntegrationEvents.Events;
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
: INotificationHandler<OrderStatusChangedToAwaitingValidationDomainEvent>
{
private readonly IOrderRepository _orderRepository;
private readonly ILoggerFactory _logger;
private readonly IBuyerRepository _buyerRepository;
private readonly IOrderingIntegrationEventService _orderingIntegrationEventService;
private readonly IHubContext<NotificationsHub> _hubContext;
public OrderStatusChangedToAwaitingValidationDomainEventHandler(
IOrderRepository orderRepository, ILoggerFactory logger,
IOrderingIntegrationEventService orderingIntegrationEventService)
IBuyerRepository buyerRepository,
IOrderingIntegrationEventService orderingIntegrationEventService,
IHubContext<NotificationsHub> hubContext)
{
_orderRepository = orderRepository ?? throw new ArgumentNullException(nameof(orderRepository));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_buyerRepository = buyerRepository;
_orderingIntegrationEventService = orderingIntegrationEventService;
_hubContext = hubContext ?? throw new ArgumentNullException(nameof(hubContext));
}
public async Task Handle(OrderStatusChangedToAwaitingValidationDomainEvent orderStatusChangedToAwaitingValidationDomainEvent, CancellationToken cancellationToken)
@ -33,12 +44,20 @@
.LogTrace($"Order with Id: {orderStatusChangedToAwaitingValidationDomainEvent.OrderId} has been successfully updated with " +
$"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
.Select(orderItem => new OrderStockItem(orderItem.ProductId, orderItem.GetUnits()));
var orderStatusChangedToAwaitingValidationIntegrationEvent = new OrderStatusChangedToAwaitingValidationIntegrationEvent(
orderStatusChangedToAwaitingValidationDomainEvent.OrderId, orderStockList);
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 Ordering.API.Application.IntegrationEvents.Events;
using System.Threading;
using Microsoft.AspNetCore.SignalR;
using Ordering.API.Infrastructure.Hubs;
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate;
public class OrderStatusChangedToPaidDomainEventHandler
: INotificationHandler<OrderStatusChangedToPaidDomainEvent>
{
private readonly IOrderRepository _orderRepository;
private readonly ILoggerFactory _logger;
private readonly IBuyerRepository _buyerRepository;
private readonly IOrderingIntegrationEventService _orderingIntegrationEventService;
private readonly IHubContext<NotificationsHub> _hubContext;
public OrderStatusChangedToPaidDomainEventHandler(
IOrderRepository orderRepository, ILoggerFactory logger,
IOrderingIntegrationEventService orderingIntegrationEventService)
IBuyerRepository buyerRepository,
IOrderingIntegrationEventService orderingIntegrationEventService,
IHubContext<NotificationsHub> hubContext)
{
_orderRepository = orderRepository ?? throw new ArgumentNullException(nameof(orderRepository));
_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)
@ -33,12 +42,19 @@
.LogTrace($"Order with Id: {orderStatusChangedToPaidDomainEvent.OrderId} has been successfully updated with " +
$"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
.Select(orderItem => new OrderStockItem(orderItem.ProductId, orderItem.GetUnits()));
var orderStatusChangedToPaidIntegrationEvent = new OrderStatusChangedToPaidIntegrationEvent(orderStatusChangedToPaidDomainEvent.OrderId,
orderStockList);
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 Microsoft.AspNetCore.Http;
using Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure.Services;
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate;
using Microsoft.Extensions.Logging;
@ -24,14 +25,14 @@ namespace Ordering.API.Application.DomainEventHandlers.OrderStartedEvent
}
public async Task Handle(OrderStartedDomainEvent orderStartedEvent, CancellationToken cancellationToken)
{
{
var cardTypeId = (orderStartedEvent.CardTypeId != 0) ? orderStartedEvent.CardTypeId : 1;
var buyer = await _buyerRepository.FindAsync(orderStartedEvent.UserId);
bool buyerOriginallyExisted = (buyer == null) ? false : true;
if (!buyerOriginallyExisted)
{
buyer = new Buyer(orderStartedEvent.UserId);
buyer = new Buyer(orderStartedEvent.UserId, orderStartedEvent.UserName);
}
buyer.VerifyOrAddPaymentMethod(cardTypeId,
@ -42,7 +43,9 @@ namespace Ordering.API.Application.DomainEventHandlers.OrderStartedEvent
orderStartedEvent.CardExpiration,
orderStartedEvent.Order.Id);
var buyerUpdated = buyerOriginallyExisted ? _buyerRepository.Update(buyer) : _buyerRepository.Add(buyer);
var buyerUpdated = buyerOriginallyExisted ?
_buyerRepository.Update(buyer) :
_buyerRepository.Add(buyer);
await _buyerRepository.UnitOfWork
.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.Events;
using System.Threading;
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate;
using Microsoft.AspNetCore.SignalR;
using Ordering.API.Infrastructure.Hubs;
public class OrderStatusChangedToStockConfirmedDomainEventHandler
: INotificationHandler<OrderStatusChangedToStockConfirmedDomainEvent>
{
private readonly IOrderRepository _orderRepository;
private readonly IBuyerRepository _buyerRepository;
private readonly ILoggerFactory _logger;
private readonly IHubContext<NotificationsHub> _hubContext;
private readonly IOrderingIntegrationEventService _orderingIntegrationEventService;
public OrderStatusChangedToStockConfirmedDomainEventHandler(
IOrderRepository orderRepository, ILoggerFactory logger,
IOrderRepository orderRepository,
IBuyerRepository buyerRepository,
ILoggerFactory logger,
IHubContext<NotificationsHub> hubContext,
IOrderingIntegrationEventService orderingIntegrationEventService)
{
_orderRepository = orderRepository ?? throw new ArgumentNullException(nameof(orderRepository));
_buyerRepository = buyerRepository ?? throw new ArgumentNullException(nameof(buyerRepository));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_hubContext = hubContext ?? throw new ArgumentNullException(nameof(hubContext));
_orderingIntegrationEventService = orderingIntegrationEventService;
}
@ -32,8 +42,15 @@
.LogTrace($"Order with Id: {orderStatusChangedToStockConfirmedDomainEvent.OrderId} has been successfully updated with " +
$"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);
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)
{
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.CardNumber, eventMsg.CardHolderName, eventMsg.CardExpiration,
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 UserName { get; }
public string City { get; set; }
public string Street { get; set; }
@ -34,7 +36,7 @@ namespace Ordering.API.Application.IntegrationEvents.Events
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,
DateTime cardExpiration, string cardSecurityNumber, int cardTypeId, string buyer, Guid requestId,
CustomerBasket basket)
@ -53,6 +55,7 @@ namespace Ordering.API.Application.IntegrationEvents.Events
Buyer = buyer;
Basket = basket;
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
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:ordering.buyerseq", "'buyerseq', '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()
.HasMaxLength(200);
b.Property<string>("Name");
b.HasKey("Id");
b.HasIndex("IdentityGuid")
@ -180,25 +182,6 @@ namespace Ordering.API.Migrations
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 =>
{
b.HasOne("Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.BuyerAggregate.Buyer")
@ -227,6 +210,18 @@ namespace Ordering.API.Migrations
.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 =>
@ -236,14 +231,6 @@ namespace Ordering.API.Migrations
.HasForeignKey("OrderId")
.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
}
}


+ 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
{
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;
}
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.AspNetCore.All" Version="2.0.5" />
<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="System.Reflection" Version="4.3.0" />
<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.Events;
using global::Ordering.API.Infrastructure.Filters;
using global::Ordering.API.Infrastructure.Hubs;
using global::Ordering.API.Infrastructure.Middlewares;
using Infrastructure.AutofacModules;
using Infrastructure.Filters;
@ -28,6 +29,8 @@
using Microsoft.Extensions.HealthChecks;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Primitives;
using Microsoft.IdentityModel.Tokens;
using Ordering.Infrastructure;
using RabbitMQ.Client;
using Swashbuckle.AspNetCore.Swagger;
@ -36,6 +39,7 @@
using System.Data.Common;
using System.IdentityModel.Tokens.Jwt;
using System.Reflection;
using System.Threading.Tasks;
public class Startup
{
@ -186,6 +190,7 @@
RegisterEventBus(services);
ConfigureAuthService(services);
services.AddOptions();
services.AddSignalR();
//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.AddDebug();
@ -220,6 +225,13 @@
app.UseCors("CorsPolicy");
ConfigureAuth(app);
app.UseSignalR(routes =>
{
routes.MapHub<NotificationsHub>("/notificationhub", options =>
options.Transports = AspNetCore.Http.Connections.TransportType.All);
});
app.UseMvcWithDefaultRoute();
app.UseSwagger()
@ -266,7 +278,7 @@
private void ConfigureAuthService(IServiceCollection services)
{
// prevent from mapping "sub" claim to nameidentifier.
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Remove("sub");
var identityUrl = Configuration.GetValue<string>("IdentityUrl");
@ -279,7 +291,7 @@
{
options.Authority = identityUrl;
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": {
"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 Name { get; private set; }
private List<PaymentMethod> _paymentMethods;
public IEnumerable<PaymentMethod> PaymentMethods => _paymentMethods.AsReadOnly();
@ -20,9 +22,10 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.B
_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));
Name = !string.IsNullOrWhiteSpace(name) ? name : throw new ArgumentNullException(nameof(name));
}
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 Update(Buyer buyer);
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
public Address Address { get; private set; }
public int? GetBuyerId => _buyerId;
private int? _buyerId;
public OrderStatus OrderStatus { get; private set; }
@ -50,7 +51,7 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.O
_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()
{
_buyerId = buyerId;
@ -61,7 +62,7 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.O
// Add the OrderStarterDomainEvent to the domain events collection
// 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);
}
@ -144,6 +145,7 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.O
_orderStatusId = OrderStatus.Shipped.Id;
_description = "The order was shipped.";
AddDomainEvent(new OrderShippedDomainEvent(this));
}
public void SetCancelledStatus()
@ -156,6 +158,7 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.O
_orderStatusId = OrderStatus.Cancelled.Id;
_description = $"The order was cancelled.";
AddDomainEvent(new OrderCancelledDomainEvent(this));
}
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)
{
var orderStartedDomainEvent = new OrderStartedDomainEvent(this, userId, cardTypeId,
var orderStartedDomainEvent = new OrderStartedDomainEvent(this, userId, userName, cardTypeId,
cardNumber, cardSecurityNumber,
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 string UserId { get; }
public string UserName { get; }
public int CardTypeId { get; }
public string CardNumber { get; }
public string CardSecurityNumber { get; }
@ -19,13 +20,14 @@ namespace Ordering.Domain.Events
public DateTime CardExpiration { get; }
public Order Order { get; }
public OrderStartedDomainEvent(Order order, string userId,
public OrderStartedDomainEvent(Order order, string userId, string userName,
int cardTypeId, string cardNumber,
string cardSecurityNumber, string cardHolderName,
DateTime cardExpiration)
{
Order = order;
UserId = userId;
UserName = userName;
CardTypeId = cardTypeId;
CardNumber = cardNumber;
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")
.IsUnique(true);
buyerConfiguration.Property(b => b.Name);
buyerConfiguration.HasMany(b => b.PaymentMethods)
.WithOne()
.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;
}
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 PurchaseUrl { get; set; }
public string ExternalPurchaseUrl { get; set; }
public bool ActivateCampaignDetailFunction { get; set; }
public Logging Logging { 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">
@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">
<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"></section>
</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>
<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-new/orders-new.component.css" />
<link rel="stylesheet" href="~/css/override.css" type="text/css" />
<link rel="stylesheet" href="~/css/site.min.css" type="text/css" />
</environment>
<environment names="Staging,Production">
<link rel="stylesheet" href="https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.7/css/bootstrap.min.css"
@ -84,5 +86,54 @@
</environment>
@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>
</html>

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

@ -18,6 +18,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="BuildBundlerMinifier" Version="2.6.375" />
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.2.1" />
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.5.1" />
<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",
"jquery": "2.2.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",
// An array of relative input file paths. Globbing patterns supported
"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",
"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>
<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">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
@ -70,6 +126,65 @@
<Folder Include="wwwroot\assets\" />
</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>
</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()
{
//Assert
Assert.Throws<ArgumentNullException>(() => new Buyer(string.Empty));
Assert.Throws<ArgumentNullException>(() => new Buyer(string.Empty, string.Empty));
}
private Buyer FakeBuyer()
{
return new Buyer(Guid.NewGuid().ToString());
return new Buyer(Guid.NewGuid().ToString(), "1");
}
private Order FakeOrder()


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

@ -1,11 +1,13 @@
using MediatR;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.SignalR;
using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands;
using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Queries;
using Microsoft.eShopOnContainers.Services.Ordering.API.Controllers;
using Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure.Services;
using Moq;
using Ordering.API.Application.Commands;
using Ordering.API.Infrastructure.Hubs;
using System;
using System.Linq;
using System.Threading;
@ -19,12 +21,14 @@ namespace UnitTest.Ordering.Application
private readonly Mock<IMediator> _mediatorMock;
private readonly Mock<IOrderQueries> _orderQueriesMock;
private readonly Mock<IIdentityService> _identityServiceMock;
private readonly Mock<IHubContext<NotificationsHub>> _hubContextMock;
public OrdersWebApiTest()
{
_mediatorMock = new Mock<IMediator>();
_orderQueriesMock = new Mock<IOrderQueries>();
_identityServiceMock = new Mock<IIdentityService>();
_hubContextMock = new Mock<IHubContext<NotificationsHub>>();
}
[Fact]
@ -35,7 +39,7 @@ namespace UnitTest.Ordering.Application
.Returns(Task.FromResult(true));
//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;
//Assert
@ -51,7 +55,7 @@ namespace UnitTest.Ordering.Application
.Returns(Task.FromResult(true));
//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;
//Assert
@ -66,7 +70,7 @@ namespace UnitTest.Ordering.Application
.Returns(Task.FromResult(true));
//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;
//Assert
@ -82,7 +86,7 @@ namespace UnitTest.Ordering.Application
.Returns(Task.FromResult(true));
//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;
//Assert
@ -98,7 +102,7 @@ namespace UnitTest.Ordering.Application
.Returns(Task.FromResult(fakeDynamicResult));
//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;
//Assert
@ -115,7 +119,7 @@ namespace UnitTest.Ordering.Application
.Returns(Task.FromResult(fakeDynamicResult));
//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;
//Assert
@ -131,7 +135,7 @@ namespace UnitTest.Ordering.Application
.Returns(Task.FromResult(fakeDynamicResult));
//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;
//Assert


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

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


Loading…
Cancel
Save