Default Bus Configuration

Overview

This document explains the NServiceBus configuration system in FlexBase applications, using the EBusiness sample as a reference. The bus configuration provides a flexible, environment-aware messaging system that supports multiple transport and persistence options.

Architecture Overview

The NServiceBus configuration in FlexBase follows a strategy pattern where different configurations are selected based on the environment and requirements. This allows for seamless transitions between development, staging, and production environments.

Configuration Flow

Environment Detection β†’ Configuration Selection β†’ Transport Setup β†’ Persistence Setup β†’ Routing Configuration

Project Structure

EBusiness.Nsb Project

The EBusiness.Nsb project contains all NServiceBus configuration implementations:

EBusiness.Nsb/
β”œβ”€β”€ EBusiness.Nsb.csproj                    # Project file with NServiceBus packages
β”œβ”€β”€ LearningNsbConfiguration.cs             # Development/Testing transport
β”œβ”€β”€ RabbitMqNsbConfiguration.cs             # Production RabbitMQ transport
β”œβ”€β”€ SqlNsbConfiguration.cs                  # SQL Server transport
β”œβ”€β”€ AzureServiceNsbConfiguration.cs         # Azure Service Bus transport
β”œβ”€β”€ AzureStorageQueueNsbConfiguration.cs    # Azure Storage Queue transport
β”œβ”€β”€ AmazonSQSNsbConfiguration.cs            # Amazon SQS transport
└── MyCustomNsbConfiguration.cs             # Template for custom configurations

Dependencies

The project references multiple FlexBase NServiceBus packages:

<PackageReference Include="Sumeru.Flex.ServiceBus.Nsb" Version="9.2.0" />
<PackageReference Include="Sumeru.Flex.ServiceBus.Nsb.Azure.Storage" Version="9.2.0" />
<PackageReference Include="Sumeru.Flex.ServiceBus.Nsb.Learning" Version="9.2.0" />
<PackageReference Include="Sumeru.Flex.ServiceBus.Nsb.OnPremises.Rabbit" Version="9.2.0" />
<PackageReference Include="Sumeru.Flex.ServiceBus.Nsb.Amazon.SQS" Version="9.2.0" />
<PackageReference Include="Sumeru.Flex.ServiceBus.Nsb.Azure.ServiceBus" Version="9.2.0" />
<PackageReference Include="Sumeru.Flex.ServiceBus.Nsb.SqlTransport" Version="9.2.0" />
<PackageReference Include="Sumeru.Flex.ServiceBus.Nsb.SqlPersistence" Version="9.2.0" />

Configuration Selection Logic

BusEndPointConfig.cs - Environment-Based Selection

The BusEndPointConfig.cs file contains the logic for selecting the appropriate NServiceBus configuration based on the environment:

public static EndpointConfiguration GetEndpoint(IConfiguration configuration, IHostEnvironment env, List<BusRouteConfig> routes)
{
    string endPointName = configuration.GetSection("EndPoint")["Name"];
    
    NsbDefaultEndpointConfiguration endPointConfig;
    
    if (env.IsDevelopment())
    {
        endPointConfig = new LearningNsbConfiguration(endPointName, routes, configuration, env);
    }
    else if (env.IsStaging())
    {
        endPointConfig = new RabbitMqNsbConfiguration(endPointName, routes, configuration, env);
    }
    else if (env.IsProduction())
    {
        endPointConfig = new RabbitMqNsbConfiguration(endPointName, routes, configuration, env);
    }
    else
    {
        endPointConfig = new RabbitMqNsbConfiguration(endPointName, routes, configuration, env);
    }
    
    return endPointConfig;
}

Environment Mapping

Environment
Configuration
Transport
Persistence
Use Case

Development

LearningNsbConfiguration

Learning Transport

Learning Persistence

Local development, testing

Staging

RabbitMqNsbConfiguration

RabbitMQ

SQL Server

Pre-production testing

Production

RabbitMqNsbConfiguration

RabbitMQ

