Last active
October 15, 2019 13:23
-
-
Save joacar/273d84da5219bf57c8d47d1a59cff68f to your computer and use it in GitHub Desktop.
NServiceBus shared service provider attempt
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
namespace Nordax.NServiceBus { | |
/// <summary> | |
/// Behavior that wraps invocation of pipeline with a scoped service provider. | |
/// </summary> | |
internal sealed class ScopedServiceBehavior : Behavior<IIncomingPhysicalMessageContext> | |
{ | |
/// <summary> | |
/// Registered behavior with name. | |
/// </summary> | |
public const string StepId = "ScopedService"; | |
private readonly IServiceScopeFactory _serviceScopeFactory; | |
public ScopedServiceBehavior(IServiceScopeFactory serviceScopeFactory) | |
{ | |
_serviceScopeFactory = serviceScopeFactory; | |
} | |
public override async Task Invoke(IIncomingPhysicalMessageContext context, Func<Task> next) | |
{ | |
using (var scope = _serviceScopeFactory.CreateScope()) | |
{ | |
// Previously implementation injected in handler constructor is now available via | |
// context.GetService(typeof(T)); | |
// All resolved services of T (if registered using AddScoped()) in the pipeline | |
// will yield same instance causing it to be shared amongst handlers and behaviors. | |
context.Extensions.Set(scope); | |
await next().ConfigureAwait(false); | |
} | |
} | |
} | |
internal sealed class EventDispatcherBehavior : Behavior<IInvokeHandlerContext> | |
{ | |
private readonly IEventDispatcherFactory _dispatcherFactory; | |
private readonly ILogger<EventDispatcherBehavior> _logger; | |
private readonly EventDispatcherSettings _settings; | |
public EventDispatcherBehavior( | |
ILoggerFactory loggerFactory, | |
EventDispatcherSettings settings) | |
{ | |
_settings = settings ?? throw new ArgumentNullException(nameof(settings)); | |
_dispatcherFactory = settings.DispatcherFactory ?? throw new ArgumentNullException(nameof(settings.DispatcherFactory)); | |
_logger = loggerFactory.CreateLogger<EventDispatcherBehavior>(); | |
} | |
public override async Task Invoke(IInvokeHandlerContext context, Func<Task> next) | |
{ | |
// Execute this outside of try-catch so errors are propagated in default way | |
await next().ConfigureAwait(false); | |
try | |
{ | |
// Check if available in scoped service | |
var eventProvider = context.GetService<IEventProvider>(); | |
if(eventProvider != null && eventProvider.HasEvents) | |
{ | |
// We have the events! | |
var events = eventProvider.GetEvents(); | |
var dispatcher = _dispatcherFactory.CreateFromHandlerContext(context); | |
foreach (var @event in events) | |
{ | |
if (@event is null) | |
{ | |
continue; | |
} | |
// Default implementation just wraps context as sender | |
await dispatcher.Dispatch(@event).ConfigureAwait(false); | |
} | |
} | |
} | |
catch (Exception e) | |
{ | |
// Error handling | |
} | |
} | |
} | |
internal sealed class Handler : IHandleMessages<Command> | |
{ | |
private readonly ILogger<Handler> _logger; | |
private readonly CommandUseCase _useCase; | |
public Handler( | |
ILoggerFactory loggerFactory, | |
CommandUseCase commandUseCase) | |
{ | |
_logger = loggerFactory.CreateLogger<Handler>(); | |
_useCase = commandUseCase; | |
} | |
public async Task Handle(Command message, IMessageHandlerContext context) | |
{ | |
// Resolved from ASPNET DI | |
var useCase = context.GetService<CommandUseCase>(); | |
// _useCase is resolved NSB DI | |
Debug.Assert(ReferenceEquals(useCase, _useCase), ""); | |
await useCase.Execute().ConfigureAwait(false); | |
} | |
} | |
public sealed class CommandUseCase | |
{ | |
private readonly IEventCollectionPublisher _eventCollectionPublisher; | |
public CommandUseCase(IEventCollectionPublisher eventCollectionPublisher) | |
{ | |
_eventCollectionPublisher = eventCollectionPublisher; | |
} | |
public Task Execute() | |
{ | |
// Do domain stuff | |
var customer = new Customer(); | |
// Publish domain events | |
_eventCollectionPublisher.Publish(customer.Events); | |
return Task.CompletedTask; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment