Attribute-Based Design
ALPHA - LIMITED ATTRIBUTES IN M1
Switchboard is currently in preview (v0.1.0-preview.62). In Milestone 1, only three internal attributes are available for extending the fluent API via source generators: [FlowAction], [Parameter], and [Transition].
Planned attributes (post-v1.0) include [ContactFlow], [Message], [Queue], and many others. See the Future section below.
This guide describes the current attribute model and the future roadmap.
Current: Flow Action Attributes (M1)
What's Available Now
The FlowActionGenerator uses three attributes to generate type-safe fluent methods:
[FlowAction]- Marks a class as a flow action[Parameter]- Marks a property as a method parameter[Transition]- Marks a property for transition routing
Example
using Switchboard.SourceGenerators.Attributes;
[FlowAction("PlayMessage")]
public class PlayMessageAction : FlowAction
{
[Parameter]
public string Text { get; set; }
[Parameter]
public string Voice { get; set; } = "Joanna";
}Generated Extension Method:
public static IFlowBuilder PlayMessage(
this IFlowBuilder builder,
string text,
string voice = "Joanna")
{
var action = new PlayMessageAction
{
Identifier = $"play-message-{Guid.NewGuid().ToString()[..8]}",
Text = text,
Voice = voice
};
return builder.AddFlowAction(action);
}Usage:
var flow = new FlowBuilder()
.SetName("SalesFlow")
.SetType(FlowType.ContactFlow)
.PlayMessage("Welcome to sales")
.TransferToQueue("SalesQueue")
.Build();Best Practices (Current)
1. Use Clear Action Names
// ✅ Good
[FlowAction("GetMenuChoice")]
public class GetMenuChoiceAction : FlowAction { }
// ❌ Poor
[FlowAction("Action1")]
public class Action1 : FlowAction { }2. Mark Parameters Explicitly
Only properties with [Parameter] appear in the generated method signature:
[FlowAction("GetInput")]
public class GetInputAction : FlowAction
{
[Parameter]
public string Prompt { get; set; } // In signature
public string InternalId { get; set; } // Not in signature
}3. Provide Sensible Defaults
[FlowAction("Timeout")]
public class TimeoutAction : FlowAction
{
[Parameter]
public int Seconds { get; set; } = 5; // Optional in generated method
}4. Inherit from FlowAction
All action classes must inherit from FlowAction:
[FlowAction("MyAction")]
public class MyAction : FlowAction // Required
{
[Parameter]
public string Data { get; set; }
}Understanding the Fluent API
Since attribute-based flow definitions are not yet available (M1), use the fluent API directly:
Building Flows Fluently
var flow = new FlowBuilder()
.SetName("CustomerService")
.SetDescription("Main customer support flow")
.SetType(FlowType.ContactFlow)
.PlayPrompt(prompt =>
{
prompt.Text = "Welcome to customer service";
prompt.Voice = "Matthew";
})
.GetCustomerInput(input =>
{
input.Primary.Prompt = "Press 1 for sales, 2 for support";
input.MaxDigits = 1;
input.TimeoutSeconds = 5;
})
.RouteByInput(router => router
.When("sales", "1", sales => sales
.PlayPrompt("Connecting to sales")
.TransferToQueue("Sales")
.Disconnect())
.Otherwise(other => other
.TransferToQueue("General")
.Disconnect())
)
.Build();Queues
var queue = new QueueBuilder()
.SetName("SalesQueue")
.SetDescription("Sales department queue")
.SetMaxContacts(50)
.AddTag("Department", "Sales")
.Build();Hours of Operation
var hours = new HoursOfOperation
{
Name = "BusinessHours",
TimeZone = "America/New_York"
};
hours.AddDayConfig(new HoursOfOperationConfig
{
Day = DayOfWeek.Monday,
StartTime = new TimeRange { Hours = 8, Minutes = 0 },
EndTime = new TimeRange { Hours = 18, Minutes = 0 }
});FUTURE: Planned Attributes (Post-v1.0)
Phase 2: ContactFlow Definition
Planned for a future milestone — DO NOT use these yet; they don't exist:
// ❌ NOT IMPLEMENTED - DO NOT USE
[ContactFlow("SalesFlow", Description = "Sales inbound")]
public partial class SalesFlow : FlowDefinitionBase
{
[Message("Welcome to sales")]
public partial void Welcome();
[TransferToQueue("Sales")]
public partial void Transfer();
}Phase 2: Message Attributes
// ❌ NOT IMPLEMENTED - DO NOT USE
[Message("Hello world")]
public partial void PlayMessage();
[Message(ConfigKey = "welcomeMessage")]
public partial void PlayConfigurableMessage();Phase 2: Routing Attributes
// ❌ NOT IMPLEMENTED - DO NOT USE
[GetUserInput("Press 1 or 2", MaxDigits = 1)]
public partial Task<string> GetChoice();
[TransferToQueue("Support")]
public partial void TransferSupport();Phase 2: Queue Definition
// ❌ NOT IMPLEMENTED - DO NOT USE
[ContactFlow("MyFlow")]
[Queue("MyQueue", MaxContacts = 50)]
public partial class MyFlow { }Phase 2: Hours of Operation Attributes
// ❌ NOT IMPLEMENTED - DO NOT USE
[HoursOfOperation("BusinessHours", TimeZone = "America/New_York")]
[Weekday(DayOfWeek.Monday, "08:00", "18:00")]
public partial class MyFlow { }Phase 3+: Advanced Attributes
// ❌ NOT IMPLEMENTED - DO NOT USE
[CheckAttribute(Attribute = "CustomerType", Value = "VIP")]
[SetAttribute(Key = "PriorityLevel", Value = "High")]
[InvokeLambda(FunctionArn = "arn:...")]
[CheckHours(HoursName = "BusinessHours")]
[PlayPrompt(PromptUri = "s3://...")]
[Disconnect]Migration Path
Today (M1): Use the fluent API and [FlowAction] for extension methods.
Future (M2+): Attribute-based flow definitions will be available as the framework stabilizes.
See the roadmap for detailed phases.
See Also
- Source Generators - How attributes generate code
- Fluent API Guide - Current way to build flows
- Examples - Working code samples