Exemple #1
0
        public void PostConfigure(string name, AzureQueueStorageTransportOptions options)
        {
            // Ensure the connection string
            if (string.IsNullOrWhiteSpace(options.ConnectionString))
            {
                throw new InvalidOperationException($"The '{nameof(options.ConnectionString)}' must be provided");
            }

            // Ensure there's only one consumer per event
            var registrations = busOptions.GetRegistrations(TransportNames.AzureQueueStorage);
            var multiple      = registrations.FirstOrDefault(r => r.Consumers.Count > 1);

            if (multiple != null)
            {
                throw new InvalidOperationException($"More than one consumer registered for '{multiple.EventType.Name}' yet "
                                                    + "Azure Queue Storage does not support more than one consumer per event in the same application domain.");
            }

            // Ensure the entity names are not longer than the limits
            // See https://docs.microsoft.com/en-us/rest/api/storageservices/naming-queues-and-metadata#queue-names
            foreach (var ereg in registrations)
            {
                // Event names become topic names and they should not be longer than 63 characters
                if (ereg.EventName.Length > 63)
                {
                    throw new InvalidOperationException($"EventName '{ereg.EventName}' generated from '{ereg.EventType.Name}' is too long. "
                                                        + "Azure Queue Storage does not allow more than 63 characters for Queue names.");
                }
            }
        }
