/// <summary> /// Builds a <see cref="ServiceDescriptor"/>, describing a singleton <see cref="IHostedService"/>, to be used /// with dependency injection. /// </summary> /// <remarks> /// It reuses an existing <see cref="IBusProxy"/> singleton, if one is found using the provided /// <see cref="IRabbitMqConfig.Id"/>. /// /// If not, a new <see cref="IBusProxy"/> singleton is registered in the service factory wrapped by the /// <see cref="ServiceDescriptor"/>. /// </remarks> public Func <IServiceProvider, T> Build(IServiceCollection serviceCollection) { var isConsumer = typeof(T).IsSubclassOf(typeof(RabbitMqConsumer <T>)); if (!isConsumer && !typeof(T).IsSubclassOf(typeof(RabbitMqProducer <T>))) { throw new Exception( $"{nameof(T)}, of type {typeof(T).FullName}, must be a subclass of " + $"{nameof(RabbitMqConsumer<T>)} or {nameof(RabbitMqProducer<T>)}."); } if (_configRabbitMqConfig == null) { _configRabbitMqConfig = new RabbitMqConfig(); } var busProxy = serviceCollection .Where(serviceDescriptor => serviceDescriptor.Lifetime == ServiceLifetime.Singleton && serviceDescriptor.ServiceType == typeof(IBusProxy)) .Select(serviceDescriptor => (IBusProxy)serviceDescriptor.ImplementationInstance) .FirstOrDefault(registeredBusProxy => registeredBusProxy.Id == _configRabbitMqConfig.Id); // ReSharper disable once ConditionIsAlwaysTrueOrFalse // ReSharper disable HeuristicUnreachableCode if (busProxy == null) { // build an IServiceProvider early so as to ensure that an ILogger<T> can be passed to // ConsumerErrorStrategy var serviceProvider = new DefaultServiceProviderFactory(new ServiceProviderOptions { ValidateScopes = false }) .CreateBuilder(serviceCollection) .BuildServiceProvider(); var bus = RabbitMqService <T> .CreateLazyBus( _configRabbitMqConfig, _configUseStronglyTypedMessages, _configUseCorrelationIds, serviceProvider); busProxy = new BusProxy(_configRabbitMqConfig.Id, bus); serviceCollection.AddSingleton(busProxy); } // ReSharper restore HeuristicUnreachableCode Func <IServiceProvider, T> BuildServiceFactoryFactory() { T service = null; var @lock = new object(); return(serviceProvider => { // ReSharper disable once ConditionIsAlwaysTrueOrFalse if (service != null) { return service; } lock (@lock) { if (service != null) { return service; } // _configRabbitMqConfig must not be null here service = RabbitMqService <T> .Create <T>( isConsumer, busProxy, _configRabbitMqConfig, _configOnConnected, serviceProvider); return service; } }); } return(BuildServiceFactoryFactory()); }