SQL Server

Live production environment

Default

RabbitMqNsbConfiguration

RabbitMQ

SQL Server

Fallback configuration

Transport Configurations

1. Learning Transport (Development)

File: LearningNsbConfiguration.cs

public class LearningNsbConfiguration : NsbBaseConfiguration
{
    public LearningNsbConfiguration(string endpointName, IEnumerable<BusRouteConfig> routes, IConfiguration configuration, IHostEnvironment env, string errorQueueName = "error") 
        : base(endpointName, configuration, env, errorQueueName)
    {
        // Configure persistence
        var persistence = this.UsePersistence<LearningPersistence>();
        
        // Configure transport
        var transport = this.UseTransport<LearningTransport>();
        
        // Configure routing
        var routing = transport.Routing();
        foreach (var route in routes)
        {
            routing.RouteToEndpoint(route.Assembly, route.Destination);
        }
    }
}

Characteristics:

  • File-Based: Stores messages in local file system

  • No Dependencies: No external infrastructure required

  • Development Only: Not suitable for production

  • Auto-Cleanup: Automatically manages message storage

Configuration Requirements:

  • No connection strings required

  • Creates .learningtransport directory automatically

  • Perfect for local development and testing

2. RabbitMQ Transport (Production)

File: RabbitMqNsbConfiguration.cs

public class RabbitMqNsbConfiguration : NsbBaseConfiguration
{
    public RabbitMqNsbConfiguration(string endpointName, IEnumerable<BusRouteConfig> routes, IConfiguration configuration, IHostEnvironment env, string errorQueueName = "error") 
        : base(endPointName, configuration, env, errorQueueName)
    {
        string sqlPersistenceConnectionString = configuration.GetSection("FlexBase")["SqlPersistenceConnectionString"];
        string rabbitMqConnectionString = configuration.GetSection("FlexBase")["RabbitMqConnectionString"];
        
        // Configure persistence
        var persistence = this.UsePersistence<SqlPersistence>();
        persistence.SqlDialect<SqlDialect.MsSqlServer>();
        persistence.ConnectionBuilder(() => new SqlConnection(sqlPersistenceConnectionString));
        
        // Configure transport
        var transport = this.UseTransport<RabbitMQTransport>();
        transport.ConnectionString(rabbitMqConnectionString);
        transport.UseConventionalRoutingTopology(QueueType.Classic);
        
        // Configure routing
        var routing = transport.Routing();
        foreach (var route in routes)
        {
            routing.RouteToEndpoint(route.Assembly, route.Destination);
        }
    }
}

Characteristics:

  • High Performance: Excellent for high-throughput scenarios

  • Reliable: Message durability and delivery guarantees

  • Scalable: Horizontal scaling capabilities

  • Production Ready: Suitable for enterprise environments

Configuration Requirements:

{
  "FlexBase": {
    "SqlPersistenceConnectionString": "Data Source=YourServer;Initial Catalog=YourPersistenceDb;...",
    "RabbitMqConnectionString": "amqp://YourUser:YourPassword@YourRabbitMqHost:YourPort"
  }
}

3. SQL Server Transport

File: SqlNsbConfiguration.cs

public class SqlNsbConfiguration : NsbBaseConfiguration
{
    public SqlNsbConfiguration(string endpointName, IEnumerable<BusRouteConfig> routes, IConfiguration configuration, IHostEnvironment env, string errorQueueName = "error") 
        : base(endPointName, configuration, env, errorQueueName)
    {
        string sqlPersistenceConnectionString = configuration.GetSection("FlexBase")["SqlPersistenceConnectionString"];
        string sqlTransportConnectionString = configuration.GetSection("FlexBase")["SqlTransportConnectionString"];
        
        // Configure persistence
        var persistence = this.UsePersistence<SqlPersistence>();
        persistence.SqlDialect<SqlDialect.MsSqlServer>();
        persistence.ConnectionBuilder(() => new SqlConnection(sqlPersistenceConnectionString));
        
        // Configure transport
        var transport = new SqlServerTransport(sqlTransportConnectionString);
        this.UseTransport(transport);
        
        // Configure routing
        var routing = this.UseTransport(transport);
        foreach (var route in routes)
        {
            routing.RouteToEndpoint(route.Assembly, route.Destination);
        }
    }
}

