예제 #1
0
        private async Task SendAsync(ICommand command, bool requireAcknowledgement)
        {
            try
            {
                var stopwatch = new Stopwatch();
                stopwatch.Start();

                if (connection.IsOpen == false)
                {
                    lock (this)
                    {
                        if (connection.IsOpen == false)
                        {
                            var factory = new ConnectionFactory()
                            {
                                HostName = host
                            };
                            this.connection = factory.CreateConnection();
                            _ = Log.TraceAsync($"Sender Reconnected: {host}");
                        }
                    }
                }

                var channel = connection.CreateModel();

                string[][] claims = null;
                if (Thread.CurrentPrincipal is ClaimsPrincipal principal)
                {
                    claims = principal.Claims.Select(x => new string[] { x.Type, x.Value }).ToArray();
                }

                var rabbitMessage = new RabbitMQCommandMessage()
                {
                    Message = command,
                    Claims  = claims
                };

                var body = RabbitMQCommon.Serialize(rabbitMessage);
                if (encryptionKey != null)
                {
                    body = SymmetricEncryptor.Encrypt(encryptionAlgorithm, encryptionKey, body);
                }

                var exchange = command.GetType().GetNiceName();

                var properties = channel.CreateBasicProperties();

                EventingBasicConsumer consumer = null;
                string consumerTag             = null;
                string correlationId           = null;
                if (requireAcknowledgement)
                {
                    string replyQueueName = channel.QueueDeclare().QueueName;
                    consumer    = new EventingBasicConsumer(channel);
                    consumerTag = channel.BasicConsume(replyQueueName, false, consumer);

                    correlationId            = Guid.NewGuid().ToString();
                    properties.ReplyTo       = replyQueueName;
                    properties.CorrelationId = correlationId;
                }

                if (encryptionKey != null)
                {
                    var messageHeaders = new Dictionary <string, object>();
                    messageHeaders.Add("Encryption", true);
                    properties.Headers = messageHeaders;
                }

                channel.BasicPublish(exchange, String.Empty, properties, body);

                _ = Log.TraceAsync($"Sent{(requireAcknowledgement ? " Await" : null)}: {exchange}");

                if (requireAcknowledgement)
                {
                    Exception exception = null;
                    var       syncEvent = new SemaphoreSlim(0, 1);

                    consumer.Received += (sender, e) =>
                    {
                        try
                        {
                            if (e.BasicProperties.CorrelationId != correlationId)
                            {
                                throw new Exception("ACK response CorrelationIds should be single and unique");
                            }

                            channel.BasicCancel(consumerTag);

                            byte[] acknowledgementBody = e.Body;
                            if (encryptionKey != null)
                            {
                                acknowledgementBody = SymmetricEncryptor.Decrypt(encryptionAlgorithm, encryptionKey, acknowledgementBody);
                            }

                            var affirmation = RabbitMQCommon.Deserialize <Acknowledgement>(acknowledgementBody);

                            stopwatch.Stop();

                            if (!affirmation.Success)
                            {
                                _ = Log.TraceAsync($"Await Failed: {exchange}: {affirmation.ErrorMessage} {stopwatch.ElapsedMilliseconds}");
                            }
                            else
                            {
                                _ = Log.TraceAsync($"Await Success: {exchange} {stopwatch.ElapsedMilliseconds}");
                            }

                            if (!affirmation.Success)
                            {
                                exception = new AcknowledgementException(affirmation, exchange);
                            }
                        }
                        catch (Exception ex)
                        {
                            exception = ex;
                        }
                        finally
                        {
                            syncEvent.Release();
                        }
                    };

                    await syncEvent.WaitAsync();

                    syncEvent.Dispose();

                    if (exception != null)
                    {
                        throw exception;
                    }
                }

                channel.Close();
                channel.Dispose();
            }
            catch (Exception ex)
            {
                _ = Log.ErrorAsync(null, ex);
                throw;
            }
        }
            private async Task ListeningThread(IConnection connection, Func <IEvent, Task> handlerAsync)
            {
                canceller = new CancellationTokenSource();

retry:

                try
                {
                    if (this.channel != null)
                    {
                        throw new Exception("Exchange already open");
                    }

                    this.channel = connection.CreateModel();
                    this.channel.ExchangeDeclare(this.exchange, "fanout");

                    var queueName = this.channel.QueueDeclare().QueueName;
                    this.channel.QueueBind(queueName, this.exchange, String.Empty);

                    var consumer = new AsyncEventingBasicConsumer(this.channel);

                    consumer.Received += async(sender, e) =>
                    {
                        bool isEncrypted = e.BasicProperties.Headers != null && e.BasicProperties.Headers.Keys.Contains("Encryption") == true;

                        var stopwatch = new Stopwatch();
                        stopwatch.Start();

                        var properties     = e.BasicProperties;
                        var acknowledgment = new Acknowledgement();

                        if (!isEncrypted && encryptionKey != null)
                        {
                            acknowledgment.Success      = false;
                            acknowledgment.ErrorMessage = "Encryption Required";
                        }
                        else
                        {
                            try
                            {
                                byte[] body = e.Body;
                                if (isEncrypted)
                                {
                                    body = SymmetricEncryptor.Decrypt(encryptionAlgorithm, encryptionKey, e.Body);
                                }

                                var rabbitMessage = RabbitMQCommon.Deserialize <RabbitMQEventMessage>(body);

                                if (rabbitMessage.Claims != null)
                                {
                                    var claimsIdentity = new ClaimsIdentity(rabbitMessage.Claims.Select(x => new Claim(x[0], x[1])), "CQRS");
                                    System.Threading.Thread.CurrentPrincipal = new ClaimsPrincipal(claimsIdentity);
                                }

                                await handlerAsync(rabbitMessage.Message);

                                stopwatch.Stop();

                                _ = Log.TraceAsync($"Received: {e.Exchange} {stopwatch.ElapsedMilliseconds}");

                                acknowledgment.Success = true;
                            }
                            catch (Exception ex)
                            {
                                stopwatch.Stop();

                                ex = ex.GetBaseException();

                                acknowledgment.Success      = false;
                                acknowledgment.ErrorMessage = ex.Message;

                                _ = Log.TraceAsync($"Error: Received: {e.Exchange} {acknowledgment.ErrorMessage} {stopwatch.ElapsedMilliseconds}");

                                _ = Log.ErrorAsync(null, ex);
                            }
                        }
                    };

                    this.channel.BasicConsume(queueName, false, consumer);
                }
                catch (Exception ex)
                {
                    _ = Log.ErrorAsync(ex);

                    if (!canceller.IsCancellationRequested)
                    {
                        if (channel != null)
                        {
                            channel.Close();
                            channel.Dispose();
                            channel = null;
                        }
                        await Task.Delay(retryDelay);

                        goto retry;
                    }
                }

                canceller.Dispose();
                canceller = null;

                if (channel != null)
                {
                    channel.Close();
                    channel.Dispose();
                    channel = null;
                }

                IsOpen = false;
            }