ServiceCollectionExtensions.cs
4,010 bytes
| 1 | using Microsoft.Extensions.Configuration; |
|---|---|
| 2 | using Microsoft.Extensions.DependencyInjection; |
| 3 | using Microsoft.Extensions.DependencyInjection.Extensions; |
| 4 | using SplitApp.Shared.Messaging.Integration.Users; |
| 5 | using SplitApp.Shared.Messaging.Internal; |
| 6 | |
| 7 | namespace SplitApp.Shared.Messaging; |
| 8 | |
| 9 | public static class ServiceCollectionExtensions |
| 10 | { |
| 11 | /// <summary> |
| 12 | /// Registers the RabbitMQ-backed message bus, connection provider, consumer hosted service, |
| 13 | /// and handler registry. Bind <see cref="MessagingOptions"/> from configuration section |
| 14 | /// <c>Messaging:RabbitMq</c>. Call AddIntegrationEventHandler / AddIntegrationRequestHandler |
| 15 | /// for each handler the service should consume. |
| 16 | /// </summary> |
| 17 | public static IServiceCollection AddMessaging(this IServiceCollection services, IConfiguration configuration) |
| 18 | { |
| 19 | services.AddOptions<MessagingOptions>() |
| 20 | .Bind(configuration.GetSection(MessagingOptions.SectionName)) |
| 21 | .PostConfigure(o => |
| 22 | { |
| 23 | if (string.IsNullOrWhiteSpace(o.ServiceName)) |
| 24 | throw new InvalidOperationException("MessagingOptions.ServiceName must be set per host"); |
| 25 | }); |
| 26 | |
| 27 | services.TryAddSingleton<RabbitMqConnectionProvider>(); |
| 28 | |
| 29 | // HandlerRegistry pulls in every MessageHandlerRegistration singleton registered |
| 30 | // via AddIntegrationEventHandler / AddIntegrationRequestHandler. Resolved as singleton |
| 31 | // so the consumer service sees all registrations. |
| 32 | services.TryAddSingleton<HandlerRegistry>(sp => |
| 33 | { |
| 34 | var registry = new HandlerRegistry(); |
| 35 | foreach (var r in sp.GetServices<MessageHandlerRegistration>()) |
| 36 | { |
| 37 | registry.Register(r); |
| 38 | } |
| 39 | return registry; |
| 40 | }); |
| 41 | |
| 42 | services.TryAddSingleton<IMessageBus, RabbitMqBus>(); |
| 43 | services.TryAddSingleton<IUserLookup, UserLookup>(); |
| 44 | services.AddHostedService<RabbitMqConsumerHostedService>(); |
| 45 | |
| 46 | return services; |
| 47 | } |
| 48 | |
| 49 | /// <summary>Convenience overload that sets <see cref="MessagingOptions.ServiceName"/> in-line.</summary> |
| 50 | public static IServiceCollection AddMessaging( |
| 51 | this IServiceCollection services, |
| 52 | IConfiguration configuration, |
| 53 | string serviceName) |
| 54 | { |
| 55 | services.AddMessaging(configuration); |
| 56 | services.PostConfigure<MessagingOptions>(o => o.ServiceName = serviceName); |
| 57 | return services; |
| 58 | } |
| 59 | |
| 60 | public static IServiceCollection AddIntegrationEventHandler<TEvent, THandler>(this IServiceCollection services) |
| 61 | where TEvent : IIntegrationEvent |
| 62 | where THandler : class, IEventHandler<TEvent> |
| 63 | { |
| 64 | services.AddScoped<THandler>(); |
| 65 | |
| 66 | services.AddSingleton(_ => new MessageHandlerRegistration |
| 67 | { |
| 68 | MessageType = typeof(TEvent), |
| 69 | HandlerType = typeof(THandler), |
| 70 | ResponseType = null, |
| 71 | Exchange = RabbitMqTopology.EventsExchange, |
| 72 | RoutingKey = typeof(TEvent).Name, |
| 73 | Kind = MessageKind.Event, |
| 74 | Dispatcher = MessageDispatcherFactory.CreateEventDispatcher<TEvent, THandler>(), |
| 75 | }); |
| 76 | |
| 77 | return services; |
| 78 | } |
| 79 | |
| 80 | public static IServiceCollection AddIntegrationRequestHandler<TRequest, TResponse, THandler>( |
| 81 | this IServiceCollection services) |
| 82 | where TRequest : IIntegrationRequest<TResponse> |
| 83 | where THandler : class, IRequestHandler<TRequest, TResponse> |
| 84 | { |
| 85 | services.AddScoped<THandler>(); |
| 86 | |
| 87 | services.AddSingleton(_ => new MessageHandlerRegistration |
| 88 | { |
| 89 | MessageType = typeof(TRequest), |
| 90 | HandlerType = typeof(THandler), |
| 91 | ResponseType = typeof(TResponse), |
| 92 | Exchange = RabbitMqTopology.RequestsExchange, |
| 93 | RoutingKey = typeof(TRequest).Name, |
| 94 | Kind = MessageKind.Request, |
| 95 | Dispatcher = MessageDispatcherFactory.CreateRequestDispatcher<TRequest, TResponse, THandler>(), |
| 96 | }); |
| 97 | |
| 98 | return services; |
| 99 | } |
| 100 | } |
| 101 | |