Characteristics:

  • Database-Based: Uses SQL Server for message transport

  • Transactional: Leverages SQL Server transactions

  • Familiar: Easy to monitor and debug

  • Reliable: ACID compliance for message delivery

Configuration Requirements:

{
  "FlexBase": {
    "SqlPersistenceConnectionString": "Data Source=YourServer;Initial Catalog=YourPersistenceDb;...",
    "SqlTransportConnectionString": "Data Source=YourServer;Initial Catalog=YourTransportDb;..."
  }
}

4. Azure Service Bus Transport

File: AzureServiceNsbConfiguration.cs

public class AzureServiceNsbConfiguration : NsbBaseConfiguration
{
    public AzureServiceNsbConfiguration(string endpointName, IEnumerable<BusRouteConfig> routes, IConfiguration configuration, IHostEnvironment env, string errorQueueName = "error") 
        : base(endPointName, configuration, env, errorQueueName)
    {
        string sqlPersistenceConnectionString = configuration.GetSection("FlexBase")["SqlPersistenceConnectionString"];
        string azureServiceBusConnectionString = configuration.GetSection("FlexBase")["AzureServiceBusConnectionString"];
        
        // Configure persistence
        var persistence = this.UsePersistence<SqlPersistence>();
        persistence.SqlDialect<SqlDialect.MsSqlServer>();
        persistence.ConnectionBuilder(() => new SqlConnection(sqlPersistenceConnectionString));
        
        // Configure transport
        var transport = new AzureServiceBusTransport(azureServiceBusConnectionString);
        this.UseTransport(transport);
        
        // Configure routing
        var routing = this.UseTransport(transport);
        foreach (var route in routes)
        {
            routing.RouteToEndpoint(route.Assembly, route.Destination);
        }
    }
}

Characteristics:

  • Cloud-Native: Fully managed Azure service

  • Scalable: Auto-scaling capabilities

  • Reliable: 99.9% SLA guarantee

  • Integrated: Works seamlessly with other Azure services

Configuration Requirements:

{
  "FlexBase": {
    "SqlPersistenceConnectionString": "Data Source=YourServer;Initial Catalog=YourPersistenceDb;...",
    "AzureServiceBusConnectionString": "Endpoint=sb://YourNamespace.servicebus.windows.net/;SharedAccessKeyName=YourKeyName;SharedAccessKey=YourKey"
  }
}

5. Azure Storage Queue Transport

File: AzureStorageQueueNsbConfiguration.cs

public class AzureStorageQueueNsbConfiguration : NsbBaseConfiguration
{
    public AzureStorageQueueNsbConfiguration(string endpointName, IEnumerable<BusRouteConfig> routes, IConfiguration configuration, IHostEnvironment env, string errorQueueName = "error") 
        : base(endPointName, configuration, env, errorQueueName)
    {
        string azureConnectionString = configuration.GetSection("FlexBase")["AzureStorageConnectionString"];
        
        // Configure persistence
        var persistence = this.UsePersistence<AzureTablePersistence>();
        persistence.ConnectionString(azureConnectionString);
        
        // Configure transport
        var queueServiceClient = new QueueServiceClient(azureConnectionString, new QueueClientOptions());
        var blobServiceClient = new BlobServiceClient(azureConnectionString, new BlobClientOptions());
        var tableServiceClient = new TableServiceClient(azureConnectionString, new TableClientOptions());
        
        var transport = new AzureStorageQueueTransport(queueServiceClient, blobServiceClient, tableServiceClient)
        {
            ReceiverBatchSize = 20,
            MaximumWaitTimeWhenIdle = TimeSpan.FromSeconds(1),
            DegreeOfReceiveParallelism = 16,
            PeekInterval = TimeSpan.FromMilliseconds(100),
            MessageInvisibleTime = TimeSpan.FromSeconds(30)
        };
        
        // Configure routing
        var routing = this.UseTransport(transport);
        foreach (var route in routes)
        {
            routing.RouteToEndpoint(route.Assembly, route.Destination);
            routing.RegisterPublisher(route.Assembly, route.Destination);
        }
    }
}

