redb.Route.Sql 3.4.0

Prefix Reserved
dotnet add package redb.Route.Sql --version 3.4.0
                    
NuGet\Install-Package redb.Route.Sql -Version 3.4.0
                    
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="redb.Route.Sql" Version="3.4.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="redb.Route.Sql" Version="3.4.0" />
                    
Directory.Packages.props
<PackageReference Include="redb.Route.Sql" />
                    
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 redb.Route.Sql --version 3.4.0
                    
#r "nuget: redb.Route.Sql, 3.4.0"
                    
#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 redb.Route.Sql@3.4.0
                    
#: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=redb.Route.Sql&version=3.4.0
                    
Install as a Cake Addin
#tool nuget:?package=redb.Route.Sql&version=3.4.0
                    
Install as a Cake Tool

redb.Route.Sql

SQL database transport for redb.Route. Pure ADO.NET polling consumer, query/batch producer, and stored procedure support. Provider-agnostic — works with PostgreSQL, SQL Server, SQLite, MySQL, and any DbConnection.

NuGet License: Apache 2.0

Installation

dotnet add package redb.Route.Sql

No additional dependencies — uses System.Data.Common abstractions only.

URI Format

One scheme — sql: — and the mode is chosen by the mode= parameter, not by the scheme.

sql:<sql-text-or-procedure-name>?mode=Poll|Execute|Procedure&dataSource=<name>&...
Mode Role Required
Execute (default) Producer — To(...) dataSource or connectionString
Procedure Producer — To(...) dataSource + procedureName
Poll Consumer — From(...) dataSource; mode=Poll is mandatory

The path is the SQL text itself and is taken verbatim (it is not URL-decoded), so it must not contain a ? — the parser splits on the first one.

Consumer — poll rows

From("sql:SELECT id, payload FROM outbox WHERE processed = 0"
    + "?mode=Poll"
    + "&dataSource=#main"
    + "&delay=5000"
    + "&maxMessagesPerPoll=100"
    + "&transacted=true"
    + "&onSuccess=UPDATE outbox SET processed = 1 WHERE id = @id")
    .Log("Processing outbox row ${header.id}")
    .To("direct://handle");

One Exchange per row; body is a Dictionary<string, object?>, and every column is also copied into headers — which is why onSuccess=... WHERE id = @id binds without any extra configuration.

Producer — execute a statement

From("direct://save")
    .To("sql:INSERT INTO audit(message, status) VALUES(@message, @status)"
        + "?dataSource=#main"
        + "&param.message=${body}"
        + "&param.status=${header.mode}");

Producer — call a stored procedure or function

// PostgreSQL function: SELECT maintain_partitions(@tbl, @keep_days)
From("direct://maintenance")
    .To("sql:maintain_partitions"
        + "?mode=Procedure"
        + "&dataSource=#main"
        + "&procedureName=maintain_partitions"
        + "&asFunction=true"
        + "&procedureParams=IN:tbl:String,IN:keep_days:Int32"
        + "&param.keep_days=90");

asFunction=true builds SELECT name(@p1, @p2, ...) from the IN/INOUT params in declaration order and executes it as a scalar — the result lands in the body. asFunction=false (default) uses CommandType.StoredProcedure (CALL/EXEC semantics of the driver) and executes non-query. OUT/INOUT values are written back into headers under their parameter names.

The procedure name must be given in procedureName=. The URI path is ignored in Procedure mode — it exists only so the parser has a non-empty path.

procedureParams format: DIR:name:DbType[:expression], comma-separated. DIR is IN, OUT or INOUT; DbType is a System.Data.DbType name (Int32, Int64, String, Decimal, …).

Batch

From("direct://bulk")
    .To("sql:INSERT INTO logs(message) VALUES(@message)?dataSource=#main&batchSize=500");

Batch mode engages only when the body is an IList. The statement runs once per element. breakBatchOnError=true stops at the first failure and rolls back; otherwise errors are collected into the redbSql.error header and the transaction commits.

Parameters and binding

SQL placeholders are @name only. There is no :name support, and there is no implicit @body — a scalar body (string, POCO) never binds itself into a parameter; use param.x=${body}.

Binding priority for each @name found in the statement:

# Source
0 param.<name>=... from the URI (constant or ${...} expression)
1 Exchange header with the same name
2 Body, if it is a Dictionary<string, object?> / IDictionary<string, object> — by key
3 (nothing matched)DBNull.Value, silently

In onFailure the special parameter @redbError resolves to exchange.Exception.Message.

In a poll consumer, param.* values are resolved without an Exchange — constants only, ${header...} expressions will not resolve there.

URI parameters

Names are the property names of SqlEndpointOptions, case-insensitive.