Exemple #2
0
        public void PostConfigure(string name, KafkaTransportOptions options)
        {
            if (options.BootstrapServers == null && options.AdminConfig == null)
            {
                throw new InvalidOperationException($"Either '{nameof(options.BootstrapServers)}' or '{nameof(options.AdminConfig)}' must be provided");
            }

            if (options.BootstrapServers != null && options.BootstrapServers.Any(b => string.IsNullOrWhiteSpace(b)))
            {
                throw new ArgumentNullException(nameof(options.BootstrapServers), "A bootstrap server cannot be null or empty");
            }

            // ensure we have a config
            options.AdminConfig ??= new AdminClientConfig
            {
                BootstrapServers = string.Join(",", options.BootstrapServers)
            };

            if (string.IsNullOrWhiteSpace(options.AdminConfig.BootstrapServers))
            {
                throw new InvalidOperationException($"BootstrapServers must be provided via '{nameof(options.BootstrapServers)}' or '{nameof(options.AdminConfig)}'.");
            }

            // ensure the checkpoint interval is not less than 1
            options.CheckpointInterval = Math.Max(options.CheckpointInterval, 1);

            // ensure there's only one consumer per event
            var registrations = busOptions.GetRegistrations(TransportNames.Kafka);
            var multiple      = registrations.FirstOrDefault(r => r.Consumers.Count > 1);

            if (multiple != null)
            {
                throw new InvalidOperationException($"More than one consumer registered for '{multiple.EventType.Name}' yet "
                                                    + "Kafka does not support more than one consumer per event in the same application domain.");
            }

            // Ensure the entity names are not longer than the limits
            // See https://docs.microsoft.com/en-us/azure/event-hubs/event-hubs-quotas#common-limits-for-all-tiers
            foreach (var ereg in registrations)
            {
                // Event names become Topic names and they should not be longer than 255 characters
                // https://www.ibm.com/support/knowledgecenter/SSMKHH_10.0.0/com.ibm.etools.mft.doc/bz91041_.html
                if (ereg.EventName.Length > 255)
                {
                    throw new InvalidOperationException($"EventName '{ereg.EventName}' generated from '{ereg.EventType.Name}' is too long. "
                                                        + "Kafka does not allow more than 255 characters for Topic names.");
                }

                // Consumer names become Consumer Group IDs and they should not be longer than 255 characters
                foreach (var creg in ereg.Consumers)
                {
                    if (creg.ConsumerName.Length > 255)
                    {
                        throw new InvalidOperationException($"ConsumerName '{creg.ConsumerName}' generated from '{creg.ConsumerType.Name}' is too long. "
                                                            + "Kafka does not allow more than 255 characters for Consumer Group IDs.");
                    }
                }
            }
        }
        public void PostConfigure(string name, AmazonKinesisTransportOptions options)
        {
            // Ensure the region is provided
            if (string.IsNullOrWhiteSpace(options.RegionName) && options.Region == null)
            {
                throw new InvalidOperationException($"Either '{nameof(options.RegionName)}' or '{nameof(options.Region)}' must be provided");
            }

            options.Region ??= RegionEndpoint.GetBySystemName(options.RegionName);

            // Ensure the access key is specified
            if (string.IsNullOrWhiteSpace(options.AccessKey))
            {
                throw new InvalidOperationException($"The '{nameof(options.AccessKey)}' must be provided");
            }

            // Ensure the secret is specified
            if (string.IsNullOrWhiteSpace(options.SecretKey))
            {
                throw new InvalidOperationException($"The '{nameof(options.SecretKey)}' must be provided");
            }

            // Ensure we have options for Kinesis and the region is set
            options.KinesisConfig ??= new AmazonKinesisConfig();
            options.KinesisConfig.RegionEndpoint ??= options.Region;

            // Ensure the partition key resolver is set
            if (options.PartitionKeyResolver == null)
            {
                throw new InvalidOperationException($"The '{nameof(options.PartitionKeyResolver)}' must be provided");
            }

            // Ensure the entity names are not longer than the limits
            var registrations = busOptions.GetRegistrations(TransportNames.AmazonKinesis);

            foreach (var ereg in registrations)
            {
                // Event names become Stream names and they should not be longer than 128 characters
                // See https://docs.aws.amazon.com/kinesis/latest/APIReference/API_CreateStream.html
                if (ereg.EventName.Length > 128)
                {
                    throw new InvalidOperationException($"EventName '{ereg.EventName}' generated from '{ereg.EventType.Name}' is too long. "
                                                        + "Amazon Kinesis does not allow more than 128 characters for Stream names.");
                }

                // Consumer names become Queue names and they should not be longer than 128 characters
                // See https://docs.aws.amazon.com/kinesis/latest/APIReference/API_RegisterStreamConsumer.html
                foreach (var creg in ereg.Consumers)
                {
                    if (creg.ConsumerName.Length > 128)
                    {
                        throw new InvalidOperationException($"ConsumerName '{creg.ConsumerName}' generated from '{creg.ConsumerType.Name}' is too long. "
                                                            + "Amazon Kinesis does not allow more than 128 characters for Stream Consumer names.");
                    }
                }
            }
        }
        public void PostConfigure(string name, AmazonSqsTransportOptions options)
        {
            // Ensure the region is provided
            if (string.IsNullOrWhiteSpace(options.RegionName) && options.Region == null)
            {
                throw new InvalidOperationException($"Either '{nameof(options.RegionName)}' or '{nameof(options.Region)}' must be provided");
            }

            options.Region ??= RegionEndpoint.GetBySystemName(options.RegionName);

            // Ensure the access key is specified
            if (string.IsNullOrWhiteSpace(options.AccessKey))
            {
                throw new InvalidOperationException($"The '{nameof(options.AccessKey)}' must be provided");
            }

            // Ensure the secret is specified
            if (string.IsNullOrWhiteSpace(options.SecretKey))
            {
                throw new InvalidOperationException($"The '{nameof(options.SecretKey)}' must be provided");
            }

            // Ensure we have options for SQS and SNS and their regions are set
            options.SqsConfig ??= new AmazonSQSConfig();
            options.SqsConfig.RegionEndpoint ??= options.Region;
            options.SnsConfig ??= new AmazonSimpleNotificationServiceConfig();
            options.SnsConfig.RegionEndpoint ??= options.Region;

            // Ensure the entity names are not longer than the limits
            var registrations = busOptions.GetRegistrations(TransportNames.AmazonSqs);

            foreach (var ereg in registrations)
            {
                // Event names become Topic names and they should not be longer than 256 characters
                // See https://aws.amazon.com/sns/faqs/#:~:text=Features%20and%20functionality,and%20underscores%20(_)%20are%20allowed.
                if (ereg.EventName.Length > 256)
                {
                    throw new InvalidOperationException($"EventName '{ereg.EventName}' generated from '{ereg.EventType.Name}' is too long. "
                                                        + "Amazon SNS does not allow more than 256 characters for Topic names.");
                }

                // Consumer names become Queue names and they should not be longer than 80 characters
                // See https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/quotas-queues.html
                foreach (var creg in ereg.Consumers)
                {
                    if (creg.ConsumerName.Length > 80)
                    {
                        throw new InvalidOperationException($"ConsumerName '{creg.ConsumerName}' generated from '{creg.ConsumerType.Name}' is too long. "
                                                            + "Amazon SQS does not allow more than 80 characters for Queue names.");
                    }
                }
            }
        }
        public void PostConfigure(string name, AzureEventHubsTransportOptions options)
        {
            // Ensure the connection string
            if (string.IsNullOrWhiteSpace(options.ConnectionString))
            {
                throw new InvalidOperationException($"The '{nameof(options.ConnectionString)}' must be provided");
            }

            // If there are consumers for this transport, we must check azure blob storage
            var registrations = busOptions.GetRegistrations(TransportNames.AzureEventHubs);

            if (registrations.Any(r => r.Consumers.Count > 0))
            {
                // ensure the connection string for blob storage is valid
                if (string.IsNullOrWhiteSpace(options.BlobStorageConnectionString))
                {
                    throw new InvalidOperationException($"The '{nameof(options.BlobStorageConnectionString)}' must be provided");
                }

                // ensure the blob container name is provided
                if (string.IsNullOrWhiteSpace(options.BlobContainerName))
                {
                    throw new InvalidOperationException($"The '{nameof(options.BlobContainerName)}' must be provided");
                }

                // ensure the prefix is always lower case.
                options.BlobContainerName = options.BlobContainerName.ToLower();
            }

            // Ensure the entity names are not longer than the limits
            // See https://docs.microsoft.com/en-us/azure/event-hubs/event-hubs-quotas#common-limits-for-all-tiers
            foreach (var ereg in registrations)
            {
                // Event names become Event Hub names and they should not be longer than 256 characters
                if (ereg.EventName.Length > 256)
                {
                    throw new InvalidOperationException($"EventName '{ereg.EventName}' generated from '{ereg.EventType.Name}' is too long. "
                                                        + "Azure Event Hubs does not allow more than 256 characters for Event Hub names.");
                }

                // Consumer names become Consumer Group names and they should not be longer than 256 characters
                foreach (var creg in ereg.Consumers)
                {
                    if (creg.ConsumerName.Length > 256)
                    {
                        throw new InvalidOperationException($"ConsumerName '{creg.ConsumerName}' generated from '{creg.ConsumerType.Name}' is too long. "
                                                            + "Azure Event Hubs does not allow more than 256 characters for Consumer Group names.");
                    }
                }
            }
        }
        public void PostConfigure(string name, AzureServiceBusTransportOptions options)
        {
            // Ensure the connection string is not null
            if (string.IsNullOrWhiteSpace(options.ConnectionString))
            {
                throw new InvalidOperationException($"The '{nameof(options.ConnectionString)}' must be provided");
            }

            // Ensure the entity names are not longer than the limits
            // See https://docs.microsoft.com/en-us/azure/service-bus-messaging/service-bus-quotas#messaging-quotas
            var registrations = busOptions.GetRegistrations(TransportNames.AzureServiceBus);

            foreach (var ereg in registrations)
            {
                // Event names become Topic and Queue names and they should not be longer than 260 characters
                if (ereg.EventName.Length > 260)
                {
                    throw new InvalidOperationException($"EventName '{ereg.EventName}' generated from '{ereg.EventType.Name}' is too long. "
                                                        + "Azure Service Bus does not allow more than 260 characters for Topic and Queue names.");
                }

                // Consumer names become Subscription names and they should not be longer than 50 characters
                // When not using basic tier or when mapped to Queue, ConsumerName -> SubscriptionName does not happen
                if (!options.UseBasicTier && !ereg.UseQueueInsteadOfTopic())
                {
                    foreach (var creg in ereg.Consumers)
                    {
                        if (creg.ConsumerName.Length > 50)
                        {
                            throw new InvalidOperationException($"ConsumerName '{creg.ConsumerName}' generated from '{creg.ConsumerType.Name}' is too long. "
                                                                + "Azure Service Bus does not allow more than 50 characters for Subscription names.");
                        }
                    }
                }
            }
        }
        public void PostConfigure(string name, RabbitMqTransportOptions options)
        {
            // If there are consumers for this transport, confirm the right Bus options
            var registrations = busOptions.GetRegistrations(TransportNames.RabbitMq);

            if (registrations.Any(r => r.Consumers.Count > 0))
            {
                // we need full type names
                if (!busOptions.Naming.UseFullTypeNames)
                {
                    throw new NotSupportedException($"When using RabbitMQ transport '{nameof(busOptions.Naming.UseFullTypeNames)}' must be 'true'");
                }

                // consumer names must be suffixed
                if (!busOptions.Naming.SuffixConsumerName)
                {
                    throw new NotSupportedException($"When using RabbitMQ transport '{nameof(busOptions.Naming.SuffixConsumerName)}' must be 'true'");
                }
            }

            // if we do not have a connection factory, attempt to create one
            if (options.ConnectionFactory == null)
            {
                // ensure we have a hostname
                if (string.IsNullOrWhiteSpace(options.Hostname))
                {
                    throw new ArgumentNullException(nameof(options.Hostname), "The hostname is required to connect to a RabbitMQ broker");
                }

                // ensure we have a username and password
                options.Username ??= "guest";
                options.Password ??= "guest";

                options.ConnectionFactory = new ConnectionFactory
                {
                    HostName = options.Hostname,
                    UserName = options.Username,
                    Password = options.Password,
                };
            }

            // at this point we have a connection factory, ensure certain settings are what we need them to be
            options.ConnectionFactory.DispatchConsumersAsync = true;

            // ensure the retries are not less than zero
            options.RetryCount = Math.Max(options.RetryCount, 0);

            // Ensure the entity names are not longer than the limits
            // See https://www.rabbitmq.com/queues.html#:~:text=Names,bytes%20of%20UTF%2D8%20characters.
            foreach (var ereg in registrations)
            {
                // Event names become Exchange names and they should not be longer than 255 characters
                if (ereg.EventName.Length > 255)
                {
                    throw new InvalidOperationException($"EventName '{ereg.EventName}' generated from '{ereg.EventType.Name}' is too long. "
                                                        + "RabbitMQ does not allow more than 255 characters for Exchange names.");
                }

                // Consumer names become Queue names and they should not be longer than 255 characters
                foreach (var creg in ereg.Consumers)
                {
                    if (creg.ConsumerName.Length > 255)
                    {
                        throw new InvalidOperationException($"ConsumerName '{creg.ConsumerName}' generated from '{creg.ConsumerType.Name}' is too long. "
                                                            + "RabbitMQ does not allow more than 255 characters for Queue names.");
                    }
                }
            }
        }