-
Notifications
You must be signed in to change notification settings - Fork 8
Expand file tree
/
Copy pathCoreExEventsExtensions.DependencyInjection.cs
More file actions
86 lines (78 loc) · 5.73 KB
/
Copy pathCoreExEventsExtensions.DependencyInjection.cs
File metadata and controls
86 lines (78 loc) · 5.73 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#pragma warning disable IDE0130 // Namespace does not match folder structure - this is by design.
namespace Microsoft.Extensions.DependencyInjection;
#pragma warning restore IDE0130 // Namespace does not match folder structure
/// <summary>
/// Provides <see cref="CoreEx.Events"/> and related extensions.
/// </summary>
public static class CoreExEventsExtensions
{
/// <summary>
/// Adds a <b>singleton</b> service for the <see cref="EventFormatter"/> as the <see cref="IEventFormatter"/>.
/// </summary>
/// <param name="services">The <see cref="IServiceCollection"/>.</param>
/// <param name="configure">The action to configure the <see cref="EventFormatter"/> instance.</param>
/// <returns>The <see cref="IServiceCollection"/> for fluent-style method-chaining.</returns>
public static IServiceCollection AddEventFormatter(this IServiceCollection services, Action<EventFormatter>? configure = null)
{
return services.AddSingleton<IEventFormatter>(sp =>
{
var ef = ActivatorUtilities.CreateInstance<EventFormatter>(sp);
configure?.Invoke(ef);
return ef;
});
}
/// <summary>
/// Adds a <b>singleton</b> service for the <see cref="FixedDestinationProvider"/> as the <see cref="IDestinationProvider"/>
/// </summary>
/// <param name="services">The <see cref="IServiceCollection"/>.</param>
/// <param name="destination">The fixed destination name.</param>
/// <returns>The <see cref="IServiceCollection"/> for fluent-style method-chaining.</returns>
public static IServiceCollection AddFixedDestinationProvider(this IServiceCollection services, string destination)
=> services.ThrowIfNull().AddSingleton<IDestinationProvider>(new FixedDestinationProvider { Destination = destination.ThrowIfNullOrEmpty() });
/// <summary>
/// Adds a <b>singleton</b> <see cref="SubscribedManager"/> service.
/// </summary>
/// <param name="services">The <see cref="IServiceCollection"/>.</param>
/// <param name="configure">The action to configure the <see cref="SubscribedManager"/> instance.</param>
/// <returns>The <see cref="IServiceCollection"/> for fluent-style method-chaining.</returns>
public static IServiceCollection AddSubscribedManager(this IServiceCollection services, Action<IServiceProvider, SubscribedManager>? configure = null)
{
return services.AddSingleton<SubscribedManager>(sp =>
{
var manager = new SubscribedManager(sp.GetService<SubscribedInvoker>());
configure?.Invoke(sp, manager);
return manager;
});
}
/// <summary>
/// Adds a keyed <b>scoped</b> <see cref="IEventPublisher"/> service.
/// </summary>
/// <param name="services">The <see cref="IServiceCollection"/>.</param>
/// <param name="serviceKey">The service key to use for the keyed registration.</param>
/// <param name="serviceFactory">The factory function to create the <see cref="IEventPublisher"/> instance.</param>
/// <param name="addAsDefaultIEventPublisher">Indicates whether to also register as the default (non-keyed) <see cref="IEventPublisher"/> service.</param>
/// <returns>The <see cref="IServiceCollection"/> for fluent-style method-chaining.</returns>
/// <remarks>This method firstly registers the service with a root key (derived from the provided service key) and then registers the provided service key to resolve to the root service.
/// This ensures that the root service is always registered, even if the non-root is re-registered the root can be resolved - useful for testing scenarios where the service is re-registered with a test double (the root remains and is accessible).
/// <para>Where <paramref name="addAsDefaultIEventPublisher"/> is <see langword="true"/>, it also registers the provided service key as the default (primary / non-keyed) <see cref="IEventPublisher"/> service, allowing it to be resolved
/// without specifying a key simplifying usage in most scenarios. Note that only a single default <see cref="IEventPublisher"/> can be registered at a time.</para></remarks>
public static IServiceCollection AddEventPublisher(this IServiceCollection services, string serviceKey, Func<IServiceProvider, IEventPublisher> serviceFactory, bool addAsDefaultIEventPublisher = true)
{
serviceFactory.ThrowIfNull();
var rootKey = $"{serviceKey.ThrowIfNullOrEmpty()}_Root";
services.ThrowIfNull().AddKeyedScoped<IEventPublisher>(rootKey, (sp, _) => serviceFactory(sp) ?? throw new InvalidOperationException("The service factory must not return null."))
.AddKeyedScoped<IEventPublisher>(serviceKey, (sp, _) => sp.GetRequiredKeyedService<IEventPublisher>(rootKey));
if (addAsDefaultIEventPublisher)
services.AddScoped<IEventPublisher>(sp => sp.GetRequiredKeyedService<IEventPublisher>(serviceKey));
return services;
}
/// <summary>
/// Adds a keyed <b>scoped</b> <see cref="NoOpEventPublisher"/> service for the specified service key.
/// </summary>
/// <param name="services">The <see cref="IServiceCollection"/>.</param>
/// <param name="serviceKey">The service key to use for the keyed registration.</param>
/// <param name="addAsDefaultIEventPublisher">Indicates whether to also register as the default (non-keyed) <see cref="IEventPublisher"/> service.</param>
/// <returns>The <see cref="IServiceCollection"/> for fluent-style method-chaining.</returns>
public static IServiceCollection AddNoOpEventPublisher(this IServiceCollection services, string serviceKey, bool addAsDefaultIEventPublisher = true)
=> AddEventPublisher(services, serviceKey, sp => ActivatorUtilities.CreateInstance<NoOpEventPublisher>(sp), addAsDefaultIEventPublisher);
}