Train Discovery & Routing
This page covers the internal implementation of train discovery and routing. For the user-facing explanation of how to use the TrainBus, see Mediator overview.
TrainRegistry
The TrainRegistry scans the specified assemblies at startup for all types implementing IServiceTrain<TIn, TOut>. For each discovered train, it extracts the TIn type and builds a Dictionary<Type, Type> mapping input types to train types. Duplicate input types are silently skipped via TryAdd — the first registration wins.
TrainBus
When RunAsync<TOut>(input, parentMetadata?) is called, the TrainBus:
- Looks up the train type from the registry by
input.GetType() - Resolves the train from the DI container in a new scope
- Injects framework-level properties (
EffectRunner,Metadata, etc.) - Invokes the train's
Runmethod via reflection, passing the input and optional parent metadata for parent-child linking
Key Constraints and Design Decisions
Input Type Uniqueness
Each input type maps to exactly one train. When duplicate input types are found, the first registration wins — subsequent duplicates are silently skipped via TryAdd. See AddMediator for the full uniqueness rules and code examples.
Train Name Resolution
When looking up a train by name (e.g., via ITrainExecutionService), the system tries three matches in order:
- Canonical name —
ServiceType.FullName(the interface's fully-qualified name, e.g.MyApp.Trains.IProcessOrderTrain) - Friendly name —
ServiceTypeName(the display name from the registration) - Short name —
ServiceType.Name(the unqualified interface name, e.g.IProcessOrderTrain)
The canonical name is the preferred identifier. It is stable across implementation class renames and matches what is stored in metadata and work queue entries.
Train Discovery Rules
- Must be concrete classes (not abstract)
- Must implement IServiceTrain<,>
- Must have parameterless constructor or be registered in DI
- Should implement a non-generic interface for better DI integration
SDK Reference
> AddMediator | RunAsync | ITrainDiscoveryService | ITrainExecutionService