1- using System . Reflection ;
1+ using System . Reflection ;
22using Cnblogs . Architecture . Ddd . EventBus . Abstractions ;
33using Cnblogs . Architecture . Ddd . EventBus . Dapr ;
4+ using MediatR ;
45using Microsoft . AspNetCore . Routing ;
56using Microsoft . Extensions . DependencyInjection ;
67using Microsoft . Extensions . Options ;
@@ -19,20 +20,11 @@ public static class EndPointExtensions
1920 /// <param name="builder"><see cref="IEndpointRouteBuilder"/></param>
2021 /// <typeparam name="TEvent">事件类型。</typeparam>
2122 /// <returns><see cref="IEndpointConventionBuilder"/></returns>
22- public static IEndpointConventionBuilder Subscribe < TEvent > ( this IEndpointRouteBuilder builder )
23+ public static IEndpointRouteBuilder Subscribe < TEvent > ( this IEndpointRouteBuilder builder )
2324 where TEvent : IntegrationEvent
2425 {
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 ) ;
3628 }
3729
3830 /// <summary>
@@ -42,7 +34,7 @@ public static IEndpointConventionBuilder Subscribe<TEvent>(this IEndpointRouteBu
4234 /// <param name="appName">事件隶属名称。</param>
4335 /// <typeparam name="TEvent">事件类型。</typeparam>
4436 /// <returns></returns>
45- public static IEndpointConventionBuilder Subscribe < TEvent > ( this IEndpointRouteBuilder builder , string appName )
37+ public static IEndpointRouteBuilder Subscribe < TEvent > ( this IEndpointRouteBuilder builder , string appName )
4638 where TEvent : IntegrationEvent
4739 {
4840 var eventName = typeof ( TEvent ) . Name ;
@@ -57,7 +49,7 @@ public static IEndpointConventionBuilder Subscribe<TEvent>(this IEndpointRouteBu
5749 /// <param name="appName">应用名称。</param>
5850 /// <typeparam name="TEvent">事件类型。</typeparam>
5951 /// <returns></returns>
60- public static IEndpointConventionBuilder Subscribe < TEvent > (
52+ public static IEndpointRouteBuilder Subscribe < TEvent > (
6153 this IEndpointRouteBuilder builder ,
6254 string route ,
6355 string appName )
@@ -68,36 +60,78 @@ public static IEndpointConventionBuilder Subscribe<TEvent>(
6860 var result = builder
6961 . MapPost ( route , ( TEvent receivedEvent , IEventBus eventBus ) => eventBus . ReceiveAsync ( receivedEvent ) )
7062 . WithTopic ( DaprOptions . PubSubName , DaprUtils . GetDaprTopicName < TEvent > ( appName ) ) ;
71- return result ;
63+
64+ return builder ;
7265 }
7366
7467 /// <summary>
7568 /// 订阅 Assembly 中的全部事件。
7669 /// </summary>
7770 /// <param name="builder"><see cref="IEndpointRouteBuilder"/></param>
7871 /// <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 )
8073 {
8174 builder . EnsureDaprEventBus ( ) ;
8275
83- var method = typeof ( EndPointExtensions ) . GetMethod (
84- nameof ( Subscribe ) ,
85- new [ ] { typeof ( IEndpointRouteBuilder ) , typeof ( string ) } ) ! ;
76+ var method = GetSubscribeMethod ( ) ;
77+
8678 foreach ( var assembly in assemblies )
8779 {
8880 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 ( ) )
94110 {
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 ) ;
97112 }
113+ }
114+
115+ return builder ;
116+ }
98117
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+ }
100132 }
133+
134+ return builder ;
101135 }
102136
103137 private static void EnsureEventBusRegistered ( this IEndpointRouteBuilder builder , DaprOptions daprOptions )
@@ -142,4 +176,32 @@ private static void EnsureDaprEventBus(this IEndpointRouteBuilder builder)
142176 builder . EnsureDaprSubscribeHandlerMapped ( options ) ;
143177 builder . EnsureEventBusRegistered ( options ) ;
144178 }
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