Call procedures from a client

Use SmartData.Client to invoke procedures over binary RPC.


SmartDataConnection wraps the binary RPC protocol. Build it with a connection string, OpenAsync once, then SendAsync per call.

Install

dotnet add package SmartData.Client

Minimal call

using SmartData.Client;

await using var conn = new SmartDataConnection(
    "Server=http://localhost:5124;User Id=admin;Password=secret");

await conn.OpenAsync();   // performs sp_login, stores the token

var response = await conn.SendAsync("usp_customer_list",
    new Dictionary<string, object>
    {
        ["Database"] = "master",
        ["Search"]   = "acme",
        ["Page"]     = 1,
        ["PageSize"] = 20,
    });

if (response.Success)
{
    var result = response.GetData<CustomerListResult>();
    foreach (var item in result.Items)
        Console.WriteLine($"{item.Id} {item.CompanyName}");
}
else
{
    Console.Error.WriteLine($"Error: {response.Error} (id={response.ErrorId}, severity={response.ErrorSeverity})");
}

Reusing a token

When you've already logged in elsewhere (e.g. a CLI persisted the token to disk), open with Token= instead of credentials. OpenAsync skips sp_login:

await using var conn = new SmartDataConnection(
    $"Server=http://localhost:5124;Token={persistedToken}");

await conn.OpenAsync();
// SendAsync will surface SmartDataException if the token has expired.

Token and User Id/Password are mutually exclusive — supplying both throws on OpenAsync.

DTOs — keep them matching by name

GetData<T>() deserialises by property name, case-insensitive. Your client-side CustomerListResult and CustomerItem need matching property names with the server's contracts — they don't need to be the same type or even in the same namespace.

Minimal client-side contract:

public class CustomerListResult
{
    public List<CustomerItem> Items { get; set; } = new();
    public int Total    { get; set; }
    public int Page     { get; set; }
    public int PageSize { get; set; }
}

public class CustomerItem
{
    public int    Id          { get; set; }
    public string CompanyName { get; set; } = "";
    public string Industry    { get; set; } = "";
}

Error handling

CommandResponse carries the server's ProcedureException details:

Field Meaning
Success true if the procedure returned; false if it threw
Error Message — from RaiseError when Success is false
ErrorId Integer message id (0–999 system, 1000+ user)
ErrorSeverity 0 = Error, 1 = Severe, 2 = Fatal
Authenticated Whether the token was valid

When Authenticated == false, SendAsync throws SmartDataException and the connection transitions to Broken. Open a new connection to recover.

Connection lifetime

SmartDataConnection is IAsyncDisposable. For a long-running app, hold one open connection and share it; for short-lived tools, await using ensures sp_logout runs on dispose. The setter on ConnectionString requires State == Closed — open one connection per credential pair.