Trax.Mediator 1.23.1

Prefix Reserved
There is a newer version of this package available.
See the version list below for details.
dotnet add package Trax.Mediator --version 1.23.1
                    
NuGet\Install-Package Trax.Mediator -Version 1.23.1
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Trax.Mediator" Version="1.23.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Trax.Mediator" Version="1.23.1" />
                    
Directory.Packages.props
<PackageReference Include="Trax.Mediator" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Trax.Mediator --version 1.23.1
                    
#r "nuget: Trax.Mediator, 1.23.1"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Trax.Mediator@1.23.1
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Trax.Mediator&version=1.23.1
                    
Install as a Cake Addin
#tool nuget:?package=Trax.Mediator&version=1.23.1
                    
Install as a Cake Tool

Trax.Mediator

Build NuGet Version NuGet Downloads .NET License: MIT Last Commit codecov Docs

Dispatch station for Trax trains. Hand it the cargo and it routes it to the right train, no need to know which train handles what.

Trax is a .NET framework for writing business operations as trains: a ServiceTrain<TIn, TOut> runs a chain of junctions, and every run is recorded. Trax.Mediator adds the ITrainBus, which finds the train registered for an input's type and runs it, so callers depend on the input type rather than on a train class. It also scans assemblies to register trains, keeps the registry of known trains, enforces [TraxAuthorize] on trains, and caps concurrent runs.

dotnet add package Trax.Mediator
dotnet add package Trax.Effect.Data.InMemory   # or Trax.Effect.Data.Postgres

A minimal host: one train, registered by scanning, run through the bus.

using LanguageExt;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Trax.Core.Junction;
using Trax.Effect.Data.InMemory.Extensions;
using Trax.Effect.Extensions;
using Trax.Effect.Services.ServiceTrain;
using Trax.Mediator.Extensions;
using Trax.Mediator.Services.TrainBus;

var builder = Host.CreateApplicationBuilder(args);

builder.Services.AddTrax(trax =>
    trax.AddEffects(effects => effects.UseInMemory())
        .AddMediator(mediator => mediator.ScanAssemblies(typeof(Program).Assembly))
);

using var host = builder.Build();
await host.StartAsync(); // startup checks every train's chain and refuses to start on a bad one

using var scope = host.Services.CreateScope();
var trainBus = scope.ServiceProvider.GetRequiredService<ITrainBus>();

var greeting = await trainBus.RunAsync<Greeting>(new GreetRequest("Jane"));
Console.WriteLine(greeting.Message); // Hello, Jane!

public record GreetRequest(string Name);
public record Greeting(string Message);

// Every train needs its own interface; the bus resolves the train through it.
public interface IGreetTrain : IServiceTrain<GreetRequest, Greeting>;

public class GreetTrain : ServiceTrain<GreetRequest, Greeting>, IGreetTrain
{
    protected override Task<Either<Exception, Greeting>> Junctions() =>
        Chain<BuildGreetingJunction>().Resolve();
}

public class BuildGreetingJunction : Junction<GreetRequest, Greeting>
{
    public override Task<Greeting> Run(GreetRequest input) =>
        Task.FromResult(new Greeting($"Hello, {input.Name}!"));
}

ITrainBus is scoped, so resolve it from a scope (in ASP.NET Core, inject it into a controller or endpoint). The documentation is at traxsharp.net/docs.

The Trax Stack

Trax is a layered framework split across several repos. You can stop at whatever layer solves your problem. You are here: Trax.Mediator.

Repo Adds
Trax.Core Pipelines, junctions, railway error propagation
Trax.Effect Execution logging, DI, pluggable storage
Trax.Mediator Decoupled dispatch via TrainBus
Trax.Scheduler Cron schedules, retries, dead-letter queues
Trax.Api GraphQL API for remote access
Trax.Dashboard Blazor monitoring UI
Trax.Cli trax-cli project scaffolding tool
Trax.Samples Sample apps and a dotnet new template

Full documentation: traxsharp.net/docs.

The Problem

When one part of your system needs to send a train, it has to know exactly which train class to use. Controllers depend on concrete train types, stops that trigger other trains need direct references, and everything gets coupled together.

With TrainBus

TrainBus is a dispatch station. At startup it builds a map of what cargo goes on which train. To send something, you just drop off the cargo:

public class OrderController(ITrainBus trainBus) : ControllerBase
{
    [HttpPost]
    public async Task<IActionResult> Create(OrderRequest request)
    {
        var receipt = await trainBus.RunAsync<OrderReceipt>(request);
        return Ok(receipt);
    }
}

No reference to ProcessOrderTrain. The dispatch station looks at the cargo type and sends it on the right train.

Installation

dotnet add package Trax.Mediator

Trax.Mediator depends on Trax.Effect, which depends on Trax.Core. Both are pulled in transitively.

For tests, Trax.Mediator.Testing ships TrainGuards.EveryTrainHasInterface(assemblies), an architecture guard that lists every ServiceTrain missing its I{Name} interface:

dotnet add package Trax.Mediator.Testing

Setup