Parameter Type Default
mode Poll | Execute | Procedure Execute
dataSource registered data source name (a leading # is stripped)
connectionString / provider inline connection instead of dataSource
commandTimeout seconds 30
transacted consumer only — SELECT + onSuccess/onFailure in one transaction false
isolationLevel System.Data.IsolationLevel provider default
outputType Auto | SelectList | SelectOne | StreamList | Scalar | None Auto
noop skip execution (dry run) false
delay / initialDelay poll interval / first delay, ms 500 / 1000
fixedRate measure delay from cycle start false
repeatCount 0 = forever 0
maxMessagesPerPoll −1 = no limit -1
routeEmptyResultSet / sendEmptyMessageWhenIdle emit an Exchange on empty polls false
onSuccess / onFailure / onBatchComplete SQL run after each row / after a failed row / after the cycle
batchSize > 0 enables batch mode (flag, not a chunk size) 0
breakBatchOnError stop and roll back on the first batch error false
param.<name> explicit parameter value or ${...} expression
procedureName required for mode=Procedure
asFunction SELECT fn(...) instead of CALL/EXEC false
procedureParams DIR:name:DbType[:expr],…

outputType=Auto inspects the statement: SELECT/WITHSelectList, anything else → None (body untouched, only redbSql.updateCount is set).

outputClass and outputHeader are accepted by the option binder but not implemented — the result always goes to the body via DictionaryRowMapper. See docs/SQL_PROCEDURE_MODE_REGRESSION.md.

Headers written back

All prefixed with redbSql.: query, updateCount, rowCount, dataSource, outputType, error, transactionId, storedProcedure, executionTime (ms).

Transactions

Producers (Execute and Procedure) always open a local transaction when there is no ambient one — write atomicity does not need transacted=true, and the option is a no-op there. The consumer is the only place that reads transacted. A route-level .Transacted() wraps the pipeline in a TransactionScope; the connector then detects the ambient transaction, skips its local one, and enlists the connection.

Register data sources

DbProviderFactories.RegisterFactory("Npgsql", NpgsqlFactory.Instance);   // required

services.AddRedbRoute(route =>
{
    route.Services.AddRedbRouteSql(sql =>
    {
        sql.AddDataSource("main", opts =>
        {
            opts.ConnectionString = "Host=localhost;Database=demo;Username=postgres;Password=***";
            opts.ProviderName = "Npgsql";
        });

        sql.AddNamedQuery("pendingOrders", "SELECT * FROM orders WHERE processed = 0");
        // → "sql:ref:pendingOrders?mode=Poll&dataSource=#main"
    });
});

Inside a Tsak module the same thing without DI:

context.AddComponent(new SqlComponent());
context.AddToRegistry("main", (ISqlConnectionFactory)new SqlConnectionFactory(
    new SqlConnectionOptions { ConnectionString = conn, ProviderName = "Npgsql" }));

SqlConnectionOptions also carries ReadConnectionString (a replica used for read-only SELECTs), TestOnBorrow / ValidationQuery, and EnableRetryOnFailure / MaxRetries / RetryDelay.

Fluent DSL

Sql.Poll(...) / Sql.Execute(...) compile to exactly the URI strings above and are equivalent:

using redb.Route.Sql.Fluent;

From(Sql.Poll("SELECT * FROM orders WHERE processed = 0")
        .DataSource("main")
        .Delay(5000)
        .OnSuccess("UPDATE orders SET processed = 1 WHERE id = @id")
        .MaxMessagesPerPoll(100))
    .To("direct://handle");

Sql.Procedure(...) is currently broken: SqlBuilder.Build() does not emit procedureName, so the resulting URI fails validation. Use the string URI form shown above until this is fixed — see docs/SQL_PROCEDURE_MODE_REGRESSION.md.

Most builder methods (DataSource, CommandTimeout, Delay, InitialDelay, RepeatCount, MaxMessagesPerPoll, Batch, Param) accept both constants and IExpression for runtime resolution.

Part of

redb.Route — ESB & EIP Framework for .NET

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  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 (1)

Showing the top 1 NuGet packages that depend on redb.Route.Sql:

Package Downloads
redb.Tsak.Core

Kernel of redb.Tsak — runtime container for redb.Route contexts. Provides hot-reload module loading, REST management API, scheduler, monitoring, security and pluggable cluster bootstrap.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
3.4.0 49 7/27/2026
3.3.3 116 7/16/2026
3.3.2 94 7/14/2026
3.3.1 120 7/10/2026
3.3.0 95 7/8/2026
3.2.0 103 6/29/2026
3.1.0 139 6/6/2026
3.0.1 114 6/3/2026
3.0.0 113 5/29/2026
2.0.2 119 5/16/2026
2.0.0 105 5/6/2026