< Summary - AsyncResponse (Release / net8.0+net10.0 / unit+integration)

Information
Class: Microsoft.Extensions.DependencyInjection.NatsAsyncResponseChannelServiceCollectionExtensions
Assembly: AsyncResponse.Channels.NATS
File(s): /home/runner/work/AsyncResponse/AsyncResponse/src/Channels/AsyncResponse.Channels.NATS/ServiceCollectionExtensions.cs
Line coverage
100%
Covered lines: 26
Uncovered lines: 0
Coverable lines: 26
Total lines: 77
Line coverage: 100%
Branch coverage
100%
Covered branches: 24
Total branches: 24
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
WithNatsChannel(...)100%2424100%

File(s)

/home/runner/work/AsyncResponse/AsyncResponse/src/Channels/AsyncResponse.Channels.NATS/ServiceCollectionExtensions.cs

#LineLine coverage
 1using AsyncResponse;
 2using AsyncResponse.Channels.NATS;
 3using Microsoft.Extensions.DependencyInjection.Extensions;
 4using Microsoft.Extensions.Options;
 5using NATS.Client.Core;
 6using NATS.Net;
 7
 8namespace Microsoft.Extensions.DependencyInjection;
 9
 10/// <summary>
 11/// DI registration for the NATS-backed AsyncResponse channel package.
 12/// </summary>
 13public static class NatsAsyncResponseChannelServiceCollectionExtensions
 14{
 15    /// <summary>
 16    /// Registers NATS Core request/reply as the response channel — behind
 17    /// <see cref="IAsyncResponsePublisher"/>, <see cref="IAsyncResponseSubscriber"/>, and
 18    /// <see cref="IRecoverableAsyncResponseSubscriber"/> — together with the durable NATS JetStream
 19    /// Key-Value recovery-state store, so a response that arrives after the waiter died (e.g. a
 20    /// redeploy) can still resume or fail the owning flow. It also registers
 21    /// <see cref="IRecoverableAsyncResponseBuilder"/> for fluent durable recovery flows. The same
 22    /// channel instance serves the engine's recovery-state scanner and active-subscriber probe, so the
 23    /// watchdog works against NATS automatically.
 24    /// <para>
 25    /// Requires a <c>NATS.Client.Core.INatsConnection</c> singleton registered by the host — for
 26    /// example via <c>builder.Services.AddNatsClient(...)</c> from
 27    /// <c>NATS.Extensions.Microsoft.DependencyInjection</c>. Reuse the application's existing
 28    /// connection; don't create a second one. The recovery store requires JetStream to be enabled on
 29    /// the NATS server. Publisher/subscriber resolve to one shared instance: per-interface instances
 30    /// would split the channel's internal state.
 31    /// </para>
 32    /// </summary>
 33    public static AsyncResponseRegistrationBuilder WithNatsChannel(
 34        this AsyncResponseRegistrationBuilder builder,
 35        Action<NatsAsyncResponseChannelOptions>? configure = null)
 36    {
 337        var services = builder.Services;
 338        services.AddOptions();
 339        if (configure is not null)
 340            services.Configure(configure);
 41
 42        // NATS JetStream Key-Value client adapter (lazily creates the recovery bucket on first use).
 343        services.TryAddSingleton<INatsKvStore>(provider => new NatsKvStoreAdapter(
 344            provider.GetRequiredService<INatsConnection>().CreateKeyValueStoreContext(),
 345            provider.GetRequiredService<IOptions<NatsAsyncResponseChannelOptions>>().Value));
 46
 47        // Durable recovery store; also the watchdog's recovery-state scanner.
 348        services.TryAddSingleton<NatsRecoveryStateStore>();
 349        services.Replace(ServiceDescriptor.Singleton<IRecoveryStateStore>(provider => provider.GetRequiredService<NatsRe
 350        services.Replace(ServiceDescriptor.Singleton<IRecoveryStateScanner>(provider => provider.GetRequiredService<Nats
 51
 52        // NATS Core request/reply client adapter (raw extension calls isolated in NatsRawRequester).
 353        services.TryAddSingleton<INatsResponseChannelClient>(provider => new NatsResponseChannelClient(
 354            new NatsRawRequester(provider.GetRequiredService<INatsConnection>())));
 55
 56        // NATS response channel: publisher + subscriber + the watchdog's liveness probe, all one shared instance.
 357        services.TryAddSingleton<NatsAsyncResponseChannel>();
 358        services.Replace(ServiceDescriptor.Singleton<IAsyncResponsePublisher>(provider => provider.GetRequiredService<Na
 359        services.Replace(ServiceDescriptor.Singleton<IRawAsyncResponsePublisher>(provider => provider.GetRequiredService
 360        services.Replace(ServiceDescriptor.Singleton<IAsyncResponseSubscriber>(provider => provider.GetRequiredService<N
 361        services.Replace(ServiceDescriptor.Singleton<IRecoverableAsyncResponseSubscriber>(provider => provider.GetRequir
 362        services.Replace(ServiceDescriptor.Singleton<IActiveSubscriberProbe>(provider => provider.GetRequiredService<Nat
 63
 64        // Durable recovery capability: expose the recoverable fluent builder only when the NATS channel
 65        // package is the selected response channel. Plain IAsyncResponseBuilder still works and shares
 66        // the same implementation, but its static type does not offer recovery callbacks.
 367        services.Replace(ServiceDescriptor.Singleton<IRecoverableAsyncResponseBuilder>(provider => new RecoverableAsyncR
 368            provider.GetRequiredService<IRecoverableAsyncResponseSubscriber>(),
 369            provider.GetService<IWorkerTransport>(),
 370            provider.GetService<IAsyncResponseReplyTargetProvider>(),
 371            provider.GetRequiredService<AsyncResponseContextPropagation>())));
 372        services.Replace(ServiceDescriptor.Singleton<IAsyncResponseBuilder>(provider => provider.GetRequiredService<IRec
 73
 374        services.AddSingleton(new AsyncResponseChannelMarker(NatsAsyncResponseChannelOptions.ChannelName));
 375        return builder;
 76    }
 77}