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");
                }
            };
        }
예제 #2
0
        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();
                            }
            }
        }
예제 #3
0
        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);
        }
예제 #4
0
        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}");
            }
        }
예제 #5
0
        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()));
        }