Characteristics:

  • Cost-Effective: Lower cost than Service Bus

  • Simple: Easy to set up and manage

  • Scalable: Handles high message volumes

  • Azure-Native: Integrated with Azure ecosystem

Configuration Requirements:

{
  "FlexBase": {
    "AzureStorageConnectionString": "DefaultEndpointsProtocol=https;AccountName=YourAccount;AccountKey=YourKey;EndpointSuffix=core.windows.net"
  }
}

6. Amazon SQS Transport

File: AmazonSQSNsbConfiguration.cs

public class AmazonSQSNsbConfiguration : NsbBaseConfiguration
{
    public AmazonSQSNsbConfiguration(string endpointName, IEnumerable<BusRouteConfig> routes, IConfiguration configuration, IHostEnvironment env, string errorQueueName = "error") 
        : base(endPointName, configuration, env, errorQueueName)
    {
        string sqlPersistenceConnectionString = configuration.GetSection("FlexBase")["SqlPersistenceConnectionString"];
        string s3BucketName = configuration.GetSection("FlexBase")["AmazonSQSTransportBucketName"];
        string s3KeyPrefix = configuration.GetSection("FlexBase")["AmazonSQSTransportKeyPrefix"];
        
        // Configure persistence
        var persistence = this.UsePersistence<SqlPersistence>();
        persistence.SqlDialect<SqlDialect.MsSqlServer>();
        persistence.ConnectionBuilder(() => new SqlConnection(sqlPersistenceConnectionString));
        
        // Configure transport
        var transport = new SqsTransport
        {
            S3 = new S3Settings(
                bucketForLargeMessages: s3BucketName,
                keyPrefix: s3KeyPrefix,
                s3Client: new AmazonS3Client())
        };
        
        // Configure routing
        var routing = this.UseTransport(transport);
        foreach (var route in routes)
        {
            routing.RouteToEndpoint(route.Assembly, route.Destination);
        }
    }
}

Characteristics:

  • AWS-Native: Fully integrated with AWS services

  • Scalable: Auto-scaling message queues

  • Reliable: High availability and durability

  • Cost-Effective: Pay-per-use pricing model

Configuration Requirements:

{
  "FlexBase": {
    "SqlPersistenceConnectionString": "Data Source=YourServer;Initial Catalog=YourPersistenceDb;...",
    "AmazonSQSTransportBucketName": "YourS3BucketName",
    "AmazonSQSTransportKeyPrefix": "YourKeyPrefix"
  }
}

Service Registration

BusEndPointConfig.cs - Service Registration

The BusEndPointConfig.cs file also handles service registration for dependency injection:

public static void AddFlexBaseBusServices(this IServiceCollection services)
{
    services.AddSingleton<IFlexServiceBusBridge, NsbServiceBusBridge>();
    services.AddTransient<FlexBusSendOptions, NsbSendOptions>();
}

What This Does:

  • Service Bus Bridge: Registers the NServiceBus bridge as a singleton

  • Send Options: Registers send options for message publishing

  • Dependency Injection: Makes bus services available throughout the application

Configuration Best Practices

1. Environment-Specific Configuration

// Development
if (env.IsDevelopment())
{
    endPointConfig = new LearningNsbConfiguration(endPointName, routes, configuration, env);
}

// Staging
else if (env.IsStaging())
{
    endPointConfig = new RabbitMqNsbConfiguration(endPointName, routes, configuration, env);
}

// Production
else if (env.IsProduction())
{
    endPointConfig = new RabbitMqNsbConfiguration(endPointName, routes, configuration, env);
}

