Skip to content

Commit d267519

Browse files
Merge pull request #237 from TransactionProcessing/bug/#236_enforceeventidondomaineventcontroller
enforce event in event controller
2 parents 26946b7 + e1ba192 commit d267519

File tree

2 files changed

+113
-13
lines changed

2 files changed

+113
-13
lines changed
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
using FileProcessor.Controllers;
2+
using Microsoft.AspNetCore.Http;
3+
using Microsoft.AspNetCore.Mvc;
4+
using Moq;
5+
using Newtonsoft.Json;
6+
using Shared.EventStore.EventHandling;
7+
using Shouldly;
8+
using System;
9+
using System.Collections.Generic;
10+
using System.Linq;
11+
using System.Text;
12+
using System.Threading.Tasks;
13+
using Xunit;
14+
15+
namespace FileProcessor.Tests
16+
{
17+
using System.Threading;
18+
using File.DomainEvents;
19+
using Shared.General;
20+
using Shared.Logger;
21+
22+
public class ControllerTests
23+
{
24+
public ControllerTests()
25+
{
26+
Logger.Initialise(new NullLogger());
27+
}
28+
[Fact]
29+
public async Task DomainEventController_EventIdNotPresentInJson_ErrorThrown()
30+
{
31+
Mock<IDomainEventHandlerResolver> resolver = new Mock<IDomainEventHandlerResolver>();
32+
TypeMap.AddType<FileLineAddedEvent>("FileLineAddedEvent");
33+
DefaultHttpContext httpContext = new DefaultHttpContext();
34+
httpContext.Request.Headers["eventType"] = "FileLineAddedEvent";
35+
DomainEventController controller = new DomainEventController(resolver.Object)
36+
{
37+
ControllerContext = new ControllerContext()
38+
{
39+
HttpContext = httpContext
40+
}
41+
};
42+
String json = "{\r\n \"estateId\": \"435613ac-a468-47a3-ac4f-649d89764c22\",\r\n \"fileId\": \"17ee2309-ec79-dd25-0af9-f557e565feaa\",\r\n \"fileLine\": \"\",\r\n \"lineNumber\": 16\r\n}\t";
43+
Object request = JsonConvert.DeserializeObject(json);
44+
ArgumentException ex = Should.Throw<ArgumentException>(async () => {
45+
await controller.PostEventAsync(request, CancellationToken.None);
46+
});
47+
ex.Message.ShouldBe("Domain Event must contain an Event Id");
48+
}
49+
50+
[Fact]
51+
public async Task DomainEventController_EventIdPresentInJson_NoErrorThrown()
52+
{
53+
Mock<IDomainEventHandlerResolver> resolver = new Mock<IDomainEventHandlerResolver>();
54+
TypeMap.AddType<FileLineAddedEvent>("FileLineAddedEvent");
55+
DefaultHttpContext httpContext = new DefaultHttpContext();
56+
httpContext.Request.Headers["eventType"] = "FileLineAddedEvent";
57+
DomainEventController controller = new DomainEventController(resolver.Object)
58+
{
59+
ControllerContext = new ControllerContext()
60+
{
61+
HttpContext = httpContext
62+
}
63+
};
64+
String json = "{\r\n \"estateId\": \"435613ac-a468-47a3-ac4f-649d89764c22\",\r\n \"fileId\": \"17ee2309-ec79-dd25-0af9-f557e565feaa\",\r\n \"fileLine\": \"\",\r\n \"lineNumber\": 16,\r\n \"eventId\": \"123456ac-a468-47a3-ac4f-649d89764b44\"\r\n}\t";
65+
Object request = JsonConvert.DeserializeObject(json);
66+
Should.NotThrow(async () => {
67+
await controller.PostEventAsync(request, CancellationToken.None);
68+
});
69+
}
70+
}
71+
}

FileProcessor/Controllers/DomainEventController.cs

