-
Notifications
You must be signed in to change notification settings - Fork 15
/
Copy pathSideEffectBroker.cs
68 lines (56 loc) · 2.75 KB
/
SideEffectBroker.cs
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
// Copyright (c) TotalSoft.
// This source code is licensed under the MIT license.
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Concurrent;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace NBB.Core.Effects
{
public class SideEffectBroker : ISideEffectBroker
{
private static readonly ConcurrentDictionary<Type, Type> Cache = new();
private readonly IServiceProvider _serviceProvider;
public SideEffectBroker(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public async Task<TSideEffectResult> Run<TSideEffect, TSideEffectResult>(TSideEffect sideEffect, CancellationToken cancellationToken = default)
where TSideEffect : ISideEffect<TSideEffectResult>
{
var sideEffectHandlerType = GetSideEffectHandlerTypeFor<TSideEffect, TSideEffectResult>();
if (_serviceProvider.GetRequiredService(sideEffectHandlerType) is not ISideEffectHandler<TSideEffect, TSideEffectResult> sideEffectHandler)
{
throw new Exception($"Could not create a side effect handler for type {typeof(TSideEffect).Name}");
}
var result = await sideEffectHandler.Handle(sideEffect, cancellationToken);
return result;
}
private static Type GetSideEffectHandlerTypeFor<TSideEffect, TSideEffectResult>()
where TSideEffect : ISideEffect<TSideEffectResult>
{
var handlerType = Cache.GetOrAdd(
typeof(TSideEffect),
sideEffType => TypeImplementsOpenGenericInterface(sideEffType, typeof(IAmHandledBy<>))
? GetFirstTypeParamForOpenGenericInterface(sideEffType, typeof(IAmHandledBy<>))
: typeof(ISideEffectHandler<TSideEffect, TSideEffectResult>));
return handlerType;
}
private static bool TypeImplementsOpenGenericInterface(Type t, Type openGenericInterfaceType)
{
return t.GetInterfaces()
.Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == openGenericInterfaceType);
}
private static Type GetFirstTypeParamForOpenGenericInterface(Type genericType, Type openGenericInterfaceType)
{
var closedGenericIntf = genericType.GetInterfaces().SingleOrDefault(i =>
i.IsGenericType && i.GetGenericTypeDefinition() == openGenericInterfaceType);
if (closedGenericIntf == null)
{
throw new Exception($"Type {genericType.Name} does not implement generic interface {openGenericInterfaceType.Name}");
}
return closedGenericIntf.GetGenericArguments().First();
}
}
}