-
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
cec5dd3
commit 510fcb3
Showing
5 changed files
with
345 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
189 changes: 189 additions & 0 deletions
189
src/ReflectionEventing.DependencyInjection/EventBusBuilderExtensions.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,189 @@ | ||
// This Source Code Form is subject to the terms of the MIT License. | ||
// If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. | ||
// Copyright (C) Leszek Pomianowski and ReflectionEventing Contributors. | ||
// All Rights Reserved. | ||
|
||
namespace ReflectionEventing.DependencyInjection; | ||
|
||
public static class EventBusBuilderExtensions | ||
{ | ||
/// <summary> | ||
/// Adds a consumer to the event bus builder and <see cref="IServiceCollection"/>. | ||
/// </summary> | ||
/// <param name="builder">The event bus builder to add the consumer to.</param> | ||
/// <param name="consumerType">The type of the consumer to add.</param> | ||
/// <returns>The event bus builder with the consumer added.</returns> | ||
public static EventBusBuilder AddTransientConsumer( | ||
this EventBusBuilder builder, | ||
#if NET5_0_OR_GREATER | ||
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.Interfaces)] | ||
#endif | ||
Type consumerType | ||
) | ||
{ | ||
if (builder is not DependencyInjectionEventBusBuilder dependencyInjectionEventBusBuilder) | ||
{ | ||
throw new InvalidOperationException( | ||
"The event bus builder must be of type DependencyInjectionEventBusBuilder to add a transient consumer." | ||
); | ||
} | ||
|
||
return dependencyInjectionEventBusBuilder.AddConsumer( | ||
consumerType, | ||
ServiceLifetime.Transient | ||
); | ||
} | ||
|
||
/// <summary> | ||
/// Adds a consumer to the event bus builder and <see cref="IServiceCollection"/>. | ||
/// </summary> | ||
/// <typeparam name="TConsumer">The type of the consumer to add.</typeparam> | ||
/// <param name="builder">The event bus builder to add the consumer to.</param> | ||
/// <returns>The event bus builder with the consumer added.</returns> | ||
public static EventBusBuilder AddTransientConsumer< | ||
#if NET5_0_OR_GREATER | ||
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.Interfaces)] | ||
#endif | ||
TConsumer | ||
>(this EventBusBuilder builder) | ||
{ | ||
if (builder is not DependencyInjectionEventBusBuilder dependencyInjectionEventBusBuilder) | ||
{ | ||
throw new InvalidOperationException( | ||
"The event bus builder must be of type DependencyInjectionEventBusBuilder to add a transient consumer." | ||
); | ||
} | ||
|
||
return dependencyInjectionEventBusBuilder.AddConsumer( | ||
typeof(TConsumer), | ||
ServiceLifetime.Transient | ||
); | ||
} | ||
|
||
/// <summary> | ||
/// Adds a consumer to the event bus builder and <see cref="IServiceCollection"/>. | ||
/// </summary> | ||
/// <param name="builder">The event bus builder to add the consumer to.</param> | ||
/// <param name="consumerType">The type of the consumer to add.</param> | ||
/// <returns>The event bus builder with the consumer added.</returns> | ||
public static EventBusBuilder AddScopedConsumer( | ||
this EventBusBuilder builder, | ||
#if NET5_0_OR_GREATER | ||
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.Interfaces)] | ||
#endif | ||
Type consumerType | ||
) | ||
{ | ||
if (builder is not DependencyInjectionEventBusBuilder dependencyInjectionEventBusBuilder) | ||
{ | ||
throw new InvalidOperationException( | ||
"The event bus builder must be of type DependencyInjectionEventBusBuilder to add a scoped consumer." | ||
); | ||
} | ||
|
||
return dependencyInjectionEventBusBuilder.AddConsumer(consumerType, ServiceLifetime.Scoped); | ||
} | ||
|
||
/// <summary> | ||
/// Adds a consumer to the event bus builder and <see cref="IServiceCollection"/>. | ||
/// </summary> | ||
/// <typeparam name="TConsumer">The type of the consumer to add.</typeparam> | ||
/// <param name="builder">The event bus builder to add the consumer to.</param> | ||
/// <returns>The event bus builder with the consumer added.</returns> | ||
public static EventBusBuilder AddScopedConsumer< | ||
#if NET5_0_OR_GREATER | ||
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.Interfaces)] | ||
#endif | ||
TConsumer | ||
>(this EventBusBuilder builder) | ||
{ | ||
if (builder is not DependencyInjectionEventBusBuilder dependencyInjectionEventBusBuilder) | ||
{ | ||
throw new InvalidOperationException( | ||
"The event bus builder must be of type DependencyInjectionEventBusBuilder to add a scoped consumer." | ||
); | ||
} | ||
|
||
return dependencyInjectionEventBusBuilder.AddConsumer( | ||
typeof(TConsumer), | ||
ServiceLifetime.Scoped | ||
); | ||
} | ||
|
||
/// <summary> | ||
/// Adds a consumer to the event bus builder and <see cref="IServiceCollection"/>. | ||
/// </summary> | ||
/// <param name="builder">The event bus builder to add the consumer to.</param> | ||
/// <param name="consumerType">The type of the consumer to add.</param> | ||
/// <returns>The event bus builder with the consumer added.</returns> | ||
public static EventBusBuilder AddSingletonConsumer( | ||
this EventBusBuilder builder, | ||
#if NET5_0_OR_GREATER | ||
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.Interfaces)] | ||
#endif | ||
Type consumerType | ||
) | ||
{ | ||
if (builder is not DependencyInjectionEventBusBuilder dependencyInjectionEventBusBuilder) | ||
{ | ||
throw new InvalidOperationException( | ||
"The event bus builder must be of type DependencyInjectionEventBusBuilder to add a singleton consumer." | ||
); | ||
} | ||
|
||
return dependencyInjectionEventBusBuilder.AddConsumer( | ||
consumerType, | ||
ServiceLifetime.Singleton | ||
); | ||
} | ||
|
||
/// <summary> | ||
/// Adds a consumer to the event bus builder and <see cref="IServiceCollection"/>. | ||
/// </summary> | ||
/// <typeparam name="TConsumer">The type of the consumer to add.</typeparam> | ||
/// <param name="builder">The event bus builder to add the consumer to.</param> | ||
/// <returns>The event bus builder with the consumer added.</returns> | ||
public static EventBusBuilder AddSingletonConsumer< | ||
#if NET5_0_OR_GREATER | ||
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.Interfaces)] | ||
#endif | ||
TConsumer | ||
>(this EventBusBuilder builder) | ||
{ | ||
if (builder is not DependencyInjectionEventBusBuilder dependencyInjectionEventBusBuilder) | ||
{ | ||
throw new InvalidOperationException( | ||
"The event bus builder must be of type DependencyInjectionEventBusBuilder to add a singleton consumer." | ||
); | ||
} | ||
|
||
return dependencyInjectionEventBusBuilder.AddConsumer( | ||
typeof(TConsumer), | ||
ServiceLifetime.Singleton | ||
); | ||
} | ||
|
||
/// <summary> | ||
/// Adds a consumer to the event bus builder and <see cref="IServiceCollection"/>. | ||
/// </summary> | ||
/// <typeparam name="TConsumer">The type of the consumer to add.</typeparam> | ||
/// <param name="builder">The event bus builder to add the consumer to.</param> | ||
/// <param name="lifetime">The service lifetime of the consumer.</param> | ||
/// <returns>The event bus builder with the consumer added.</returns> | ||
public static EventBusBuilder AddConsumer< | ||
#if NET5_0_OR_GREATER | ||
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.Interfaces)] | ||
#endif | ||
TConsumer | ||
>(this EventBusBuilder builder, ServiceLifetime lifetime) | ||
{ | ||
if (builder is not DependencyInjectionEventBusBuilder dependencyInjectionEventBusBuilder) | ||
{ | ||
throw new InvalidOperationException( | ||
"The event bus builder must be of type DependencyInjectionEventBusBuilder to add a transient consumer." | ||
); | ||
} | ||
|
||
return dependencyInjectionEventBusBuilder.AddConsumer(typeof(TConsumer), lifetime); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
117 changes: 117 additions & 0 deletions
117
tests/ReflectionEventing.DependencyInjection.UnitTests/EventBusBuilderExtensionsTests.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
// This Source Code Form is subject to the terms of the MIT License. | ||
// If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. | ||
// Copyright (C) Leszek Pomianowski and ReflectionEventing Contributors. | ||
// All Rights Reserved. | ||
|
||
using Microsoft.Extensions.DependencyInjection; | ||
|
||
namespace ReflectionEventing.DependencyInjection.UnitTests; | ||
|
||
public sealed class EventBusBuilderExtensionsTests | ||
{ | ||
[Fact] | ||
public void AddConsumer_ShouldRegisterConsumerWhenLifetimeProvided() | ||
{ | ||
IServiceCollection services = new ServiceCollection(); | ||
DependencyInjectionEventBusBuilder eventBusBuilder = new(services); | ||
|
||
eventBusBuilder.AddConsumer<TestConsumer>(ServiceLifetime.Transient); | ||
|
||
IConsumerTypesProvider consumerTypesProvider = eventBusBuilder.BuildTypesProvider(); | ||
_ = consumerTypesProvider | ||
.GetConsumerTypes(typeof(TestEvent)) | ||
.Should() | ||
.Contain(typeof(TestConsumer)); | ||
|
||
services | ||
.First(d => d.ServiceType == typeof(TestConsumer)) | ||
.Lifetime.Should() | ||
.Be(ServiceLifetime.Transient); | ||
} | ||
|
||
[Fact] | ||
public void AddScopedConsumer_ShouldThrowExceptionWhenConsumerIsRegisteredWithDifferentScope() | ||
{ | ||
IServiceCollection services = new ServiceCollection(); | ||
_ = services.AddSingleton<TestConsumer>(); | ||
DependencyInjectionEventBusBuilder eventBusBuilder = new(services); | ||
|
||
Action act = () => eventBusBuilder.AddScopedConsumer(typeof(TestConsumer)); | ||
|
||
_ = act.Should() | ||
.Throw<InvalidOperationException>() | ||
.WithMessage( | ||
"Event consumer must be registered with the same lifetime as the one provided." | ||
); | ||
} | ||
|
||
[Fact] | ||
public void AddScopedConsumer_ShouldRegisterTransientConsumer() | ||
{ | ||
IServiceCollection services = new ServiceCollection(); | ||
DependencyInjectionEventBusBuilder eventBusBuilder = new(services); | ||
|
||
eventBusBuilder.AddTransientConsumer<TestConsumer>(); | ||
|
||
IConsumerTypesProvider consumerTypesProvider = eventBusBuilder.BuildTypesProvider(); | ||
_ = consumerTypesProvider | ||
.GetConsumerTypes(typeof(TestEvent)) | ||
.Should() | ||
.Contain(typeof(TestConsumer)); | ||
|
||
services | ||
.First(d => d.ServiceType == typeof(TestConsumer)) | ||
.Lifetime.Should() | ||
.Be(ServiceLifetime.Transient); | ||
} | ||
|
||
[Fact] | ||
public void AddScopedConsumer_ShouldRegisterScopedConsumer() | ||
{ | ||
IServiceCollection services = new ServiceCollection(); | ||
DependencyInjectionEventBusBuilder eventBusBuilder = new(services); | ||
|
||
eventBusBuilder.AddScopedConsumer<TestConsumer>(); | ||
|
||
IConsumerTypesProvider consumerTypesProvider = eventBusBuilder.BuildTypesProvider(); | ||
_ = consumerTypesProvider | ||
.GetConsumerTypes(typeof(TestEvent)) | ||
.Should() | ||
.Contain(typeof(TestConsumer)); | ||
|
||
services | ||
.First(d => d.ServiceType == typeof(TestConsumer)) | ||
.Lifetime.Should() | ||
.Be(ServiceLifetime.Scoped); | ||
} | ||
|
||
[Fact] | ||
public void AddScopedConsumer_ShouldRegisterSingletonConsumer() | ||
{ | ||
IServiceCollection services = new ServiceCollection(); | ||
DependencyInjectionEventBusBuilder eventBusBuilder = new(services); | ||
|
||
eventBusBuilder.AddSingletonConsumer<TestConsumer>(); | ||
|
||
IConsumerTypesProvider consumerTypesProvider = eventBusBuilder.BuildTypesProvider(); | ||
_ = consumerTypesProvider | ||
.GetConsumerTypes(typeof(TestEvent)) | ||
.Should() | ||
.Contain(typeof(TestConsumer)); | ||
|
||
services | ||
.First(d => d.ServiceType == typeof(TestConsumer)) | ||
.Lifetime.Should() | ||
.Be(ServiceLifetime.Singleton); | ||
} | ||
|
||
public interface ITestEvent; | ||
|
||
public record TestEvent : ITestEvent; | ||
|
||
public class TestConsumer : IConsumer<TestEvent> | ||
{ | ||
public Task ConsumeAsync(TestEvent payload, CancellationToken cancellationToken) => | ||
Task.CompletedTask; | ||
} | ||
} |