Register your train assemblies during startup. The dispatch station scans them for all IServiceTrain<TIn, TOut> implementations and builds the cargo-to-train map automatically:

builder.Services.AddTrax(trax =>
    trax.AddEffects(effects => effects.UsePostgres(connectionString))
        .AddMediator(typeof(Program).Assembly)
);

Multiple assemblies:

builder.Services.AddTrax(trax =>
    trax.AddEffects(effects => effects.UsePostgres(connectionString))
        .AddMediator(
            typeof(Program).Assembly,
            typeof(SomeTrainInAnotherProject).Assembly
        )
);

That's it. Every IServiceTrain<TIn, TOut> in those assemblies is now dispatchable through ITrainBus.

Usage

Dispatching a train

// With a return value: send cargo, get a delivery back
var user = await trainBus.RunAsync<User>(new CreateUserRequest
{
    Email = "jane@example.com",
    Name = "Jane"
});

// One-way: send cargo, no delivery expected
await trainBus.RunAsync(new SendNotificationRequest { UserId = userId });

Cancellation

var receipt = await trainBus.RunAsync<OrderReceipt>(request, cancellationToken);

The cancellation signal is forwarded to the train and all its stops.

Nested trains

A stop can dispatch another train mid-journey. The nested train records its own run, which is not linked to the outer one: the bus does not set its ParentId. Do not pass the current train's Metadata to try to link them; the metadata argument is for running as a pre-created Pending record, and a running train's metadata is refused with a TrainException.

public class SendWelcomeEmailJunction(ITrainBus trainBus) : Junction<User, Unit>
{
    public override async Task<Unit> Run(User input)
    {
        await trainBus.RunAsync(new SendEmailRequest
        {
            To = input.Email,
            Template = "welcome"
        });

        return Unit.Default;
    }
}

The departure board

The dispatch station exposes a registry of all known trains, which is useful for tooling and dashboards:

public class TrainListEndpoint(ITrainRegistry registry)
{
    public IEnumerable<string> GetTrainNames()
        => registry.InputTypeToTrain.Values.Select(t => t.Name);
}

How It Works

At startup, AddMediator scans the provided assemblies for types implementing IServiceTrain<TIn, TOut>. It builds a dictionary from cargo type (input) to train type and registers each train in the DI container. When you call RunAsync<TOut>(input), the dispatch station looks up input.GetType(), resolves the matching train from DI, and sends it on its way.

Next Layer

When you need recurring background jobs with retries and dead-lettering, move up to Trax.Scheduler.

License

MIT

Trademark & Brand Notice

Trax is an open-source .NET framework provided by TraxSharp. This project is an independent community effort and is not affiliated with, sponsored by, or endorsed by the Utah Transit Authority, Trax Retail, or any other entity using the "Trax" name in other industries.

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (5)

Showing the top 5 NuGet packages that depend on Trax.Mediator:

Package Downloads
Trax.Scheduler

Recurring and one-off scheduling for Trax .NET trains: cron and interval manifests, a durable work queue, retries, dead-lettering and dependent trains. Requires a persistent Trax data provider such as Trax.Effect.Data.Postgres.

Trax.Api

Core services behind the Trax .NET GraphQL API: health checks, per-train authorization, the HTTP principal provider and the shared DTOs. Trax.Api.GraphQL brings it in; reference it directly only to use those services without the GraphQL schema.

Trax.Api.Auth

Core principal abstraction (TraxPrincipal, ITraxPrincipalResolver) and claim-type constants shared by the Trax .NET auth schemes. The scheme packages bring it in; reference it directly to write a resolver or inject TraxPrincipal. NO WARRANTY. Trax auth is plumbing, not a security product. You are solely responsible for securing systems that use it. See SECURITY-DISCLAIMER.md.

Trax.Dashboard

Blazor Server operations dashboard for Trax .NET, mounted into your existing ASP.NET Core host at /trax: trains, run metadata and logs, scheduler manifests and groups, dead letters, the work queue, and runtime effect settings. Install it in the app that already calls AddTrax, then call builder.AddTraxDashboard() and app.UseTraxDashboard().

Trax.Api.GraphQL.Client.Trax

Trax .NET integration layer for Trax.Api.GraphQL.Client: AssemblySchemaProvider, GraphQLQueryJunction, log correlation, dashboard discovery.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.62.0 7 10/9/2026
1.61.0 298 10/6/2026
1.24.2 526 10/6/2026
1.24.1 756 10/4/2026
1.24.0 330 10/2/2026
1.23.3 340 10/1/2026
1.23.2 247 9/30/2026
1.23.1 209 9/29/2026
1.23.0 802 9/28/2026
1.22.1 700 9/24/2026
1.22.0 2,308 9/15/2026
1.21.0 1,408 8/13/2026
1.20.0 5,688 6/5/2026
1.19.0 649 6/2/2026
1.18.0 660 6/2/2026
1.17.0 4,217 5/4/2026
1.16.1 902 4/15/2026
1.16.0 767 4/15/2026
1.15.0 1,564 4/1/2026
1.14.1 929 3/19/2026
Loading failed