Install and configure CaeriusNet
This quickstart creates a .NET 10 / C# 14 client for a SQL Server 2022 or 2025 stored procedure. CaeriusNet calls only stored procedures; inline SQL is not a runtime feature.
Install
dotnet add package CaeriusNet --version 11.2.0CaeriusNet.Redis, CaeriusNet.Aspire and CaeriusNet.Contracts are optional packages. Install them only for their corresponding integration.
Build v12 with SDK 10.0.400 (patch roll-forward) and Roslyn 5.9 or later.
Register the database
using CaeriusNet;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCaeriusNet(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("Orders")!));For production, the configured connection string must use Encrypt=Strict;TrustServerCertificate=False and a server certificate trusted by the application host.
For more than one database, give each additional registration a key and request it with the standard keyed-service mechanism:
builder.Services.AddCaeriusNet("reporting", options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("Reporting")!));
public sealed class Reports(
[FromKeyedServices("reporting")] ICaeriusNetDbContext reporting)
{
}Create the stored procedure
CREATE PROCEDURE dbo.usp_User_ByMinimumAge
@Age int
AS
BEGIN
SET NOCOUNT ON;
SELECT Id, Name, Age
FROM dbo.Users
WHERE Age >= @Age
ORDER BY Id;
ENDSET NOCOUNT ON is recommended to reduce protocol noise. CaeriusNet also skips rowless frames, so it is not a hidden precondition for a multiple-result-set contract.
Map a row and call the procedure
Use the generator with [GenerateDto], or implement the static mapper contract explicitly:
using CaeriusNet;
using CaeriusNet.Abstractions;
using CaeriusNet.Commands;
using CaeriusNet.Mappers;
using Microsoft.Data.SqlClient;
using System.Data;
using System.Collections.ObjectModel;
public sealed record User(int Id, string Name, byte Age) : ISpMapper<User>
{
public static User MapFromDataReader(SqlDataReader reader) =>
new(reader.GetInt32(0), reader.GetString(1), reader.GetByte(2));
}
public sealed class UserRepository(ICaeriusNetDbContext database)
{
public ValueTask<ReadOnlyCollection<User>> GetAsync(byte age, CancellationToken ct)
{
var command = new StoredProcedureCommandBuilder("dbo", "usp_User_ByMinimumAge")
.AddParameter("Age", age, SqlDbType.TinyInt)
.Build();
return database.QueryReadOnlyCollectionAsync<User>(command, cancellationToken: ct);
}
}Parameter names may be passed with or without one @; use the same declared SqlDbType and supply size, precision or scale where the SQL contract needs it. Command validation happens before the connection opens.
Add a local cache
var command = new StoredProcedureCommandBuilder("dbo", "usp_User_ByMinimumAge")
.AddParameter("Age", age, SqlDbType.TinyInt)
.UseInMemoryCache(TimeSpan.FromMinutes(2), slidingExpiration: true)
.Build();Cache identity comes from the stored procedure contract, result shape and canonical input values. Do not invent a cache-key string at each call site.