2. Connection String Management

{
  "FlexBase": {
    "SqlPersistenceConnectionString": "Data Source=YourServer;Initial Catalog=YourPersistenceDb;...",
    "RabbitMqConnectionString": "amqp://YourUser:YourPassword@YourRabbitMqHost:YourPort",
    "AzureServiceBusConnectionString": "Endpoint=sb://YourNamespace.servicebus.windows.net/;...",
    "AzureStorageConnectionString": "DefaultEndpointsProtocol=https;AccountName=YourAccount;...",
    "AmazonSQSTransportBucketName": "YourS3BucketName",
    "AmazonSQSTransportKeyPrefix": "YourKeyPrefix"
  }
}

3. Error Handling

Guard.AgainstNullAndEmpty("SqlPersistenceConnectionString for connection string cannot be empty", 
    configuration.GetSection("FlexBase")["SqlPersistenceConnectionString"]);

4. Routing Configuration

var routing = transport.Routing();
foreach (var route in routes)
{
    routing.RouteToEndpoint(route.Assembly, route.Destination);
}

Custom Configuration Template

MyCustomNsbConfiguration.cs

public class MyCustomNsbConfiguration : EndpointConfiguration
{
    public MyCustomNsbConfiguration(string endpointName, string errorQueueName = "error") : base(endpointName)
    {
        this.SendFailedMessagesTo(errorQueueName);
        
        // Add all other NSB Configuration here
        // - Transport configuration
        // - Persistence configuration
        // - Routing configuration
        // - Serialization settings
        // - Error handling
        // - Performance tuning
    }
}

Use Cases:

  • Custom Requirements: Specific business needs not covered by standard configurations

  • Performance Tuning: Optimized settings for specific scenarios

  • Integration: Custom transport or persistence providers

  • Testing: Specialized configurations for testing scenarios

Performance Considerations

Transport Selection Guidelines

Scenario
Recommended Transport
Reason

Development

Learning Transport

No external dependencies, easy setup

Small Scale

SQL Server Transport

Familiar, easy to monitor

High Throughput

RabbitMQ Transport

Excellent performance, reliable

Cloud-Native

Azure Service Bus

Fully managed, integrated

Cost-Sensitive

Azure Storage Queue

Lower cost, good performance

AWS Environment

Amazon SQS

Native AWS integration

Persistence Selection Guidelines

Scenario
Recommended Persistence
Reason

Development

Learning Persistence

No external dependencies

Production

SQL Server Persistence

Reliable, familiar, ACID compliance

Azure

Azure Table Persistence

Native Azure integration

Troubleshooting

Common Issues

  1. Connection String Errors

    • Verify connection strings in configuration

    • Check network connectivity

    • Validate credentials

  2. Transport Failures

    • Ensure transport service is running

    • Check firewall settings

    • Verify endpoint configuration

  3. Routing Issues

    • Verify route configuration

    • Check assembly references

    • Validate destination endpoints

  4. Performance Problems

    • Monitor message throughput

    • Check resource utilization

    • Consider transport scaling

Debugging Tips

  1. Enable Logging: Use structured logging to track message flow

  2. Monitor Queues: Check queue depths and processing rates

  3. Health Checks: Implement health checks for transport and persistence

  4. Metrics: Use application insights or similar tools for monitoring

Key Benefits

  • Environment Awareness: Automatic configuration based on environment

  • Multiple Transports: Support for various messaging technologies

  • Flexible Persistence: Multiple persistence options

  • Easy Configuration: Simple configuration management

  • Production Ready: Battle-tested configurations

  • Scalable: Supports high-throughput scenarios

  • Reliable: Built-in error handling and retry mechanisms

  • Maintainable: Clear separation of concerns

  • Testable: Easy to test with different configurations


This NServiceBus configuration system provides a robust, scalable, and maintainable messaging infrastructure that adapts to different environments and requirements! πŸš€

Last updated