1
- using System . Reflection ;
1
+ using System . Reflection ;
2
2
using Cnblogs . Architecture . Ddd . EventBus . Abstractions ;
3
3
using Cnblogs . Architecture . Ddd . EventBus . Dapr ;
4
+ using MediatR ;
4
5
using Microsoft . AspNetCore . Routing ;
5
6
using Microsoft . Extensions . DependencyInjection ;
6
7
using Microsoft . Extensions . Options ;
@@ -19,20 +20,11 @@ public static class EndPointExtensions
19
20
/// <param name="builder"><see cref="IEndpointRouteBuilder"/></param>
20
21
/// <typeparam name="TEvent">事件类型。</typeparam>
21
22
/// <returns><see cref="IEndpointConventionBuilder"/></returns>
22
- public static IEndpointConventionBuilder Subscribe < TEvent > ( this IEndpointRouteBuilder builder )
23
+ public static IEndpointRouteBuilder Subscribe < TEvent > ( this IEndpointRouteBuilder builder )
23
24
where TEvent : IntegrationEvent
24
25
{
25
- var attr = typeof ( TEvent ) . Assembly
26
- . GetCustomAttributes ( typeof ( AssemblyAppNameAttribute ) , false )
27
- . Cast < AssemblyAppNameAttribute > ( )
28
- . FirstOrDefault ( ) ;
29
- if ( attr is null || string . IsNullOrEmpty ( attr . Name ) )
30
- {
31
- throw new InvalidOperationException (
32
- $ "No AppName was configured in assembly for event: { typeof ( TEvent ) . Name } , either use Subscribe<TEvent>(string appName) method to set AppName manually or add [assembly:AssemblyAppName()] to the Assembly that { typeof ( TEvent ) . Name } belongs to") ;
33
- }
34
-
35
- return builder . Subscribe < TEvent > ( attr . Name ) ;
26
+ var appName = typeof ( TEvent ) . Assembly . GetAppName ( ) ;
27
+ return builder . Subscribe < TEvent > ( appName ) ;
36
28
}
37
29
38
30
/// <summary>
@@ -42,7 +34,7 @@ public static IEndpointConventionBuilder Subscribe<TEvent>(this IEndpointRouteBu
42
34
/// <param name="appName">事件隶属名称。</param>
43
35
/// <typeparam name="TEvent">事件类型。</typeparam>
44
36
/// <returns></returns>
45
- public static IEndpointConventionBuilder Subscribe < TEvent > ( this IEndpointRouteBuilder builder , string appName )
37
+ public static IEndpointRouteBuilder Subscribe < TEvent > ( this IEndpointRouteBuilder builder , string appName )
46
38
where TEvent : IntegrationEvent
47
39
{
48
40
var eventName = typeof ( TEvent ) . Name ;
@@ -57,7 +49,7 @@ public static IEndpointConventionBuilder Subscribe<TEvent>(this IEndpointRouteBu
57
49
/// <param name="appName">应用名称。</param>
58
50
/// <typeparam name="TEvent">事件类型。</typeparam>
59
51
/// <returns></returns>
60
- public static IEndpointConventionBuilder Subscribe < TEvent > (
52
+ public static IEndpointRouteBuilder Subscribe < TEvent > (
61
53
this IEndpointRouteBuilder builder ,
62
54
string route ,
63
55
string appName )
@@ -68,36 +60,78 @@ public static IEndpointConventionBuilder Subscribe<TEvent>(
68
60
var result = builder
69
61
. MapPost ( route , ( TEvent receivedEvent , IEventBus eventBus ) => eventBus . ReceiveAsync ( receivedEvent ) )
70
62
. WithTopic ( DaprOptions . PubSubName , DaprUtils . GetDaprTopicName < TEvent > ( appName ) ) ;
71
- return result ;
63
+
64
+ return builder ;
72
65
}
73
66
74
67
/// <summary>
75
68
/// 订阅 Assembly 中的全部事件。
76
69
/// </summary>
77
70
/// <param name="builder"><see cref="IEndpointRouteBuilder"/></param>
78
71
/// <param name="assemblies"><see cref="Assembly"/></param>
79
- public static void Subscribe ( this IEndpointRouteBuilder builder , params Assembly [ ] assemblies )
72
+ public static IEndpointRouteBuilder Subscribe ( this IEndpointRouteBuilder builder , params Assembly [ ] assemblies )
80
73
{
81
74
builder . EnsureDaprEventBus ( ) ;
82
75
83
- var method = typeof ( EndPointExtensions ) . GetMethod (
84
- nameof ( Subscribe ) ,
85
- new [ ] { typeof ( IEndpointRouteBuilder ) , typeof ( string ) } ) ! ;
76
+ var method = GetSubscribeMethod ( ) ;
77
+
86
78
foreach ( var assembly in assemblies )
87
79
{
88
80
var events = assembly . GetTypes ( ) . Where ( x => x . IsSubclassOf ( typeof ( IntegrationEvent ) ) ) . ToList ( ) ;
89
- var attr = assembly
90
- . GetCustomAttributes ( typeof ( AssemblyAppNameAttribute ) , false )
91
- . Cast < AssemblyAppNameAttribute > ( )
92
- . FirstOrDefault ( ) ;
93
- if ( attr is null || string . IsNullOrEmpty ( attr . Name ) )
81
+ var appName = assembly . GetAppName ( ) ;
82
+ events . ForEach ( e => method . InvokeSubscribe ( e , builder , appName ) ) ;
83
+ }
84
+
85
+ return builder ;
86
+ }
87
+
88
+ /// <summary>
89
+ /// Subscribes integration events that the TEventHandler implements
90
+ /// </summary>
91
+ /// <typeparam name="TEventHandler">The integration event handler that implements <![CDATA[IIntegrationEventHandler<TEvent>]]></typeparam>
92
+ /// <param name="builder"><see cref="IEndpointRouteBuilder"/></param>
93
+ public static IEndpointRouteBuilder SubscribeByEventHandler < TEventHandler > ( this IEndpointRouteBuilder builder )
94
+ where TEventHandler : IEventBusHandler
95
+ {
96
+ return builder . SubscribeByEventHandler ( typeof ( TEventHandler ) ) ;
97
+ }
98
+
99
+ /// <summary>
100
+ /// Subscribes integration events that event handlers implement in assemblies
101
+ /// </summary>
102
+ /// <param name="builder"><see cref="IEndpointRouteBuilder"/></param>
103
+ /// <param name="assemblies">assemblies that event handlers reside</param>
104
+ /// <returns></returns>
105
+ public static IEndpointRouteBuilder SubscribeByEventHandler ( this IEndpointRouteBuilder builder , params Assembly [ ] assemblies )
106
+ {
107
+ foreach ( var assembly in assemblies )
108
+ {
109
+ foreach ( Type type in assembly . GetTypes ( ) )
94
110
{
95
- throw new InvalidOperationException (
96
- $ "No AppName was configured in assembly: { assembly . FullName } , either use Subscribe<TEvent>(string appName) method to set AppName manually or add [assembly:AssemblyAppName()] to the Assembly") ;
111
+ builder . SubscribeByEventHandler ( type ) ;
97
112
}
113
+ }
114
+
115
+ return builder ;
116
+ }
98
117
99
- events . ForEach ( e => method . MakeGenericMethod ( e ) . Invoke ( null , new object [ ] { builder , attr . Name } ) ) ;
118
+ private static IEndpointRouteBuilder SubscribeByEventHandler ( this IEndpointRouteBuilder builder , Type type )
119
+ {
120
+ var interfaces = type . GetInterfaces ( )
121
+ . Where ( i => i . IsGenericType && i . GetGenericTypeDefinition ( ) == typeof ( IIntegrationEventHandler < > ) ) ;
122
+
123
+ foreach ( var handlerInterface in interfaces )
124
+ {
125
+ var eventType = handlerInterface . GetGenericArguments ( ) . FirstOrDefault ( ) ;
126
+ if ( eventType != null )
127
+ {
128
+ var assembly = eventType . Assembly ;
129
+ var appName = assembly . GetAppName ( ) ;
130
+ GetSubscribeMethod ( ) . InvokeSubscribe ( eventType , builder , appName ) ;
131
+ }
100
132
}
133
+
134
+ return builder ;
101
135
}
102
136
103
137
private static void EnsureEventBusRegistered ( this IEndpointRouteBuilder builder , DaprOptions daprOptions )
@@ -142,4 +176,32 @@ private static void EnsureDaprEventBus(this IEndpointRouteBuilder builder)
142
176
builder . EnsureDaprSubscribeHandlerMapped ( options ) ;
143
177
builder . EnsureEventBusRegistered ( options ) ;
144
178
}
145
- }
179
+
180
+ private static MethodInfo GetSubscribeMethod ( )
181
+ {
182
+ return typeof ( EndPointExtensions ) . GetMethod (
183
+ nameof ( Subscribe ) ,
184
+ new [ ] { typeof ( IEndpointRouteBuilder ) , typeof ( string ) } ) ! ;
185
+ }
186
+
187
+ private static void InvokeSubscribe ( this MethodInfo method , Type eventType , IEndpointRouteBuilder builder , string appName )
188
+ {
189
+ method . MakeGenericMethod ( eventType ) . Invoke ( null , new object [ ] { builder , appName } ) ;
190
+ }
191
+
192
+ private static string GetAppName ( this Assembly assembly )
193
+ {
194
+ var appName = assembly
195
+ . GetCustomAttributes ( typeof ( AssemblyAppNameAttribute ) , false )
196
+ . Cast < AssemblyAppNameAttribute > ( )
197
+ . FirstOrDefault ( ) ? . Name ;
198
+
199
+ if ( string . IsNullOrEmpty ( appName ) )
200
+ {
201
+ throw new InvalidOperationException (
202
+ $ "No AppName was configured in assembly: { assembly . FullName } , either use Subscribe<TEvent>(string appName) method to set AppName manually or add [assembly:AssemblyAppName()] to the Assembly") ;
203
+ }
204
+
205
+ return appName ;
206
+ }
207
+ }
0 commit comments