Skip to content

Commit 3b9cd43

Browse files
committed
#4 Initial commit
1 parent a6443db commit 3b9cd43

14 files changed

+665
-0
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,3 +286,6 @@ __pycache__/
286286
*.btm.cs
287287
*.odx.cs
288288
*.xsd.cs
289+
290+
# VS Code
291+
.vscode/

Src/AssemblyInfo.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
// Allow test project to access internal classes.
2+
[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("Xer.Cqrs.Extensions.SimpleInjector.Tests")]
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
using System;
2+
using Xer.Delegator;
3+
4+
namespace Xer.Cqrs.Extensions.SimpleInjector
5+
{
6+
internal class CommandHandlerDelegateResolver : IMessageHandlerResolver
7+
{
8+
private readonly IMessageHandlerResolver _messageHandlerResolver;
9+
10+
public CommandHandlerDelegateResolver(IMessageHandlerResolver messageHandlerResolver)
11+
{
12+
_messageHandlerResolver = messageHandlerResolver;
13+
}
14+
15+
public MessageHandlerDelegate ResolveMessageHandler(Type messageType) => _messageHandlerResolver.ResolveMessageHandler(messageType);
16+
}
17+
}

Src/CqrsBuilder.cs

Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Reflection;
5+
using SimpleInjector;
6+
using SimpleInjector.Advanced;
7+
using Xer.Cqrs.CommandStack;
8+
using Xer.Cqrs.CommandStack.Attributes;
9+
using Xer.Cqrs.CommandStack.Resolvers;
10+
using Xer.Cqrs.EventStack;
11+
using Xer.Cqrs.EventStack.Attributes;
12+
using Xer.Cqrs.EventStack.Resolvers;
13+
using Xer.Delegator;
14+
using Xer.Delegator.Registrations;
15+
using Xer.Delegator.Resolvers;
16+
17+
namespace Xer.Cqrs.Extensions.SimpleInjector
18+
{
19+
internal class CqrsBuilder : ICqrsBuilder
20+
{
21+
private readonly Container _container;
22+
23+
public CqrsBuilder(Container container)
24+
{
25+
_container = container;
26+
}
27+
28+
public ICqrsBuilder RegisterCommandDelegator()
29+
{
30+
_container.RegisterSingleton<CommandDelegator>(() =>
31+
{
32+
if (tryGetInstance(out IEnumerable<CommandHandlerDelegateResolver> commandHandlerResolvers))
33+
{
34+
CommandHandlerDelegateResolver[] resolverArray = commandHandlerResolvers.ToArray();
35+
36+
if (resolverArray.Length == 1)
37+
{
38+
return new CommandDelegator(resolverArray[0]);
39+
}
40+
41+
return new CommandDelegator(CompositeMessageHandlerResolver.Compose(resolverArray));
42+
}
43+
44+
return new CommandDelegator(new SingleMessageHandlerRegistration().BuildMessageHandlerResolver());
45+
});
46+
47+
return this;
48+
}
49+
50+
public ICqrsBuilder RegisterCommandHandlers(Assembly assembly)
51+
{
52+
return RegisterCommandHandlers(assembly, Lifestyle.Transient);
53+
}
54+
55+
public ICqrsBuilder RegisterCommandHandlers(Assembly assembly, Lifestyle lifeStyle)
56+
{
57+
return RegisterCommandHandlers(new[] { assembly }, lifeStyle);
58+
}
59+
60+
public ICqrsBuilder RegisterCommandHandlers(IEnumerable<Assembly> assemblies)
61+
{
62+
return RegisterCommandHandlers(assemblies, Lifestyle.Transient);
63+
}
64+
65+
public ICqrsBuilder RegisterCommandHandlers(IEnumerable<Assembly> assemblies, Lifestyle lifeStyle)
66+
{
67+
_container.Register(typeof(ICommandAsyncHandler<>), assemblies, lifeStyle);
68+
_container.Register(typeof(ICommandHandler<>), assemblies, lifeStyle);
69+
70+
// Register resolver.
71+
_container.AppendToCollection(
72+
typeof(CommandHandlerDelegateResolver),
73+
Lifestyle.Singleton.CreateRegistration(() =>
74+
new CommandHandlerDelegateResolver(
75+
// Combine async and sync command handler resolver.
76+
CompositeMessageHandlerResolver.Compose(
77+
new ContainerCommandAsyncHandlerResolver(new SimpleInjectorContainerAdapter(_container)),
78+
new ContainerCommandHandlerResolver(new SimpleInjectorContainerAdapter(_container)))),
79+
_container
80+
)
81+
);
82+
83+
return this;
84+
}
85+
86+
public ICqrsBuilder RegisterCommandHandlersAttributes(Assembly assembly)
87+
{
88+
return RegisterCommandHandlersAttributes(assembly, Lifestyle.Transient);
89+
}
90+
91+
public ICqrsBuilder RegisterCommandHandlersAttributes(Assembly assembly, Lifestyle lifeStyle)
92+
{
93+
return RegisterCommandHandlersAttributes(new[] { assembly }, lifeStyle);
94+
}
95+
96+
public ICqrsBuilder RegisterCommandHandlersAttributes(IEnumerable<Assembly> assemblies)
97+
{
98+
return RegisterCommandHandlersAttributes(assemblies, Lifestyle.Transient);
99+
}
100+
101+
public ICqrsBuilder RegisterCommandHandlersAttributes(IEnumerable<Assembly> assemblies, Lifestyle lifeStyle)
102+
{
103+
// Get all types that has methods marked with [CommandHandler] attribute.
104+
IEnumerable<Type> allTypes = assemblies.SelectMany(assembly => assembly.GetTypes())
105+
.Where(type => type.IsClass &&
106+
!type.IsAbstract &&
107+
CommandHandlerAttributeMethod.IsFoundInType(type)).ToArray();
108+
109+
foreach(Type type in allTypes)
110+
{
111+
// Register type as self.
112+
_container.Register(type, type, lifeStyle);
113+
}
114+
115+
var singleMessageHandlerRegistration = new SingleMessageHandlerRegistration();
116+
singleMessageHandlerRegistration.RegisterCommandHandlerAttributes(allTypes, _container.GetInstance);
117+
118+
// Register resolver.
119+
_container.AppendToCollection(
120+
typeof(CommandHandlerDelegateResolver),
121+
Lifestyle.Singleton.CreateRegistration(() =>
122+
new CommandHandlerDelegateResolver(singleMessageHandlerRegistration.BuildMessageHandlerResolver()),
123+
_container
124+
)
125+
);
126+
127+
return this;
128+
}
129+
130+
public ICqrsBuilder RegisterEventDelegator()
131+
{
132+
_container.RegisterSingleton<EventDelegator>(() =>
133+
{
134+
if (tryGetInstance(out IEnumerable<EventHandlerDelegateResolver> eventHandlerResolvers))
135+
{
136+
EventHandlerDelegateResolver[] resolverArray = eventHandlerResolvers.ToArray();
137+
138+
if (resolverArray.Length == 1)
139+
{
140+
return new EventDelegator(resolverArray[0]);
141+
}
142+
143+
return new EventDelegator(CompositeMessageHandlerResolver.Compose(resolverArray));
144+
}
145+
146+
return new EventDelegator(new SingleMessageHandlerRegistration().BuildMessageHandlerResolver());
147+
});
148+
149+
return this;
150+
}
151+
152+
public ICqrsBuilder RegisterEventHandlers(Assembly assembly)
153+
{
154+
return RegisterEventHandlers(assembly, Lifestyle.Transient);
155+
}
156+
157+
public ICqrsBuilder RegisterEventHandlers(Assembly assembly, Lifestyle lifeStyle)
158+
{
159+
return RegisterEventHandlers(new[] { assembly }, lifeStyle);
160+
}
161+
162+
public ICqrsBuilder RegisterEventHandlers(IEnumerable<Assembly> assemblies)
163+
{
164+
return RegisterEventHandlers(assemblies, Lifestyle.Transient);
165+
}
166+
167+
public ICqrsBuilder RegisterEventHandlers(IEnumerable<Assembly> assemblies, Lifestyle lifeStyle)
168+
{
169+
_container.Register(typeof(IEventAsyncHandler<>), assemblies, lifeStyle);
170+
_container.Register(typeof(IEventHandler<>), assemblies, lifeStyle);
171+
172+
// Register resolver.
173+
_container.AppendToCollection(
174+
typeof(EventHandlerDelegateResolver),
175+
Lifestyle.Singleton.CreateRegistration(() =>
176+
new EventHandlerDelegateResolver(new ContainerEventHandlerResolver(new SimpleInjectorContainerAdapter(_container))),
177+
_container
178+
)
179+
);
180+
181+
return this;
182+
}
183+
184+
public ICqrsBuilder RegisterEventHandlersAttributes(Assembly assembly)
185+
{
186+
return RegisterEventHandlersAttributes(assembly, Lifestyle.Transient);
187+
}
188+
189+
public ICqrsBuilder RegisterEventHandlersAttributes(Assembly assembly, Lifestyle lifeStyle)
190+
{
191+
return RegisterEventHandlersAttributes(new[] { assembly }, lifeStyle);
192+
}
193+
194+
public ICqrsBuilder RegisterEventHandlersAttributes(IEnumerable<Assembly> assemblies)
195+
{
196+
return RegisterEventHandlersAttributes(assemblies, Lifestyle.Transient);
197+
}
198+
199+
public ICqrsBuilder RegisterEventHandlersAttributes(IEnumerable<Assembly> assemblies, Lifestyle lifeStyle)
200+
{
201+
// Get all types that has methods marked with [CommandHandler] attribute.
202+
IEnumerable<Type> allTypes = assemblies.SelectMany(assembly => assembly.GetTypes())
203+
.Where(type => type.IsClass &&
204+
!type.IsAbstract &&
205+
EventHandlerAttributeMethod.IsFoundInType(type)).ToArray();
206+
207+
foreach(Type type in allTypes)
208+
{
209+
// Register type as self.
210+
_container.Register(type, type, lifeStyle);
211+
}
212+
213+
var multiMessageHandlerRegistration = new MultiMessageHandlerRegistration();
214+
multiMessageHandlerRegistration.RegisterEventHandlerAttributes(allTypes, _container.GetInstance);
215+
216+
// Register resolver.
217+
_container.AppendToCollection(
218+
typeof(EventHandlerDelegateResolver),
219+
Lifestyle.Singleton.CreateRegistration(() =>
220+
new EventHandlerDelegateResolver(multiMessageHandlerRegistration.BuildMessageHandlerResolver()),
221+
_container
222+
)
223+
);
224+
225+
return this;
226+
}
227+
228+
private bool tryGetInstance<T>(out T instance) where T : class
229+
{
230+
// Cast to IServiceProvider so that container will not throw if no resolver collection was registered.
231+
IServiceProvider serviceProvider = _container;
232+
233+
instance = serviceProvider.GetService(typeof(T)) as T;
234+
if (instance == null)
235+
{
236+
return false;
237+
}
238+
239+
return true;
240+
}
241+
}
242+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
using System;
2+
using Xer.Delegator;
3+
4+
namespace Xer.Cqrs.Extensions.SimpleInjector
5+
{
6+
internal class EventHandlerDelegateResolver : IMessageHandlerResolver
7+
{
8+
private readonly IMessageHandlerResolver _messageHandlerResolver;
9+
10+
public EventHandlerDelegateResolver(IMessageHandlerResolver messageHandlerResolver)
11+
{
12+
_messageHandlerResolver = messageHandlerResolver;
13+
}
14+
15+
public MessageHandlerDelegate ResolveMessageHandler(Type messageType) => _messageHandlerResolver.ResolveMessageHandler(messageType);
16+
}
17+
}

Src/ICqrsBuilder.cs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
using System.Collections.Generic;
2+
using System.Reflection;
3+
using SimpleInjector;
4+
5+
namespace Xer.Cqrs.Extensions.SimpleInjector
6+
{
7+
public interface ICqrsBuilder
8+
{
9+
ICqrsBuilder RegisterCommandHandlers(Assembly assembly);
10+
ICqrsBuilder RegisterCommandHandlers(Assembly assembly, Lifestyle lifeStyle);
11+
ICqrsBuilder RegisterCommandHandlersAttributes(Assembly assembly);
12+
ICqrsBuilder RegisterCommandHandlersAttributes(Assembly assembly, Lifestyle lifeStyle);
13+
ICqrsBuilder RegisterCommandHandlers(IEnumerable<Assembly> assemblies);
14+
ICqrsBuilder RegisterCommandHandlers(IEnumerable<Assembly> assemblies, Lifestyle lifeStyle);
15+
ICqrsBuilder RegisterCommandHandlersAttributes(IEnumerable<Assembly> assemblies);
16+
ICqrsBuilder RegisterCommandHandlersAttributes(IEnumerable<Assembly> assemblies, Lifestyle lifeStyle);
17+
ICqrsBuilder RegisterCommandDelegator();
18+
ICqrsBuilder RegisterEventHandlers(Assembly assembly);
19+
ICqrsBuilder RegisterEventHandlers(Assembly assembly, Lifestyle lifeStyle);
20+
ICqrsBuilder RegisterEventHandlersAttributes(Assembly assembly);
21+
ICqrsBuilder RegisterEventHandlersAttributes(Assembly assembly, Lifestyle lifeStyle);
22+
ICqrsBuilder RegisterEventHandlers(IEnumerable<Assembly> assemblies);
23+
ICqrsBuilder RegisterEventHandlers(IEnumerable<Assembly> assemblies, Lifestyle lifeStyle);
24+
ICqrsBuilder RegisterEventHandlersAttributes(IEnumerable<Assembly> assemblies);
25+
ICqrsBuilder RegisterEventHandlersAttributes(IEnumerable<Assembly> assemblies, Lifestyle lifeStyle);
26+
ICqrsBuilder RegisterEventDelegator();
27+
}
28+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using SimpleInjector;
4+
5+
namespace Xer.Cqrs.Extensions.SimpleInjector
6+
{
7+
/// <summary>
8+
/// Represents an adapter to SimpleInjector's Container.
9+
/// This will request an instance from the container without throwing an exception
10+
/// if the requested type is not registered to the container.
11+
/// </summary>
12+
public class SimpleInjectorContainerAdapter : CommandStack.Resolvers.IContainerAdapter,
13+
EventStack.Resolvers.IContainerAdapter
14+
{
15+
private readonly IServiceProvider _serviceProvider;
16+
17+
public SimpleInjectorContainerAdapter(Container container)
18+
{
19+
// Cast to IServiceProvider so that container will not throw if type is not registered.
20+
_serviceProvider = container;
21+
}
22+
23+
public T Resolve<T>() where T : class => _serviceProvider.GetService(typeof(T)) as T;
24+
public IEnumerable<T> ResolveMultiple<T>() where T : class => _serviceProvider.GetService(typeof(IEnumerable<T>)) as IEnumerable<T>;
25+
}
26+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Reflection;
4+
using Xer.Cqrs.Extensions.SimpleInjector;
5+
6+
namespace SimpleInjector
7+
{
8+
public static class SimpleInjectorContainerExtensions
9+
{
10+
public static Container RegisterCqrs(this Container container, Assembly assembly)
11+
{
12+
return AddCqrs(container, new[] { assembly });
13+
}
14+
15+
public static Container AddCqrs(this Container container, IEnumerable<Assembly> assemblies)
16+
{
17+
RegisterCqrsCore(container)
18+
.RegisterCommandHandlers(assemblies)
19+
.RegisterCommandHandlersAttributes(assemblies)
20+
.RegisterEventHandlers(assemblies)
21+
.RegisterEventHandlersAttributes(assemblies);
22+
23+
return container;
24+
}
25+
26+
public static ICqrsBuilder RegisterCqrsCore(this Container container)
27+
{
28+
if (container == null)
29+
{
30+
throw new ArgumentNullException(nameof(container));
31+
}
32+
33+
// Builder will search in entry and reference assemblies if no assembly is provided.
34+
return new CqrsBuilder(container)
35+
.RegisterCommandDelegator()
36+
.RegisterEventDelegator();
37+
}
38+
}
39+
}

0 commit comments

Comments
 (0)