diff --git a/Directory.Build.props b/Directory.Build.props index 64132785d..94fc28d2b 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -6,7 +6,7 @@ MIT Copyright (c) 2020 Sergio Aquilini - 2.1.2$(VersionSuffix) + 2.2.0$(VersionSuffix) https://beagle1984.github.io/silverback/ https://github.com/BEagle1984/silverback/ git diff --git a/docs/_docs/0-introduction/003-releases.md b/docs/_docs/0-introduction/003-releases.md index 757e39c00..389eb131e 100644 --- a/docs/_docs/0-introduction/003-releases.md +++ b/docs/_docs/0-introduction/003-releases.md @@ -4,6 +4,11 @@ permalink: /docs/releases toc: true --- +## [2.2.0](https://github.com/BEagle1984/silverback/releases/tag/v2.2.0) + +### What's new +* Allow custom outbound routers to be registered as scoped or transient (instead of singleton only) + ## [2.1.1](https://github.com/BEagle1984/silverback/releases/tag/v2.1.1) ### What's new diff --git a/docs/_docs/2-configuration/202-outbound.md b/docs/_docs/2-configuration/202-outbound.md index 9077f88bf..0e79cf38a 100644 --- a/docs/_docs/2-configuration/202-outbound.md +++ b/docs/_docs/2-configuration/202-outbound.md @@ -300,7 +300,3 @@ public class Startup } {% endhighlight %} - -The outbound routers can only be registered as singleton. If a scoped instance is needed you have to inject the `IServiceScopeFactory` (or `IServiceProvider`). -{: .notice--note} - diff --git a/samples/Examples/src/Silverback.Examples.Main/UseCases/Producing/Kafka/Advanced/CustomRoutingUseCase.cs b/samples/Examples/src/Silverback.Examples.Main/UseCases/Producing/Kafka/Advanced/CustomRoutingUseCase.cs index 37bc149c8..5b093331c 100644 --- a/samples/Examples/src/Silverback.Examples.Main/UseCases/Producing/Kafka/Advanced/CustomRoutingUseCase.cs +++ b/samples/Examples/src/Silverback.Examples.Main/UseCases/Producing/Kafka/Advanced/CustomRoutingUseCase.cs @@ -28,7 +28,7 @@ protected override void ConfigureServices(IServiceCollection services) => servic .AddSilverback() .UseModel() .WithConnectionToMessageBroker(options => options.AddKafka()) - .AddSingletonOutboundRouter(); + .AddScopedOutboundRouter(); protected override void Configure(BusConfigurator configurator, IServiceProvider serviceProvider) => configurator.Connect(endpoints => endpoints diff --git a/samples/Examples/src/Silverback.Examples.Main/UseCases/Producing/Kafka/HealthCheck/OutboundEndpointsHealthUseCase.cs b/samples/Examples/src/Silverback.Examples.Main/UseCases/Producing/Kafka/HealthCheck/OutboundEndpointsHealthUseCase.cs index 7dde6aa16..fc3eaf7f5 100644 --- a/samples/Examples/src/Silverback.Examples.Main/UseCases/Producing/Kafka/HealthCheck/OutboundEndpointsHealthUseCase.cs +++ b/samples/Examples/src/Silverback.Examples.Main/UseCases/Producing/Kafka/HealthCheck/OutboundEndpointsHealthUseCase.cs @@ -74,7 +74,8 @@ protected override async Task Execute(IServiceProvider serviceProvider) var result = await new OutboundEndpointsHealthCheckService( serviceProvider.GetRequiredService(), - serviceProvider.GetRequiredService()).PingAllEndpoints(); + serviceProvider.GetRequiredService(), + serviceProvider).PingAllEndpoints(); Console.ForegroundColor = Constants.PrimaryColor; Console.WriteLine(JsonConvert.SerializeObject(result, Formatting.Indented)); diff --git a/src/Silverback.Integration/Messaging/Configuration/BusConfiguratorExtensions.cs b/src/Silverback.Integration/Messaging/Configuration/BusConfiguratorExtensions.cs index 83cfb159b..9bb8ba194 100644 --- a/src/Silverback.Integration/Messaging/Configuration/BusConfiguratorExtensions.cs +++ b/src/Silverback.Integration/Messaging/Configuration/BusConfiguratorExtensions.cs @@ -33,8 +33,7 @@ public static IBrokerCollection Connect( var endpointsConfigurationBuilder = new EndpointsConfigurationBuilder( configurator.ServiceProvider.GetRequiredService(), configurator.ServiceProvider.GetRequiredService>(), - configurator.ServiceProvider.GetRequiredService(), - configurator.ServiceProvider); + configurator.ServiceProvider.GetRequiredService()); endpointsConfigurationAction?.Invoke(endpointsConfigurationBuilder); configurator.ServiceProvider.GetServices().ForEach(c => diff --git a/src/Silverback.Integration/Messaging/Configuration/EndpointsConfigurationBuilder.cs b/src/Silverback.Integration/Messaging/Configuration/EndpointsConfigurationBuilder.cs index 619be712c..1c52e37ad 100644 --- a/src/Silverback.Integration/Messaging/Configuration/EndpointsConfigurationBuilder.cs +++ b/src/Silverback.Integration/Messaging/Configuration/EndpointsConfigurationBuilder.cs @@ -16,18 +16,15 @@ public class EndpointsConfigurationBuilder : IEndpointsConfigurationBuilder private readonly IOutboundRoutingConfiguration _outboundRoutingConfiguration; private readonly IReadOnlyCollection _inboundConnectors; private readonly ErrorPolicyBuilder _errorPolicyBuilder; - private readonly IServiceProvider _serviceProvider; public EndpointsConfigurationBuilder( IOutboundRoutingConfiguration outboundRoutingConfiguration, IEnumerable inboundConnectors, - ErrorPolicyBuilder errorPolicyBuilder, - IServiceProvider serviceProvider) + ErrorPolicyBuilder errorPolicyBuilder) { _outboundRoutingConfiguration = outboundRoutingConfiguration; _inboundConnectors = inboundConnectors.ToList(); _errorPolicyBuilder = errorPolicyBuilder; - _serviceProvider = serviceProvider; } public IEndpointsConfigurationBuilder AddOutbound(IProducerEndpoint endpoint) @@ -85,8 +82,9 @@ public IEndpointsConfigurationBuilder AddOutbound( Type routerType, Type outboundConnectorType) { - var router = (IOutboundRouter) _serviceProvider.GetRequiredService(routerType); - _outboundRoutingConfiguration.Add(messageType, router, outboundConnectorType); + _outboundRoutingConfiguration.Add(messageType, + serviceProvider => (IOutboundRouter) serviceProvider.GetRequiredService(routerType), + outboundConnectorType); return this; } @@ -95,7 +93,7 @@ public IEndpointsConfigurationBuilder AddOutbound( IOutboundRouter router, Type outboundConnectorType) { - _outboundRoutingConfiguration.Add(messageType, router, outboundConnectorType); + _outboundRoutingConfiguration.Add(messageType, _ => router, outboundConnectorType); return this; } diff --git a/src/Silverback.Integration/Messaging/Configuration/ServiceCollectionExtensions.cs b/src/Silverback.Integration/Messaging/Configuration/ServiceCollectionExtensions.cs index 7ce88ce08..810c20ca7 100644 --- a/src/Silverback.Integration/Messaging/Configuration/ServiceCollectionExtensions.cs +++ b/src/Silverback.Integration/Messaging/Configuration/ServiceCollectionExtensions.cs @@ -70,7 +70,8 @@ public static IServiceCollection AddEndpointsConfigurator( /// A reference to this instance after the operation has completed. public static IServiceCollection AddSingletonBrokerBehavior(this IServiceCollection services, Type behaviorType) { - if (behaviorType == null) throw new ArgumentNullException(nameof(behaviorType)); + if (behaviorType == null) + throw new ArgumentNullException(nameof(behaviorType)); services.AddSingleton(typeof(IBrokerBehavior), behaviorType); @@ -106,7 +107,8 @@ public static IServiceCollection AddSingletonBrokerBehavior( this IServiceCollection services, Func implementationFactory) { - if (implementationFactory == null) throw new ArgumentNullException(nameof(implementationFactory)); + if (implementationFactory == null) + throw new ArgumentNullException(nameof(implementationFactory)); services.AddSingleton(typeof(IBrokerBehavior), implementationFactory); @@ -128,7 +130,8 @@ public static IServiceCollection AddSingletonBrokerBehavior( this IServiceCollection services, IBrokerBehavior implementationInstance) { - if (implementationInstance == null) throw new ArgumentNullException(nameof(implementationInstance)); + if (implementationInstance == null) + throw new ArgumentNullException(nameof(implementationInstance)); services.AddSingleton(typeof(IBrokerBehavior), implementationInstance); @@ -137,6 +140,128 @@ public static IServiceCollection AddSingletonBrokerBehavior( #endregion + #region AddTransientOutboundRouter + + /// + /// Adds a transient outbound router of the type specified in to the + /// specified . + /// + /// + /// The to add the + /// service to. + /// + /// The type of the outbound router to register and the implementation to use. + /// A reference to this instance after the operation has completed. + public static IServiceCollection AddTransientOutboundRouter(this IServiceCollection services, Type routerType) + { + if (routerType == null) + throw new ArgumentNullException(nameof(routerType)); + + services.AddTransient(routerType); + + return services; + } + + /// + /// Adds a transient outbound router of the type specified in to the + /// specified . + /// + /// The type of the outbound router to add. + /// + /// The to add the + /// service to. + /// + /// A reference to this instance after the operation has completed. + public static IServiceCollection AddTransientOutboundRouter(this IServiceCollection services) + where TRouter : class, IOutboundRouter => + AddTransientOutboundRouter(services, typeof(TRouter)); + + /// + /// Adds a transient outbound router with a + /// factory specified in to the + /// specified . + /// + /// + /// The to add the + /// service to. + /// + /// The factory that creates the service. + /// A reference to this instance after the operation has completed. + public static IServiceCollection AddTransientOutboundRouter( + this IServiceCollection services, + Func implementationFactory) + { + if (implementationFactory == null) + throw new ArgumentNullException(nameof(implementationFactory)); + + services.AddTransient(implementationFactory); + + return services; + } + + #endregion + + #region AddScopedOutboundRouter + + /// + /// Adds a scoped outbound router of the type specified in to the + /// specified . + /// + /// + /// The to add the + /// service to. + /// + /// The type of the outbound router to register and the implementation to use. + /// A reference to this instance after the operation has completed. + public static IServiceCollection AddScopedOutboundRouter(this IServiceCollection services, Type routerType) + { + if (routerType == null) + throw new ArgumentNullException(nameof(routerType)); + + services.AddScoped(routerType); + + return services; + } + + /// + /// Adds a scoped outbound router of the type specified in to the + /// specified . + /// + /// The type of the outbound router to add. + /// + /// The to add the + /// service to. + /// + /// A reference to this instance after the operation has completed. + public static IServiceCollection AddScopedOutboundRouter(this IServiceCollection services) + where TRouter : class, IOutboundRouter => + AddScopedOutboundRouter(services, typeof(TRouter)); + + /// + /// Adds a scoped outbound router with a + /// factory specified in to the + /// specified . + /// + /// + /// The to add the + /// service to. + /// + /// The factory that creates the service. + /// A reference to this instance after the operation has completed. + public static IServiceCollection AddScopedOutboundRouter( + this IServiceCollection services, + Func implementationFactory) + { + if (implementationFactory == null) + throw new ArgumentNullException(nameof(implementationFactory)); + + services.AddScoped(implementationFactory); + + return services; + } + + #endregion + #region AddSingletonOutboundRouter /// @@ -151,7 +276,8 @@ public static IServiceCollection AddSingletonBrokerBehavior( /// A reference to this instance after the operation has completed. public static IServiceCollection AddSingletonOutboundRouter(this IServiceCollection services, Type routerType) { - if (routerType == null) throw new ArgumentNullException(nameof(routerType)); + if (routerType == null) + throw new ArgumentNullException(nameof(routerType)); services.AddSingleton(routerType); @@ -187,7 +313,8 @@ public static IServiceCollection AddSingletonOutboundRouter( this IServiceCollection services, Func implementationFactory) { - if (implementationFactory == null) throw new ArgumentNullException(nameof(implementationFactory)); + if (implementationFactory == null) + throw new ArgumentNullException(nameof(implementationFactory)); services.AddSingleton(implementationFactory); @@ -209,7 +336,8 @@ public static IServiceCollection AddSingletonOutboundRouter( this IServiceCollection services, IOutboundRouter implementationInstance) { - if (implementationInstance == null) throw new ArgumentNullException(nameof(implementationInstance)); + if (implementationInstance == null) + throw new ArgumentNullException(nameof(implementationInstance)); services.AddSingleton(implementationInstance); diff --git a/src/Silverback.Integration/Messaging/Configuration/SilverbackBuilderExtensions.cs b/src/Silverback.Integration/Messaging/Configuration/SilverbackBuilderExtensions.cs index b496427b6..c7788a2bd 100644 --- a/src/Silverback.Integration/Messaging/Configuration/SilverbackBuilderExtensions.cs +++ b/src/Silverback.Integration/Messaging/Configuration/SilverbackBuilderExtensions.cs @@ -169,6 +169,100 @@ public static ISilverbackBuilder AddSingletonBrokerBehavior( #endregion + #region AddTransientOutboundRouter + + /// + /// Adds a transient outbound router of the type specified in to the + /// . + /// + /// + /// The type of the outbound router to register and the implementation to use. + /// A reference to this instance after the operation has completed. + public static ISilverbackBuilder AddTransientOutboundRouter(this ISilverbackBuilder builder, Type routerType) + { + builder.Services.AddTransientOutboundRouter(routerType); + return builder; + } + + /// + /// Adds a transient outbound router of the type specified in to the + /// . + /// + /// The type of the outbound router to add. + /// + /// A reference to this instance after the operation has completed. + public static ISilverbackBuilder AddTransientOutboundRouter(this ISilverbackBuilder builder) + where TRouter : class, IOutboundRouter + { + builder.Services.AddTransientOutboundRouter(); + return builder; + } + + /// + /// Adds a transient outbound router with a + /// factory specified in to the + /// . + /// + /// + /// The factory that creates the service. + /// A reference to this instance after the operation has completed. + public static ISilverbackBuilder AddTransientOutboundRouter( + this ISilverbackBuilder builder, + Func implementationFactory) + { + builder.Services.AddTransientOutboundRouter(implementationFactory); + return builder; + } + + #endregion + + #region AddScopedOutboundRouter + + /// + /// Adds a scoped outbound router of the type specified in to the + /// . + /// + /// + /// The type of the outbound router to register and the implementation to use. + /// A reference to this instance after the operation has completed. + public static ISilverbackBuilder AddScopedOutboundRouter(this ISilverbackBuilder builder, Type routerType) + { + builder.Services.AddScopedOutboundRouter(routerType); + return builder; + } + + /// + /// Adds a scoped outbound router of the type specified in to the + /// . + /// + /// The type of the outbound router to add. + /// + /// A reference to this instance after the operation has completed. + public static ISilverbackBuilder AddScopedOutboundRouter(this ISilverbackBuilder builder) + where TRouter : class, IOutboundRouter + { + builder.Services.AddScopedOutboundRouter(); + return builder; + } + + /// + /// Adds a scoped outbound router with a + /// factory specified in to the + /// . + /// + /// + /// The factory that creates the service. + /// A reference to this instance after the operation has completed. + public static ISilverbackBuilder AddScopedOutboundRouter( + this ISilverbackBuilder builder, + Func implementationFactory) + { + builder.Services.AddScopedOutboundRouter(implementationFactory); + return builder; + } + + #endregion + #region AddSingletonOutboundRouter /// diff --git a/src/Silverback.Integration/Messaging/Connectors/Behaviors/OutboundRouterBehavior.cs b/src/Silverback.Integration/Messaging/Connectors/Behaviors/OutboundRouterBehavior.cs index 17999b2a4..0a6d67dc1 100644 --- a/src/Silverback.Integration/Messaging/Connectors/Behaviors/OutboundRouterBehavior.cs +++ b/src/Silverback.Integration/Messaging/Connectors/Behaviors/OutboundRouterBehavior.cs @@ -2,6 +2,7 @@ // This code is licensed under MIT license (see LICENSE file for details) using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; @@ -20,6 +21,9 @@ public class OutboundRouterBehavior : IBehavior, ISorted private readonly IServiceProvider _serviceProvider; private readonly IOutboundRoutingConfiguration _routing; + private readonly ConcurrentDictionary _routers = + new ConcurrentDictionary(); + public OutboundRouterBehavior(IServiceProvider serviceProvider) { _serviceProvider = serviceProvider; @@ -62,7 +66,8 @@ await _serviceProvider private IEnumerable CreateOutboundEnvelope(object message, IOutboundRoute route) { var headers = new MessageHeaderCollection(); - var endpoints = route.Router.GetDestinationEndpoints(message, headers); + var router = _routers.GetOrAdd(route, _ => route.GetOutboundRouter(_serviceProvider)); + var endpoints = router.GetDestinationEndpoints(message, headers); foreach (var endpoint in endpoints) { diff --git a/src/Silverback.Integration/Messaging/Connectors/IOutboundRoute.cs b/src/Silverback.Integration/Messaging/Connectors/IOutboundRoute.cs index 6c2f414b1..34db1782a 100644 --- a/src/Silverback.Integration/Messaging/Connectors/IOutboundRoute.cs +++ b/src/Silverback.Integration/Messaging/Connectors/IOutboundRoute.cs @@ -16,13 +16,13 @@ public interface IOutboundRoute Type MessageType { get; } /// - /// Gets the instance of to be used to determine the destination endpoint. + /// Gets the type of the to be used when publishing these messages. /// - IOutboundRouter Router { get; } + Type OutboundConnectorType { get; } /// - /// Gets the type of the to be used when publishing these messages. + /// Returns the instance of to be used to determine the destination endpoint. /// - Type OutboundConnectorType { get; } + IOutboundRouter GetOutboundRouter(IServiceProvider serviceProvider); } } \ No newline at end of file diff --git a/src/Silverback.Integration/Messaging/Connectors/IOutboundRoutingConfiguration.cs b/src/Silverback.Integration/Messaging/Connectors/IOutboundRoutingConfiguration.cs index f0d42c808..c2a76fcc6 100644 --- a/src/Silverback.Integration/Messaging/Connectors/IOutboundRoutingConfiguration.cs +++ b/src/Silverback.Integration/Messaging/Connectors/IOutboundRoutingConfiguration.cs @@ -29,25 +29,34 @@ public interface IOutboundRoutingConfiguration /// /// The type of the messages to be routed. /// - /// - /// The router to be used to determine the destination endpoint. + /// + /// The factory method to be used to get the instance of to be used to + /// determine the destination endpoint. /// /// /// The type of the to be used. /// If null, the default will be used. /// - IOutboundRoutingConfiguration Add(IOutboundRouter router, Type outboundConnectorType = null); + IOutboundRoutingConfiguration Add( + Func outboundRouterFactory, + Type outboundConnectorType = null); /// /// Add an outbound routing rule. /// /// The type of the messages to be routed. - /// The router to be used to determine the destination endpoint. + /// + /// The factory method to be used to get the instance of to be used to + /// determine the destination endpoint. + /// /// /// The type of the to be used. /// If null, the default will be used. /// - IOutboundRoutingConfiguration Add(Type messageType, IOutboundRouter router, Type outboundConnectorType = null); + IOutboundRoutingConfiguration Add( + Type messageType, + Func outboundRouterFactory, + Type outboundConnectorType = null); /// /// Returns the outbound routes that apply to the specified message. diff --git a/src/Silverback.Integration/Messaging/Connectors/OutboundRoute.cs b/src/Silverback.Integration/Messaging/Connectors/OutboundRoute.cs index dbe14972a..a22ee586a 100644 --- a/src/Silverback.Integration/Messaging/Connectors/OutboundRoute.cs +++ b/src/Silverback.Integration/Messaging/Connectors/OutboundRoute.cs @@ -8,17 +8,20 @@ namespace Silverback.Messaging.Connectors /// public class OutboundRoute : IOutboundRoute { - public OutboundRoute(Type messageType, IOutboundRouter router, Type outboundConnectorType) + private readonly Func _outboundRouterFactory; + + public OutboundRoute(Type messageType, Func outboundRouterFactory, Type outboundConnectorType) { MessageType = messageType; - Router = router; + _outboundRouterFactory = outboundRouterFactory; OutboundConnectorType = outboundConnectorType; } public Type MessageType { get; } - public IOutboundRouter Router { get; } - public Type OutboundConnectorType { get; } + + public IOutboundRouter GetOutboundRouter(IServiceProvider serviceProvider) => + _outboundRouterFactory.Invoke(serviceProvider); } } \ No newline at end of file diff --git a/src/Silverback.Integration/Messaging/Connectors/OutboundRoutingConfiguration.cs b/src/Silverback.Integration/Messaging/Connectors/OutboundRoutingConfiguration.cs index a32bb5161..e57370bd6 100644 --- a/src/Silverback.Integration/Messaging/Connectors/OutboundRoutingConfiguration.cs +++ b/src/Silverback.Integration/Messaging/Connectors/OutboundRoutingConfiguration.cs @@ -16,15 +16,15 @@ public class OutboundRoutingConfiguration : IOutboundRoutingConfiguration public IEnumerable Routes => _routes.AsReadOnly(); - public IOutboundRoutingConfiguration Add(IOutboundRouter router, Type outboundConnectorType) => - Add(typeof(TMessage), router, outboundConnectorType); + public IOutboundRoutingConfiguration Add(Func outboundRouterFactory, Type outboundConnectorType) => + Add(typeof(TMessage), outboundRouterFactory, outboundConnectorType); public IOutboundRoutingConfiguration Add( Type messageType, - IOutboundRouter router, + Func outboundRouterFactory, Type outboundConnectorType = null) { - _routes.Add(new OutboundRoute(messageType, router, outboundConnectorType)); + _routes.Add(new OutboundRoute(messageType, outboundRouterFactory, outboundConnectorType)); return this; } diff --git a/src/Silverback.Integration/Messaging/HealthChecks/OutboundEndpointsHealthCheckService.cs b/src/Silverback.Integration/Messaging/HealthChecks/OutboundEndpointsHealthCheckService.cs index c94b4480b..3b6305259 100644 --- a/src/Silverback.Integration/Messaging/HealthChecks/OutboundEndpointsHealthCheckService.cs +++ b/src/Silverback.Integration/Messaging/HealthChecks/OutboundEndpointsHealthCheckService.cs @@ -14,14 +14,17 @@ public class OutboundEndpointsHealthCheckService : IOutboundEndpointsHealthCheck { private readonly IOutboundRoutingConfiguration _outboundRoutingConfiguration; private readonly IBrokerCollection _brokerCollection; + private readonly IServiceProvider _serviceProvider; public OutboundEndpointsHealthCheckService( IOutboundRoutingConfiguration outboundRoutingConfiguration, - IBrokerCollection brokerCollection) + IBrokerCollection brokerCollection, + IServiceProvider serviceProvider) { _outboundRoutingConfiguration = outboundRoutingConfiguration ?? throw new ArgumentNullException(nameof(outboundRoutingConfiguration)); _brokerCollection = brokerCollection ?? throw new ArgumentNullException(nameof(brokerCollection)); + _serviceProvider = serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider)); } public async Task> PingAllEndpoints() @@ -30,7 +33,7 @@ public async Task> PingAllEndpoints() return Enumerable.Empty(); var tasks = _outboundRoutingConfiguration.Routes - .SelectMany(route => route.Router.Endpoints + .SelectMany(route => route.GetOutboundRouter(_serviceProvider).Endpoints .Select(async endpoint => { try diff --git a/tests/Silverback.Integration.Tests/Messaging/Connectors/Behaviors/OutboundRouterBehaviorTests.cs b/tests/Silverback.Integration.Tests/Messaging/Connectors/Behaviors/OutboundRouterBehaviorTests.cs index cce9d6a20..19c6fab48 100644 --- a/tests/Silverback.Integration.Tests/Messaging/Connectors/Behaviors/OutboundRouterBehaviorTests.cs +++ b/tests/Silverback.Integration.Tests/Messaging/Connectors/Behaviors/OutboundRouterBehaviorTests.cs @@ -1,6 +1,7 @@ // Copyright (c) 2020 Sergio Aquilini // This code is licensed under MIT license (see LICENSE file for details) +using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; @@ -28,6 +29,7 @@ public class OutboundRouterBehaviorTests private readonly TestBroker _broker; private readonly TestOtherBroker _otherBroker; private readonly TestSubscriber _testSubscriber; + private readonly IServiceProvider _serviceProvider; public OutboundRouterBehaviorTests() { @@ -49,14 +51,14 @@ public OutboundRouterBehaviorTests() services.AddNullLogger(); - var serviceProvider = services.BuildServiceProvider(); + _serviceProvider = services.BuildServiceProvider(); - _behavior = (OutboundRouterBehavior) serviceProvider.GetServices() + _behavior = (OutboundRouterBehavior) _serviceProvider.GetServices() .First(s => s is OutboundRouterBehavior); _routingConfiguration = - (OutboundRoutingConfiguration) serviceProvider.GetRequiredService(); - _broker = serviceProvider.GetRequiredService(); - _otherBroker = serviceProvider.GetRequiredService(); + (OutboundRoutingConfiguration) _serviceProvider.GetRequiredService(); + _broker = _serviceProvider.GetRequiredService(); + _otherBroker = _serviceProvider.GetRequiredService(); } [Theory, MemberData(nameof(Handle_MultipleMessages_CorrectlyRoutedToEndpoints_TestData))] @@ -65,11 +67,11 @@ public async Task Handle_MultipleMessages_CorrectlyRoutedToStaticEndpoint( string[] expectedEndpointNames) { _routingConfiguration.Add( - new StaticOutboundRouter(new TestProducerEndpoint("allMessages"))); + _ => new StaticOutboundRouter(new TestProducerEndpoint("allMessages"))); _routingConfiguration.Add( - new StaticOutboundRouter(new TestProducerEndpoint("allEvents"))); - _routingConfiguration.Add(new StaticOutboundRouter(new TestProducerEndpoint("eventOne"))); - _routingConfiguration.Add(new StaticOutboundRouter(new TestProducerEndpoint("eventTwo"))); + _ => new StaticOutboundRouter(new TestProducerEndpoint("allEvents"))); + _routingConfiguration.Add(_ => new StaticOutboundRouter(new TestProducerEndpoint("eventOne"))); + _routingConfiguration.Add(_ => new StaticOutboundRouter(new TestProducerEndpoint("eventTwo"))); await _behavior.Handle(new[] { message }, Task.FromResult); await _outboundQueue.Commit(); @@ -82,7 +84,7 @@ public async Task Handle_MultipleMessages_CorrectlyRoutedToStaticEndpoint( } var notExpectedEndpointNames = _routingConfiguration - .Routes.Select(r => r.Router.Endpoints.First().Name) + .Routes.Select(r => r.GetOutboundRouter(_serviceProvider).Endpoints.First().Name) .Where(r => !expectedEndpointNames.Contains(r)); foreach (var notExpectedEndpointName in notExpectedEndpointNames) @@ -101,7 +103,7 @@ public async Task Handle_MultipleMessages_CorrectlyRoutedToStaticEndpoint( [Fact] public async Task Handle_Message_CorrectlyRoutedToDefaultConnector() { - _routingConfiguration.Add(new StaticOutboundRouter(new TestProducerEndpoint("eventOne"))); + _routingConfiguration.Add(_ => new StaticOutboundRouter(new TestProducerEndpoint("eventOne"))); await _behavior.Handle(new[] { new TestEventOne() }, Task.FromResult); await _outboundQueue.Commit(); @@ -114,7 +116,7 @@ public async Task Handle_Message_CorrectlyRoutedToDefaultConnector() [Fact] public async Task Handle_Message_CorrectlyRoutedToConnector() { - _routingConfiguration.Add(new StaticOutboundRouter(new TestProducerEndpoint("eventOne")), + _routingConfiguration.Add(_ => new StaticOutboundRouter(new TestProducerEndpoint("eventOne")), typeof(OutboundConnector)); await _behavior.Handle(new[] { new TestEventOne() }, Task.FromResult); @@ -128,7 +130,7 @@ public async Task Handle_Message_CorrectlyRoutedToConnector() [Fact] public async Task Handle_Messages_RoutedMessageIsFiltered() { - _routingConfiguration.Add(new StaticOutboundRouter(new TestProducerEndpoint("eventOne")), + _routingConfiguration.Add(_ => new StaticOutboundRouter(new TestProducerEndpoint("eventOne")), typeof(OutboundConnector)); var messages = @@ -141,7 +143,7 @@ public async Task Handle_Messages_RoutedMessageIsFiltered() [Fact] public async Task Handle_Messages_RoutedMessageIsRepublishedWithoutAutoUnwrap() { - _routingConfiguration.Add(new StaticOutboundRouter(new TestProducerEndpoint("eventOne")), + _routingConfiguration.Add(_ => new StaticOutboundRouter(new TestProducerEndpoint("eventOne")), typeof(OutboundConnector)); await _behavior.Handle(new object[] { new TestEventOne(), new TestEventTwo() }, Task.FromResult); @@ -153,7 +155,7 @@ public async Task Handle_Messages_RoutedMessageIsRepublishedWithoutAutoUnwrap() public async Task Handle_MessagesWithPublishToInternBusOption_RoutedMessageIsFiltered() { _routingConfiguration.PublishOutboundMessagesToInternalBus = true; - _routingConfiguration.Add(new StaticOutboundRouter(new TestProducerEndpoint("eventOne")), + _routingConfiguration.Add(_ => new StaticOutboundRouter(new TestProducerEndpoint("eventOne")), typeof(OutboundConnector)); var messages = @@ -167,7 +169,7 @@ public async Task Handle_MessagesWithPublishToInternBusOption_RoutedMessageIsFil public async Task Handle_MessagesWithPublishToInternBusOption_RoutedMessageIsRepublishedWithAutoUnwrap() { _routingConfiguration.PublishOutboundMessagesToInternalBus = true; - _routingConfiguration.Add(new StaticOutboundRouter(new TestProducerEndpoint("eventOne")), + _routingConfiguration.Add(_ => new StaticOutboundRouter(new TestProducerEndpoint("eventOne")), typeof(OutboundConnector)); await _behavior.Handle(new object[] { new TestEventOne(), new TestEventTwo() }, Task.FromResult); @@ -180,7 +182,7 @@ public async Task Handle_MessagesWithPublishToInternBusOption_RoutedMessageIsRep public async Task Handle_OutboundEnvelopeWithPublishToInternBusOption_OutboundEnvelopeIsNotFiltered() { _routingConfiguration.PublishOutboundMessagesToInternalBus = true; - _routingConfiguration.Add(new StaticOutboundRouter(new TestProducerEndpoint("eventOne")), + _routingConfiguration.Add(_ => new StaticOutboundRouter(new TestProducerEndpoint("eventOne")), typeof(OutboundConnector)); var messages = @@ -202,7 +204,7 @@ public async Task Handle_UnhandledMessageType_CorrectlyRelayed() { var message = new SomeUnhandledMessage { Content = "abc" }; _routingConfiguration.Add( - new StaticOutboundRouter(new TestProducerEndpoint("eventOne")), + _ => new StaticOutboundRouter(new TestProducerEndpoint("eventOne")), typeof(OutboundConnector)); await _behavior.Handle(new[] { message }, Task.FromResult); @@ -214,9 +216,9 @@ public async Task Handle_UnhandledMessageType_CorrectlyRelayed() public async Task Handle_MultipleRoutesToMultipleBrokers_CorrectlyQueued() { _routingConfiguration - .Add(new StaticOutboundRouter(new TestProducerEndpoint("eventOne"))) - .Add(new StaticOutboundRouter(new TestOtherProducerEndpoint("eventTwo"))) - .Add(new StaticOutboundRouter(new TestProducerEndpoint("eventThree"))); + .Add(_ => new StaticOutboundRouter(new TestProducerEndpoint("eventOne"))) + .Add(_ => new StaticOutboundRouter(new TestOtherProducerEndpoint("eventTwo"))) + .Add(_ => new StaticOutboundRouter(new TestProducerEndpoint("eventThree"))); await _behavior.Handle(new[] { new TestEventOne() }, Task.FromResult); await _behavior.Handle(new[] { new TestEventThree(), }, Task.FromResult); @@ -234,11 +236,11 @@ public async Task Handle_MultipleRoutesToMultipleBrokers_CorrectlyQueued() public async Task Handle_MultipleRoutesToMultipleBrokers_CorrectlyRelayed() { _routingConfiguration - .Add(new StaticOutboundRouter(new TestProducerEndpoint("eventOne")), + .Add(_ => new StaticOutboundRouter(new TestProducerEndpoint("eventOne")), typeof(OutboundConnector)) - .Add(new StaticOutboundRouter(new TestOtherProducerEndpoint("eventTwo")), + .Add(_ => new StaticOutboundRouter(new TestOtherProducerEndpoint("eventTwo")), typeof(OutboundConnector)) - .Add(new StaticOutboundRouter(new TestProducerEndpoint("eventThree")), + .Add(_ => new StaticOutboundRouter(new TestProducerEndpoint("eventThree")), typeof(OutboundConnector)); await _behavior.Handle(new[] { new TestEventOne() }, Task.FromResult); diff --git a/tests/Silverback.Integration.Tests/Messaging/Connectors/OutboundQueueWorkerTests.cs b/tests/Silverback.Integration.Tests/Messaging/Connectors/OutboundQueueWorkerTests.cs index 1911f9db3..a09144cf2 100644 --- a/tests/Silverback.Integration.Tests/Messaging/Connectors/OutboundQueueWorkerTests.cs +++ b/tests/Silverback.Integration.Tests/Messaging/Connectors/OutboundQueueWorkerTests.cs @@ -46,7 +46,7 @@ public OutboundQueueWorkerTests() var serviceProvider = services.BuildServiceProvider(new ServiceProviderOptions { ValidateScopes = true }); serviceProvider.GetRequiredService() - .Add(new StaticOutboundRouter(TestProducerEndpoint.GetDefault())); + .Add(_ => new StaticOutboundRouter(TestProducerEndpoint.GetDefault())); _broker = (TestBroker) serviceProvider.GetRequiredService(); _broker.Connect(); diff --git a/tests/Silverback.Integration.Tests/Messaging/HealthChecks/OutboundEndpointsHealthCheckServiceTests.cs b/tests/Silverback.Integration.Tests/Messaging/HealthChecks/OutboundEndpointsHealthCheckServiceTests.cs index c529fea98..615ba661b 100644 --- a/tests/Silverback.Integration.Tests/Messaging/HealthChecks/OutboundEndpointsHealthCheckServiceTests.cs +++ b/tests/Silverback.Integration.Tests/Messaging/HealthChecks/OutboundEndpointsHealthCheckServiceTests.cs @@ -1,6 +1,7 @@ // Copyright (c) 2020 Sergio Aquilini // This code is licensed under MIT license (see LICENSE file for details) +using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; @@ -37,20 +38,20 @@ public async Task PingAllEndpoints_AllEndpointsWorking_EachEndpointIsPinged() { new OutboundRoute( typeof(TestEventOne), - new StaticOutboundRouter(new TestProducerEndpoint("endpoint1")), + _ => new StaticOutboundRouter(new TestProducerEndpoint("endpoint1")), typeof(OutboundConnector)), new OutboundRoute( typeof(TestEventTwo), - new StaticOutboundRouter(new TestProducerEndpoint("endpoint2")), + _ => new StaticOutboundRouter(new TestProducerEndpoint("endpoint2")), typeof(OutboundConnector)), new OutboundRoute( typeof(TestEventThree), - new StaticOutboundRouter(new TestProducerEndpoint("endpoint3")), + _ => new StaticOutboundRouter(new TestProducerEndpoint("endpoint3")), typeof(OutboundConnector)) }); var service = new OutboundEndpointsHealthCheckService(configuration, - new BrokerCollection(new[] { broker })); + new BrokerCollection(new[] { broker }), Substitute.For()); await service.PingAllEndpoints(); @@ -77,20 +78,20 @@ public async Task PingAllEndpoints_AllEndpointsWorking_ResultsAreAllSuccess() { new OutboundRoute( typeof(TestEventOne), - new StaticOutboundRouter(new TestProducerEndpoint("endpoint1")), + _ => new StaticOutboundRouter(new TestProducerEndpoint("endpoint1")), typeof(OutboundConnector)), new OutboundRoute( typeof(TestEventTwo), - new StaticOutboundRouter(new TestProducerEndpoint("endpoint2")), + _ => new StaticOutboundRouter(new TestProducerEndpoint("endpoint2")), typeof(OutboundConnector)), new OutboundRoute( typeof(TestEventThree), - new StaticOutboundRouter(new TestProducerEndpoint("endpoint3")), + _ => new StaticOutboundRouter(new TestProducerEndpoint("endpoint3")), typeof(OutboundConnector)) }); var service = new OutboundEndpointsHealthCheckService(configuration, - new BrokerCollection(new[] { broker })); + new BrokerCollection(new[] { broker }), Substitute.For()); var results = await service.PingAllEndpoints(); @@ -116,20 +117,20 @@ public async Task PingAllEndpoints_SomeEndpointNotWorking_FailureIsProperlyRepor { new OutboundRoute( typeof(TestEventOne), - new StaticOutboundRouter(new TestProducerEndpoint("endpoint1")), + _ => new StaticOutboundRouter(new TestProducerEndpoint("endpoint1")), typeof(OutboundConnector)), new OutboundRoute( typeof(TestEventTwo), - new StaticOutboundRouter(new TestProducerEndpoint("endpoint2")), + _ => new StaticOutboundRouter(new TestProducerEndpoint("endpoint2")), typeof(OutboundConnector)), new OutboundRoute( typeof(TestEventThree), - new StaticOutboundRouter(new TestProducerEndpoint("endpoint3")), + _ => new StaticOutboundRouter(new TestProducerEndpoint("endpoint3")), typeof(OutboundConnector)) }); var service = new OutboundEndpointsHealthCheckService(configuration, - new BrokerCollection(new[] { broker })); + new BrokerCollection(new[] { broker }), Substitute.For()); var results = (await service.PingAllEndpoints()).ToList();