Skip to content

Commit 3f3b9b0

Browse files
committed
Moved Integrationevent to Application folder
Created basic structure for order process saga
1 parent 2785dd7 commit 3f3b9b0

9 files changed

Lines changed: 212 additions & 10 deletions

File tree

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
using MediatR;
2+
using System;
3+
using System.Collections.Generic;
4+
using System.Linq;
5+
using System.Runtime.Serialization;
6+
using System.Threading.Tasks;
7+
8+
namespace Ordering.API.Application.Commands
9+
{
10+
public class CancelOrderCommand : IAsyncRequest<bool>
11+
{
12+
13+
[DataMember]
14+
public int OrderNumber { get; private set; }
15+
16+
public CancelOrderCommand(int orderNumber)
17+
{
18+
OrderNumber = orderNumber;
19+
}
20+
}
21+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events;
2+
using System;
3+
using System.Collections.Generic;
4+
using System.Linq;
5+
using System.Threading.Tasks;
6+
7+
namespace Ordering.API.Application.IntegrationCommands.Commands
8+
{
9+
public class ConfirmGracePeriodCommandMsg : IntegrationEvent
10+
{
11+
public int OrderNumber { get; private set; }
12+
13+
//TODO: message should change to Integration command type once command bus is implemented
14+
}
15+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Threading.Tasks;
5+
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events;
6+
7+
namespace Ordering.API.Application.IntegrationCommands.Commands
8+
{
9+
public class SubmitOrderCommandMsg : IntegrationEvent
10+
{
11+
public int OrderNumber { get; private set; }
12+
//TODO: message should change to Integration command type once command bus is implemented
13+
}
14+
}

src/Services/Ordering/Ordering.API/IntegrationEvents/Events/OrderStartedIntegrationEvent.cs renamed to src/Services/Ordering/Ordering.API/Application/IntegrationEvents/Events/OrderStartedIntegrationEvent.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
using System.Linq;
55
using System.Threading.Tasks;
66

7-
namespace Ordering.API.IntegrationEvents.Events
7+
namespace Ordering.API.Application.IntegrationEvents.Events
88
{
99
// Integration Events notes:
1010
// An Event is “something that has happened in the past”, therefore its name has to be

src/Services/Ordering/Ordering.API/IntegrationEvents/IOrderingIntegrationEventService.cs renamed to src/Services/Ordering/Ordering.API/Application/IntegrationEvents/IOrderingIntegrationEventService.cs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
11
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events;
2-
using System;
3-
using System.Collections.Generic;
4-
using System.Linq;
52
using System.Threading.Tasks;
63

7-
namespace Ordering.API.IntegrationEvents
4+
namespace Ordering.API.Application.IntegrationEvents
85
{
96
public interface IOrderingIntegrationEventService
107
{

src/Services/Ordering/Ordering.API/IntegrationEvents/OrderingIntegrationEventService.cs renamed to src/Services/Ordering/Ordering.API/Application/IntegrationEvents/OrderingIntegrationEventService.cs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,14 @@
11
using Microsoft.EntityFrameworkCore;
2-
using Microsoft.EntityFrameworkCore.Storage;
32
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
43
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events;
54
using Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF.Services;
65
using Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF.Utilities;
7-
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate;
86
using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure;
97
using System;
108
using System.Data.Common;
119
using System.Threading.Tasks;
1210

13-
namespace Ordering.API.IntegrationEvents
11+
namespace Ordering.API.Application.IntegrationEvents
1412
{
1513
public class OrderingIntegrationEventService : IOrderingIntegrationEventService
1614
{
@@ -19,7 +17,7 @@ public class OrderingIntegrationEventService : IOrderingIntegrationEventService
1917
private readonly OrderingContext _orderingContext;
2018
private readonly IIntegrationEventLogService _eventLogService;
2119

22-
public OrderingIntegrationEventService (IEventBus eventBus, OrderingContext orderingContext,
20+
public OrderingIntegrationEventService(IEventBus eventBus, OrderingContext orderingContext,
2321
Func<DbConnection, IIntegrationEventLogService> integrationEventLogServiceFactory)
2422
{
2523
_orderingContext = orderingContext ?? throw new ArgumentNullException(nameof(orderingContext));
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
using Autofac.Features.OwnedInstances;
2+
using MediatR;
3+
using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions;
4+
using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands;
5+
using Microsoft.eShopOnContainers.Services.Ordering.Domain.AggregatesModel.OrderAggregate;
6+
using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure;
7+
using Microsoft.eShopOnContainers.Services.Ordering.Infrastructure.Idempotency;
8+
using Ordering.API.Application.Commands;
9+
using Ordering.API.Application.IntegrationCommands.Commands;
10+
using Ordering.Domain.Exceptions;
11+
using System;
12+
using System.Threading.Tasks;
13+
14+
namespace Ordering.API.Application.Sagas
15+
{
16+
/// <summary>
17+
/// Saga for handling the place order process
18+
/// and which is started once the basket.api has
19+
/// successfully processed the items ordered.
20+
/// Saga provides a period of grace to give the customer
21+
/// the opportunity to cancel the order before proceeding
22+
/// with the validations.
23+
/// </summary>
24+
public class OrderProcessSaga : Saga<Order>,
25+
IIntegrationEventHandler<SubmitOrderCommandMsg>,
26+
IIntegrationEventHandler<ConfirmGracePeriodCommandMsg>,
27+
IAsyncRequestHandler<CancelOrderCommand, bool>
28+
{
29+
private readonly IMediator _mediator;
30+
private readonly Func<Owned<OrderingContext>> _dbContextFactory;
31+
32+
public OrderProcessSaga(
33+
Func<Owned<OrderingContext>> dbContextFactory, OrderingContext orderingContext,
34+
IMediator mediator)
35+
: base(orderingContext)
36+
{
37+
_dbContextFactory = dbContextFactory;
38+
_mediator = mediator;
39+
}
40+
41+
/// <summary>
42+
/// Command handler which starts the create order process
43+
/// and initializes the saga
44+
/// </summary>
45+
/// <param name="command">
46+
/// Integration command message which is sent by the
47+
/// basket.api once it has successfully process the
48+
/// order items.
49+
/// </param>
50+
/// <returns></returns>
51+
public async Task Handle(SubmitOrderCommandMsg command)
52+
{
53+
var orderSaga = FindSagaById(command.OrderNumber);
54+
CheckValidSagaId(orderSaga);
55+
56+
// TODO: This handler should change to Integration command handler type once command bus is implemented
57+
58+
// TODO: Send createOrder Command
59+
60+
// TODO: Set saga timeout
61+
}
62+
63+
/// <summary>
64+
/// Command handler which confirms that the grace period
65+
/// has been completed and order has not been cancelled.
66+
/// If so, the process continues for validation.
67+
/// </summary>
68+
/// <param name="command">
69+
/// Integration command message which is sent by a saga
70+
/// scheduler which provides the sagas that its grace
71+
/// period has completed.
72+
/// </param>
73+
/// <returns></returns>
74+
public async Task Handle(ConfirmGracePeriodCommandMsg command)
75+
{
76+
var orderSaga = FindSagaById(command.OrderNumber);
77+
CheckValidSagaId(orderSaga);
78+
79+
// TODO: This handler should change to Integration command handler type once command bus is implemented
80+
81+
// TODO: If order status is not cancelled, change state to awaitingValidation and
82+
// send ConfirmOrderStockCommandMsg to Inventory api
83+
}
84+
85+
86+
/// <summary>
87+
/// Handler which processes the command when
88+
/// customer executes cancel order from app
89+
/// </summary>
90+
/// <param name="command"></param>
91+
/// <returns></returns>
92+
public async Task<bool> Handle(CancelOrderCommand command)
93+
{
94+
var orderSaga = FindSagaById(command.OrderNumber);
95+
CheckValidSagaId(orderSaga);
96+
97+
// Set order status tu cancelled
98+
99+
return true;
100+
}
101+
102+
private void CheckValidSagaId(Order orderSaga)
103+
{
104+
if (orderSaga is null)
105+
{
106+
throw new OrderingDomainException("Not able to process order saga event. Reason: no valid orderId");
107+
}
108+
}
109+
110+
#region CommandHandlerIdentifiers
111+
112+
public class CancelOrderCommandIdentifiedHandler : IdentifierCommandHandler<CancelOrderCommand, bool>
113+
{
114+
public CancelOrderCommandIdentifiedHandler(IMediator mediator, IRequestManager requestManager) : base(mediator, requestManager)
115+
{
116+
}
117+
118+
protected override bool CreateResultForDuplicateRequest()
119+
{
120+
return true; // Ignore duplicate requests for processing order.
121+
}
122+
}
123+
124+
#endregion
125+
}
126+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
using Microsoft.EntityFrameworkCore;
2+
using Microsoft.eShopOnContainers.Services.Ordering.Domain.Seedwork;
3+
using System.Linq;
4+
using System.Threading.Tasks;
5+
6+
namespace Ordering.API.Application.Sagas
7+
{
8+
public abstract class Saga<TEntity> where TEntity : Entity
9+
{
10+
private readonly DbContext _dbContext;
11+
12+
public Saga(DbContext dbContext)
13+
{
14+
_dbContext = dbContext;
15+
}
16+
17+
protected TEntity FindSagaById(int id, DbContext context = null)
18+
{
19+
var ctx = context ?? _dbContext;
20+
return ctx.Set<TEntity>().Where(x => x.Id == id).SingleOrDefault();
21+
}
22+
23+
protected async Task<bool> SaveChangesAsync(DbContext context = null)
24+
{
25+
var ctx = context ?? _dbContext;
26+
var result = await ctx.SaveChangesAsync();
27+
return result > 0;
28+
}
29+
}
30+
}

src/Services/Ordering/Ordering.API/Ordering.API.csproj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,9 @@
7979
</ItemGroup>
8080

8181
<ItemGroup>
82+
<Folder Include="Application\IntegrationCommands\CommandHandlers\" />
83+
<Folder Include="Application\IntegrationEvents\EventHandling\" />
8284
<Folder Include="Infrastructure\IntegrationEventMigrations\" />
83-
<Folder Include="IntegrationEvents\EventHandling\" />
8485
</ItemGroup>
8586

8687
</Project>

0 commit comments

Comments
 (0)