-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathSoftawareCqsDecoratorBuilder.cs
More file actions
91 lines (74 loc) · 4.07 KB
/
SoftawareCqsDecoratorBuilder.cs
File metadata and controls
91 lines (74 loc) · 4.07 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
using softaware.Cqs;
using softaware.Cqs.DependencyInjection;
namespace Microsoft.Extensions.DependencyInjection;
/// <summary>
/// Provides methods for configuring decorators for the softaware CQS infrastructure.
/// </summary>
public class SoftawareCqsDecoratorBuilder
{
/// <summary>
/// The service collection.
/// </summary>
public IServiceCollection Services { get; }
/// <summary>
/// Initializes a new instance of the <see cref="SoftawareCqsDecoratorBuilder"/> class.
/// </summary>
/// <param name="services">The service collection.</param>
public SoftawareCqsDecoratorBuilder(IServiceCollection services) =>
this.Services = services;
/// <summary>
/// Adds a request handler decorator.
/// </summary>
/// <param name="decoratorType">Type type of the decorator. The decorator must implement <see cref="IRequestHandler{TRequest, TResult}"/>.</param>
public SoftawareCqsDecoratorBuilder AddRequestHandlerDecorator(Type decoratorType)
{
var implementedInterfaceTypes = decoratorType.GetImplementedRequestHandlerInterfaceTypes();
if (!implementedInterfaceTypes.Any())
{
throw new ArgumentException($"Type '{decoratorType}' cannot be used as decorator because it does not implement IRequestHandler<TRequest, TResult>.", nameof(decoratorType));
}
(var isDecorator, var isValidDecoratorConfiguration) = decoratorType.GetDecoratorInfo();
if (!isDecorator)
{
throw new ArgumentException($"Type '{decoratorType}' cannot be used as decorator for '{implementedInterfaceTypes.Single()}' because it has no constructor parameter with this type.", nameof(decoratorType));
}
else if (!isValidDecoratorConfiguration)
{
var implementedInterfaceTypesString = string.Join(", ", implementedInterfaceTypes.Select(t => $"'{t}'"));
throw new ArgumentException($"Type '{decoratorType}' cannot be used as decorator for [{implementedInterfaceTypesString}] because it is not supported that decorators implement multiple IRequestHandler<TRequest, TResult> interfaces.", nameof(decoratorType));
}
foreach (var implementedInterfaceType in implementedInterfaceTypes)
{
// We have to distinguish between generic IRequestHandler implementations
// (e.g. class Decorator<TRequest, TResult> : IRequestHandler<TRequest, TResult>)
// that should be applied to different request types (based on the generic
// constraints) and non-generic implementations that target a specific request type
// (e.g. class Decorator : IRequestHandler<ICommand, NoResult).
// A mix of both is currently not supported.
int genericParametersInImplementedInterface = implementedInterfaceType.GetGenericArguments().Count(t => t.IsGenericParameter);
switch (genericParametersInImplementedInterface)
{
case 0:
// register as IRequestHandler<ICommand, NoResult>
this.Services.Decorate(implementedInterfaceType, decoratorType);
break;
case 2:
// register as IRequestHandler<,>
this.Services.Decorate(RequestHandlerTypeHelper.GenericRequestHandlerTypeDefinition, decoratorType);
break;
default:
var message =
@"Sorry, partially closed decorators are not supported at the moment. You can achieve the same behavior by changing your decorator class definition to a generic type with two type arguments and applying type constraints:
For example:
class Decorator<TResult> : IRequestHandler<SomeRequest, TResult>
where TRequest : IRequest<TResult>
can be changed to
class Decorator<TRequest, TResult> : IRequestHandler<TRequest, TResult>
where TRequest : SomeRequest
Alternatively, you can use softaware.CQS.SimpleInjector instead of softaware.CQS.DependencyInjection.";
throw new NotSupportedException(message);
}
}
return this;
}
}