public CommandDispatcher(IBusSubscription busSubscription) { channel = busSubscription.CreateChannel(); replyQueueName = channel.QueueDeclare().QueueName; consumer = new EventingBasicConsumer(channel); consumer.Received += (model, ea) => { var body = ea.Body; var response = Encoding.UTF8.GetString(body); TaskCompletionSource <object> tcs; if (respsMap.TryRemove(Guid.Parse(ea.BasicProperties.CorrelationId), out tcs)) { if (response == "") { tcs.SetResult(null); log.Debug($"Got the success response correlationId: {ea.BasicProperties.CorrelationId}"); } else { var error = JsonConvert.DeserializeObject <CommandFailed>(response); log.Debug($"Got the failure response correlationId: {ea.BasicProperties.CorrelationId}, message: {error.Message}"); tcs.SetException(new CommandHandlingException(error.Message)); } } else { log.Warn($"Didn't manage to find correlationId: {ea.BasicProperties.CorrelationId} in the map"); } }; }
public static void Main(string[] args) { var builder = new ContainerBuilder(); string[] scannerPattern = { @".*BoundedContext\.dll", @"Infrastructure.RabbitMQ\.dll" }; var assemblies = new List <Assembly>(); assemblies.AddRange(Directory .EnumerateFiles(Directory.GetCurrentDirectory(), "*.dll", SearchOption.AllDirectories) .Where(filename => scannerPattern.Any( pattern => Regex.IsMatch(filename, pattern, RegexOptions.IgnoreCase))).Select(Assembly.LoadFrom)); builder.RegisterType <BusSubscription>().As <IBusSubscription>().InstancePerLifetimeScope(); builder.RegisterAssemblyTypes(assemblies.ToArray()).AsImplementedInterfaces(); var container = builder.Build(); using (var lts = container.BeginLifetimeScope()) { IEnumerable commandHandlers = lts.Resolve <IEnumerable <IHandleCommand> >(); IEnumerable eventDeclarations = lts.Resolve <IEnumerable <IDeclareEvent> >(); IEnumerable eventHandlers = lts.Resolve <IEnumerable <IHandleEvent> >(); using (IBusSubscription sub = lts.Resolve <IBusSubscription>()) using (RegisterCommandHandlers(sub, commandHandlers)) using (RegisterEvents(sub.CreateChannel(), eventDeclarations)) using (RegisterEventHandlers(sub, eventHandlers)) { log.Info("All services up"); Console.ReadLine(); } } }
private static IDisposable RegisterCommandHandler(object cHandler, Type impl, IBusSubscription subscription) { var channel = subscription.CreateChannel(); var handlerCmdType = impl.GetGenericArguments()[0]; var consumer = ConfigureCommandQueue(channel, handlerCmdType.FullName); log.Debug($"Awaiting {handlerCmdType.FullName} requests"); var handlerMethod = GetHandlerMethod(cHandler, handlerCmdType, "HandleAsync"); consumer.Received += async(model, ea) => { var body = ea.Body; var props = ea.BasicProperties; var replyProps = channel.CreateBasicProperties(); replyProps.CorrelationId = props.CorrelationId; log.Trace($"Got command with correlationid={props.CorrelationId}"); string responseSerialized = ""; try { var message = Encoding.UTF8.GetString(body); log.Debug($"Got command {message} of type {handlerCmdType.FullName}, correlationId: {props.CorrelationId}"); var cmd = JsonConvert.DeserializeObject(message, handlerCmdType); await(Task) handlerMethod.Invoke(cHandler, new[] { cmd }); log.Debug($"Successfully processed command: {message}, correlationId: {props.CorrelationId}"); } catch (Exception e) { log.Error(e, $"Error occurred in processing of command with correlationId: {props.CorrelationId}"); responseSerialized = JsonConvert.SerializeObject(new CommandFailed { Code = "", Message = e.Message }); } finally { channel.BasicPublish(exchange: "", routingKey: props.ReplyTo, basicProperties: replyProps, body: Encoding.UTF8.GetBytes(responseSerialized)); channel.BasicAck(deliveryTag: ea.DeliveryTag, multiple: false); } }; return(channel); }
public void Dispatch(object e) { if (e == null) { throw new ArgumentNullException(nameof(e)); } using (var channel = _busSubscription.CreateChannel()) { var properties = channel.CreateBasicProperties(); properties.Persistent = true; properties.Headers = new Dictionary <string, object> { { "event-type", e.GetType().AssemblyQualifiedName } }; var message = JsonConvert.SerializeObject(e); var body = Encoding.UTF8.GetBytes(message); channel.BasicPublish(exchange: e.GetType().FullName, routingKey: "", basicProperties: properties, body: body, mandatory: true); log.Debug($"Sent event of type {e.GetType().FullName}: {message}"); } }
private static IDisposable RegisterEventHandlers(IBusSubscription sub, IEnumerable eventHandlers) { var lst = new List <IDisposable>(); foreach (var eHandler in eventHandlers) { var interfaces = eHandler.GetType().GetInterfaces() .Where(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(IHandleEvent <>)) .ToArray(); var channel = sub.CreateChannel(); var queueName = eHandler.GetType().FullName; foreach (var impl in interfaces) { RegisterEventHandler(queueName, impl.GetGenericArguments()[0], channel); } var consumer = new EventingBasicConsumer(channel); consumer.Received += async(model, ea) => { var body = ea.Body; try { var props = ea.BasicProperties; var eventTypeNameBytes = props.Headers["event-type"]; var eventType = Type.GetType(Encoding.UTF8.GetString((Byte[])eventTypeNameBytes), true); var message = Encoding.UTF8.GetString(body); var cmd = JsonConvert.DeserializeObject(message, eventType); var handlerMethod = GetHandlerMethod(eHandler, eventType, "HandleAsync"); try { log.Debug($"Got event of type {eventType.FullName}: {message}"); await(Task) handlerMethod.Invoke(eHandler, new[] { cmd }); log.Debug($"Successfully processed event {eventType.FullName}: {message}"); } catch (Exception ex) { log.Error(ex, $"Error occurred in processing of event { eventType.FullName }: {message}"); //TODO: event is to be placed into dead letters table } } catch (Exception e) { log.Fatal(e, $"Error occurred wile preparing obtained event to handling. {body}"); //TODO: event is to be placed into dead letters table } finally { channel.BasicAck(deliveryTag: ea.DeliveryTag, multiple: false); } }; channel.BasicConsume(queue: queueName, autoAck: false, consumer: consumer); lst.Add(channel); } return(new ListOfDisposables(lst.ToArray())); }