Lines changed: 42 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ namespace FileProcessor.Controllers
99
using System.Threading;
1010
using Microsoft.AspNetCore.Mvc;
1111
using Newtonsoft.Json;
12+
using Newtonsoft.Json.Linq;
1213
using Shared.DomainDrivenDesign.EventSourcing;
1314
using Shared.EventStore.Aggregate;
1415
using Shared.EventStore.EventHandling;
@@ -60,12 +61,12 @@ public async Task<IActionResult> PostEventAsync([FromBody] Object request,
6061

6162
cancellationToken.Register(() => this.Callback(cancellationToken, domainEvent.EventId));
6263

64+
List<IDomainEventHandler> eventHandlers = this.GetDomainEventHandlers(domainEvent);
65+
6366
try
6467
{
6568
Logger.LogInformation($"Processing event - ID [{domainEvent.EventId}], Type[{domainEvent.GetType().Name}]");
6669

67-
List<IDomainEventHandler> eventHandlers = this.DomainEventHandlerResolver.GetDomainEventHandlers(domainEvent);
68-
6970
if (eventHandlers == null || eventHandlers.Any() == false)
7071
{
7172
// Log a warning out
@@ -109,22 +110,37 @@ private void Callback(CancellationToken cancellationToken,
109110
}
110111
}
111112

112-
/// <summary>
113-
/// Gets the domain event.
114-
/// </summary>
115-
/// <param name="domainEvent">The domain event.</param>
116-
/// <returns></returns>
113+
private List<IDomainEventHandler> GetDomainEventHandlers(IDomainEvent domainEvent)
114+
{
115+
116+
if (this.Request.Headers.ContainsKey("EventHandler"))
117+
{
118+
var eventHandler = this.Request.Headers["EventHandler"];
119+
var eventHandlerType = this.Request.Headers["EventHandlerType"];
120+
var resolver = Startup.Container.GetInstance<IDomainEventHandlerResolver>(eventHandlerType);
121+
// We are being told by the caller to use a specific handler
122+
var allhandlers = resolver.GetDomainEventHandlers(domainEvent);
123+
var handlers = allhandlers.Where(h => h.GetType().Name.Contains(eventHandler));
124+
125+
return handlers.ToList();
126+
127+
}
128+
129+
List<IDomainEventHandler> eventHandlers = this.DomainEventHandlerResolver.GetDomainEventHandlers(domainEvent);
130+
return eventHandlers;
131+
}
132+
117133
private async Task<IDomainEvent> GetDomainEvent(Object domainEvent)
118134
{
119-
String eventType = this.Request.Query["eventType"].ToString();
135+
String eventType = this.Request.Headers["eventType"].ToString();
120136

121-
var type = TypeMap.GetType(eventType);
137+
Type type = TypeMap.GetType(eventType);
122138

123139
if (type == null)
124140
throw new Exception($"Failed to find a domain event with type {eventType}");
125141

126142
JsonIgnoreAttributeIgnorerContractResolver jsonIgnoreAttributeIgnorerContractResolver = new JsonIgnoreAttributeIgnorerContractResolver();
127-
var jsonSerialiserSettings = new JsonSerializerSettings
143+
JsonSerializerSettings jsonSerialiserSettings = new JsonSerializerSettings
128144
{
129145
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
130146
TypeNameHandling = TypeNameHandling.All,
@@ -135,15 +151,28 @@ private async Task<IDomainEvent> GetDomainEvent(Object domainEvent)
135151

136152
if (type.IsSubclassOf(typeof(DomainEvent)))
137153
{
138-
var json = JsonConvert.SerializeObject(domainEvent, jsonSerialiserSettings);
139-
DomainEventFactory domainEventFactory = new();
154+
String json = JsonConvert.SerializeObject(domainEvent, jsonSerialiserSettings);
140155

141-
return domainEventFactory.CreateDomainEvent(json, type);
156+
DomainEventFactory domainEventFactory = new();
157+
String validatedJson = this.ValidateEvent(json);
158+
return domainEventFactory.CreateDomainEvent(validatedJson, type);
142159
}
143160

144161
return null;
145162
}
146163

164+
private String ValidateEvent(String domainEventJson)
165+
{
166+
JObject domainEvent = JObject.Parse(domainEventJson);
167+
168+
if (domainEvent.ContainsKey("eventId") == false || domainEvent["eventId"].ToObject<Guid>() == Guid.Empty)
169+
{
170+
throw new ArgumentException("Domain Event must contain an Event Id");
171+
}
172+
173+
return domainEventJson;
174+
}
175+
147176
#endregion
148177

149178
#region Others

0 commit comments

Comments
 (0)