Dependency Injection Extensions
The Switchboard.Extensions.DependencyInjection package provides powerful IoC/DI integration for the Switchboard framework, enabling clean, testable, and maintainable code.
Installation
dotnet add package Switchboard.Extensions.DependencyInjectionQuick Start
Ultra-Simple Setup (Recommended)
using Microsoft.Extensions.Hosting;
using Switchboard.Extensions.DependencyInjection;
var builder = Host.CreateApplicationBuilder(args);
// One-liner: Switchboard + assembly scanning
builder.AddSwitchboardWithScanning(options =>
{
options.InstanceName = "MyCallCenter";
options.Region = "us-east-1";
});
var host = builder.Build();
var app = host.Services.GetRequiredService<ISwitchboardApp>();
// Auto-discover and configure everything
var stack = app.CreateAndConfigureStack(
host.Services,
"MyCallCenter",
"my-instance-alias"
);
app.Synth();Extension Methods
AddSwitchboardWithScanning()
Configures Switchboard and automatically scans your assembly for flow builders and providers.
Signature:
public static IHostApplicationBuilder AddSwitchboardWithScanning(
this IHostApplicationBuilder builder,
Action<SwitchboardOptions>? configure = null)What it does:
- Registers Switchboard framework services in DI
- Applies configuration options
- Scans the entry assembly for classes ending in
*FlowBuilderand*Provider - Registers all discovered classes as singletons
Example:
builder.AddSwitchboardWithScanning(options =>
{
options.InstanceName = "EnterpriseCallCenter";
options.Region = "us-east-1";
options.Environment = "Production";
});AddSwitchboard()
Registers Switchboard services without automatic scanning (for manual control).
Signature:
public static ISwitchboardBuilder AddSwitchboard(
this IServiceCollection services,
Action<SwitchboardOptions> configure)Example:
builder.Services.AddSwitchboard(options =>
{
options.InstanceName = "MyCallCenter";
options.Region = "us-east-1";
})
.AddAssemblyScanning(typeof(Program).Assembly);AddAssemblyScanning()
Scans a specific assembly for flow builders and providers.
Signature:
public static ISwitchboardBuilder AddAssemblyScanning(
this ISwitchboardBuilder builder,
Assembly assembly)What it discovers:
- All classes ending with
FlowBuilder(e.g.,SalesInboundFlowBuilder) - All classes ending with
Provider(e.g.,QueueConfigurationProvider,HoursOfOperationProvider)
Example:
builder.Services.AddSwitchboard(options => { })
.AddAssemblyScanning(typeof(Program).Assembly);AddFlowBuilders()
Manually registers specific flow builder types (alternative to assembly scanning).
Signature:
public static ISwitchboardBuilder AddFlowBuilders(
this ISwitchboardBuilder builder,
params Type[] flowBuilderTypes)Example:
builder.Services.AddSwitchboard(options => { })
.AddFlowBuilders(
typeof(SalesInboundFlowBuilder),
typeof(SupportInboundFlowBuilder)
);AddProviders()
Manually registers specific provider types (alternative to assembly scanning).
Signature:
public static ISwitchboardBuilder AddProviders(
this ISwitchboardBuilder builder,
params Type[] providerTypes)Example:
builder.Services.AddSwitchboard(options => { })
.AddProviders(
typeof(QueueConfigurationProvider),
typeof(HoursOfOperationProvider)
);CreateAndConfigureStack()
Creates a stack and automatically discovers and adds all resources from DI.
Signature:
public static SwitchboardStack CreateAndConfigureStack(
this ISwitchboardApp app,
IServiceProvider serviceProvider,
string stackName,
string instanceAlias)What it does:
- Creates the CDK stack
- Resolves all
*Providerclasses from DI - Invokes
GetBusinessHours()orGetExtendedHours()methods → adds hours to stack - Invokes
GetAllQueues()methods → adds queues to stack - Resolves all
*FlowBuilderclasses from DI - Invokes
Build()on each → adds flows to stack
Example:
var stack = app.CreateAndConfigureStack(
host.Services,
"EnterpriseCallCenter",
"enterprise-demo"
);SwitchboardOptions
Configuration options for the framework.
public class SwitchboardOptions
{
/// <summary>
/// Amazon Connect instance name/alias.
/// </summary>
public string? InstanceName { get; set; }
/// <summary>
/// AWS region for deployment (default: "us-east-1").
/// </summary>
public string Region { get; set; } = "us-east-1";
/// <summary>
/// AWS account ID.
/// </summary>
public string? AwsAccount { get; set; }
/// <summary>
/// Environment name (Development, Staging, Production).
/// </summary>
public string Environment { get; set; } = "Development";
/// <summary>
/// Enable automatic assembly scanning (default: true).
/// </summary>
public bool EnableAssemblyScanning { get; set; } = true;
}Usage Patterns
Pattern 1: Ultra-Simple (Recommended)
Best for most projects. One-liner setup with auto-discovery.
var builder = Host.CreateApplicationBuilder(args);
builder.AddSwitchboardWithScanning(options =>
{
options.InstanceName = "MyCallCenter";
options.Region = "us-east-1";
});
var host = builder.Build();
var app = host.Services.GetRequiredService<ISwitchboardApp>();
var stack = app.CreateAndConfigureStack(host.Services, "MyCallCenter", "my-alias");
app.Synth();Pros:
- ✅ Minimal code (< 15 lines)
- ✅ Convention-based discovery
- ✅ Clean and maintainable
Pattern 2: Manual Control
When you need explicit control over what gets registered.
var builder = Host.CreateApplicationBuilder(args);
builder.Services.AddSwitchboard(options =>
{
options.InstanceName = "MyCallCenter";
options.Region = "us-east-1";
})
.AddFlowBuilders(
typeof(SalesFlowBuilder),
typeof(SupportFlowBuilder)
)
.AddProviders(
typeof(QueueConfigurationProvider)
);
var host = builder.Build();
var app = host.Services.GetRequiredService<ISwitchboardApp>();
// Still auto-configures stack
var stack = app.CreateAndConfigureStack(host.Services, "MyCallCenter", "my-alias");
app.Synth();Pros:
- ✅ Explicit registration (easy to understand what's included)
- ✅ Still uses auto-configuration for stack
- ✅ Good for smaller projects
Pattern 3: Full Manual
Maximum control - manually resolve and add everything.
var builder = Host.CreateApplicationBuilder(args);
builder.Services.AddSwitchboard(options =>
{
options.InstanceName = "MyCallCenter";
options.Region = "us-east-1";
})
.AddAssemblyScanning(typeof(Program).Assembly);
var host = builder.Build();
var app = host.Services.GetRequiredService<ISwitchboardApp>();
var stack = app.CreateStack("MyCallCenter", "my-alias");
// Manually resolve and add hours
var hoursProvider = host.Services.GetRequiredService<HoursOfOperationProvider>();
var businessHours = hoursProvider.GetBusinessHours();
stack.AddHoursOfOperation(businessHours);
// Manually resolve and add queues
var queueProvider = host.Services.GetRequiredService<QueueConfigurationProvider>();
foreach (var queue in queueProvider.GetAllQueues())
{
stack.AddQueue(queue, businessHours.Name);
}
// Manually resolve and build flows
var salesFlow = host.Services.GetRequiredService<SalesFlowBuilder>().Build();
stack.AddFlow(salesFlow);
app.Synth();Pros:
- ✅ Maximum control over ordering
- ✅ Can conditionally add resources
- ✅ Good for complex scenarios
Conventions
The framework follows these conventions:
Flow Builders
Classes ending with FlowBuilder are automatically discovered and registered.
public class SalesInboundFlowBuilder
{
public IFlow Build()
{
return new FlowBuilder()
.SetName("SalesInbound")
// ...
.Build();
}
}Providers
Classes ending with Provider are automatically discovered and registered.
public class QueueConfigurationProvider
{
public List<IQueue> GetAllQueues()
{
return new List<IQueue>
{
new QueueBuilder().SetName("Sales").Build(),
new QueueBuilder().SetName("Support").Build()
};
}
}
public class HoursOfOperationProvider
{
public HoursOfOperation GetBusinessHours()
{
var hours = new HoursOfOperation
{
Name = "BusinessHours",
TimeZone = "America/New_York"
};
// Configure hours...
return hours;
}
}Benefits
- Testability: All components can be mocked/injected for unit testing
- Maintainability: Clear separation of concerns
- Convention-based: Minimal configuration needed
- Type-safe: Compile-time checking
- Flexible: Three levels of control (ultra-simple, manual, full manual)