The official Schematic C# library, supporting .NET Standard, .NET Core, and .NET Framework.
- Install the library using the .NET Core command-line interface (CLI) tools:
dotnet add package SchematicHQ.Clientor using the NuGet Command Line Interface (CLI):
nuget install SchematicHQ.Client-
Issue an API key for the appropriate environment using the Schematic app.
-
Using this secret key, initialize a client in your application:
using SchematicHQ;
Schematic schematic = new Schematic("YOUR_API_KEY")A number of these examples use keys to identify companies and users. Learn more about keys here.
Create or update users and companies using identify events.
using SchematicHQ.Client;
using System.Collections.Generic;
using OneOf;
Schematic schematic = new Schematic("YOUR_API_KEY");
schematic.Identify(
keys: new Dictionary<string, string>
{
{ "email", "wcoyote@acme.net" },
{ "user_id", "your-user-id" }
},
company: new EventBodyIdentifyCompany
{
Keys = new Dictionary<string, string> { { "id", "your-company-id" } },
Name = "Acme Widgets, Inc.",
Traits = new Dictionary<string, OneOf<string, double, bool, OneOf<string, double, bool>>>
{
{ "city", "Atlanta" }
}
},
name: "Wile E. Coyote",
traits: new Dictionary<string, OneOf<string, double, bool, OneOf<string, double, bool>>>
{
{ "login_count", 24 },
{ "is_staff", false }
}
);
// to guarantee that all events are sent before the application exits, call this method before your program shuts down
await schematic.Shutdown();This call is non-blocking and there is no response to check.
Track activity in your application using track events; these events can later be used to produce metrics for targeting.
Schematic schematic = new Schematic("YOUR_API_KEY");
schematic.Track(
eventName: "some-action",
user: new Dictionary<string, string> { { "user_id", "your-user-id" } },
company: new Dictionary<string, string> { { "id", "your-company-id" } }
);
// to guarantee that all events are sent before the application exits, call this method before your program shuts down
await schematic.Shutdown();This call is non-blocking and there is no response to check.
If you want to record large numbers of the same event at once, or perhaps measure usage in terms of a unit like tokens or memory, you can optionally specify a quantity for your event:
schematic.Track(
eventName: "some-action",
user: new Dictionary<string, string> { { "user_id", "your-user-id" } },
company: new Dictionary<string, string> { { "id", "your-company-id" } },
quantity: 10
);Although it is faster to create companies and users via identify events, if you need to handle a response, you can use the companies API to upsert companies. Because you use your own identifiers to identify companies, rather than a Schematic company ID, creating and updating companies are both done via the same upsert operation:
using SchematicHQ.Client;
using System.Collections.Generic;
using System.Threading.Tasks;
Schematic schematic = new Schematic("YOUR_API_KEY");
// Creating and updating companies
async Task UpsertCompanyExample()
{
var response = await schematic.Companies.UpsertCompanyAsync(new UpsertCompanyRequestBody
{
Keys = new Dictionary<string, string> { { "id", "your-company-id" } },
Name = "Acme Widgets, Inc.",
Traits = new Dictionary<string, object>
{
{ "city", "Atlanta" },
{ "high_score", 25 },
{ "is_active", true }
}
});
// Handle the response as needed
Console.WriteLine($"Company upserted: {response.Data.Name}");
}You can define any number of company keys; these are used to address the company in the future, for example by updating the company's traits or checking a flag for the company.
You can also define any number of company traits; these can then be used as targeting parameters.
Similarly, you can upsert users using the Schematic API, as an alternative to using identify events. Because you use your own identifiers to identify users, rather than a Schematic user ID, creating and updating users are both done via the same upsert operation:
using SchematicHQ.Client;
using System.Collections.Generic;
using System.Threading.Tasks;
Schematic schematic = new Schematic("YOUR_API_KEY");
// Creating and updating users
async Task UpsertUserExample()
{
var response = await schematic.Companies.UpsertUserAsync(new UpsertUserRequestBody
{
Keys = new Dictionary<string, string>
{
{ "email", "wcoyote@acme.net" },
{ "user_id", "your-user-id" }
},
Name = "Wile E. Coyote",
Traits = new Dictionary<string, object>
{
{ "city", "Atlanta" },
{ "high_score", 25 },
{ "is_active", true }
},
Company = new Dictionary<string, string> { { "id", "your-company-id" } }
});
// Handle the response as needed
Console.WriteLine($"User upserted: {response.Data.Name}");
}You can define any number of user keys; these are used to address the user in the future, for example by updating the user's traits or checking a flag for the user.
You can also define any number of user traits; these can then be used as targeting parameters.
When checking a flag, you'll provide keys for a company and/or keys for a user. You can also provide no keys at all, in which case you'll get the default value for the flag.
Schematic schematic = new Schematic("YOUR_API_KEY");
bool flagValue = await schematic.CheckFlag(
"some-flag-key",
company: new Dictionary<string, string> { { "id", "your-company-id" } },
user: new Dictionary<string, string> { { "user_id", "your-user-id" } }
);If you need more detail about how a flag check was resolved, including any entitlement associated with the check, use CheckFlagWithEntitlement. This returns a response object with the flag value, the reason for the evaluation result, and entitlement details such as usage, allocation, and credit balances when applicable.
Schematic schematic = new Schematic("YOUR_API_KEY");
var resp = await schematic.CheckFlagWithEntitlement(
"some-flag-key",
company: new Dictionary<string, string> { { "id", "your-company-id" } },
user: new Dictionary<string, string> { { "user_id", "your-user-id" } }
);
Console.WriteLine($"Flag: {resp.FlagKey}, Value: {resp.Value}, Reason: {resp.Reason}");
if (resp.Entitlement != null)
{
Console.WriteLine($"Entitlement type: {resp.Entitlement.ValueType}");
Console.WriteLine($"Usage: {resp.Entitlement.Usage}, Allocation: {resp.Entitlement.Allocation}");
Console.WriteLine($"Credit remaining: {resp.Entitlement.CreditRemaining}");
}The CheckFlags method allows you to efficiently check multiple feature flags in a single operation. When you provide specific flag keys, it will only return the flag values for those flags, leveraging intelligent caching to minimize API calls.
Schematic schematic = new Schematic("YOUR_API_KEY");
var company = new Dictionary<string, string> { { "id", "your-company-id" } };
// Check specific flags by providing an array of flag keys
var results = await schematic.CheckFlags(
company: company,
keys: new[] { "feature-flag-1", "feature-flag-2", "feature-flag-3" }
);
foreach (var result in results)
{
Console.WriteLine($"Flag {result.Flag}: {result.Value} ({result.Reason})");
if (result.Value)
{
// This flag is enabled
}
else
{
// This flag is disabled
}
}
// Or check all available flags by omitting the keys parameter
var allResults = await schematic.CheckFlags(company: company);
foreach (var result in allResults)
{
Console.WriteLine($"Flag {result.Flag}: {result.Value}");
}The Schematic .NET SDK includes built-in support for OpenFeature, allowing you to use Schematic's feature flags through the OpenFeature standard API.
using OpenFeature;
using SchematicHQ.Client.OpenFeature;
// Create and set the Schematic provider
var provider = new SchematicProvider("YOUR_API_KEY");
await Api.Instance.SetProviderAsync(provider);
// Get the OpenFeature client
var client = Api.Instance.GetClient();
// Evaluate a boolean feature flag
var isEnabled = await client.GetBooleanValue("your-flag-key", false);The Schematic provider supports company and user context through OpenFeature's evaluation context:
var context = EvaluationContext.Builder()
.Set("company", new Structure(new Dictionary<string, Value>
{
["id"] = new Value("company-123"),
["name"] = new Value("Acme Corp"),
["plan"] = new Value("enterprise")
}))
.Set("user", new Structure(new Dictionary<string, Value>
{
["id"] = new Value("user-456"),
["email"] = new Value("user@example.com"),
["role"] = new Value("admin")
}))
.Build();
// Evaluate with context
var isEnabled = await client.GetBooleanValue("your-flag-key", false, context);The provider includes a method to track events:
var provider = (SchematicProvider)Api.Instance.GetProvider();
await provider.TrackEventAsync(
"button_clicked",
context,
new Dictionary<string, object>
{
["button_name"] = "submit",
["page"] = "checkout"
}
);For features metered by credit burndown (for example inference tokens), Check reserves credits for the work about to run and TrackWithReservation settles the reservation with actual usage. The SDK gates in one of two modes:
- Client mode acquires a lease, a tranche of credits held against the company's balance, and carves a per-request reservation out of it locally, so a check needs no API call. It requires Datastream (or Replicator Mode) and, across multiple processes, a shared Redis so every instance gates against the same lease.
- Server mode makes one
check-and-reserveAPI call per check. No lease, no Redis, no local state.
CreditLeases.Mode defaults to Auto: client when the datastream is running, server otherwise. A datastream that fails to start counts as server, since there is no local engine behind the gate. Client mode suits high-throughput gating; server mode suits low-volume checks and operations that run for seconds.
using SchematicHQ.Client;
using SchematicHQ.Client.Datastream;
using SchematicHQ.Client.Leases;
var options = new ClientOptions
{
UseDatastream = true,
CreditLeases = new CreditLeaseConfig
{
DefaultLeaseSize = 10_000, // credits requested per lease
DefaultLeaseDuration = TimeSpan.FromMinutes(5), // lease lifetime
DefaultReservationTTL = TimeSpan.FromSeconds(60) // how long a reservation is held if no track settles it
}
}.WithRedisCache(new RedisCacheConfig { Configuration = "localhost:6379" });
Schematic schematic = new Schematic("YOUR_API_KEY", options);The Redis the cache is configured with also backs lease and reservation state. Set CreditLeases.RedisConfig (or CreditLeases.RedisClient, for a connection you own) to keep lease state in a different Redis.
Server mode needs only a TTL:
var options = new ClientOptions
{
CreditLeases = new CreditLeaseConfig
{
// How long the server holds the credits if no track settles them. One hour is the maximum.
DefaultReservationTTL = TimeSpan.FromSeconds(60)
}
};
Schematic schematic = new Schematic("YOUR_API_KEY", options);Only Mode and DefaultReservationTTL apply in server mode; the SDK warns at startup if a client-only option is set.
var company = new Dictionary<string, string> { { "id", "your-company-id" } };
// Reserve up to maxTokens for this operation.
var result = await schematic.Check(
"inference",
company: company,
options: new CheckOptions
{
Usage = maxTokens, // upper bound for this operation
EventSubtype = "inference_tokens" // the metered event
}
);
if (!result.Allowed)
{
throw new InvalidOperationException("credit balance exceeded");
}
var inference = await RunInference();
// Report actual usage; the unused slice of the reservation is refunded.
if (result.Reservation != null)
{
await schematic.TrackWithReservation(result.Reservation, inference.TokensUsed);
}
else
{
schematic.Track("inference_tokens", company: company, quantity: inference.TokensUsed);
}Usage may be fractional, but a fraction of an event is not something the server bills, so everything that moves credits rounds up to whole units. A client-mode reservation holds ceil(Usage) times the consumption rate, and a settle debits ceil of the actual quantity, so the local ledger moves by exactly what the track event charges. The preflight quantity and the quantity a track event bills round the same way. A check for 2.5 units at a rate of 10 holds 30 credits and bills 3 units, while the reservation still records the Usage the caller declared.
A check can allow without reserving credits (the feature is not credit-metered, Usage is 0, or the check failed open), and that usage still has to be tracked.
An unsettled reservation expires after DefaultReservationTTL and its credits return to the lease. A late settle still bills the usage (the track event carries a deterministic idempotency key, so it never double-bills) but does not re-debit the local lease, so set DefaultReservationTTL above the longest expected gap between Check and TrackWithReservation.
Pre-warm leases when the user is identified, so a session's first check does not wait on a lease acquire:
schematic.Identify(
keys: new Dictionary<string, string> { { "user_id", "your-user-id" } },
company: new EventBodyIdentifyCompany
{
Keys = new Dictionary<string, string> { { "id", "your-company-id" } }
},
options: new IdentifyOptions
{
Prewarm = new List<string> { "credit-type-id" } // credit type IDs to acquire leases for
}
);Or call schematic.Prewarm(company, creditTypeIds) directly. Both are no-ops in server mode.
Pre-warming resolves the company the way the server does: it looks the keys up first, whatever they are named, and only when nothing matches does it read a value carrying Schematic's comp_ prefix as the company id.
An Identify that carries Prewarm flushes the event buffer so the company exists before the lease acquire asks for it, which makes it a call to place once at the start of a session rather than on every event.
A check that cannot be gated (API unreachable, Redis down, lease exhausted) fails closed by default. Override per check:
var result = await schematic.Check(
"inference",
company: company,
options: new CheckOptions
{
Usage = maxTokens,
EventSubtype = "inference_tokens",
OnAcquireFailure = OnAcquireFailure.FailOpen
}
);In client mode, FailOpen still evaluates the flag's rules with the credit balance assumed sufficient, so plan targeting and all non-credit conditions apply and only the credit gate is bypassed. In server mode it returns the flag's default value, which is false unless you pass CheckOptions.DefaultValue or configure a FlagDefaults entry.
In server mode, a check that times out after the server has already reserved leaves those credits reserved until the TTL expires, so keep DefaultReservationTTL short there.
See Credit Lease Options for the full set of knobs.
Schematic can send webhooks to notify your application of events. To ensure the security of these webhooks, Schematic signs each request using HMAC-SHA256. The .NET SDK provides utility functions to verify these signatures.
When your application receives a webhook request from Schematic, you should verify its signature to ensure it's authentic:
using SchematicHQ.Client.Webhooks.WebhookUtils;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
[ApiController]
[Route("api/[controller]")]
public class WebhooksController : ControllerBase
{
[HttpPost("schematic")]
public async Task<IActionResult> HandleSchematicWebhook()
{
try
{
// Read the request body
string body;
using (var reader = new StreamReader(Request.Body))
{
body = await reader.ReadToEndAsync();
}
// Extract headers into a dictionary
var headers = new Dictionary<string, string>();
foreach (var header in Request.Headers)
{
headers[header.Key] = header.Value;
}
// Each webhook has a distinct secret; you can access this via the Schematic app
string webhookSecret = "your-webhook-secret";
// Verify the webhook signature
WebhookVerifier.VerifyWebhookSignature(body, headers, webhookSecret);
// Process the webhook payload
// ...
return Ok();
}
catch (WebhookSignatureException ex)
{
// Handle signature verification failure
return Unauthorized(new { error = ex.Message });
}
catch (Exception ex)
{
// Handle other errors
return StatusCode(500, new { error = "Internal server error" });
}
}
}If you need to verify a webhook signature outside of the context of an HTTP request, you can use the VerifySignature method:
using SchematicHQ.Client.Webhooks.WebhookUtils;
public bool VerifyWebhookManually(string body, string signature, string timestamp, string secret)
{
try
{
WebhookVerifier.VerifySignature(body, signature, timestamp, secret);
Console.WriteLine("Signature verification successful!");
return true;
}
catch (WebhookSignatureException ex)
{
Console.WriteLine($"Signature verification failed: {ex.Message}");
return false;
}
}There are a number of configuration options that can be specified by passing ClientOptions as a second parameter when instantiating the Schematic client.
The recommended way to configure caching is through the fluent helpers on ClientOptions or by setting ClientOptions.CacheConfiguration directly.
By default an in-memory cache will be configured, but you can customize it further if required:
using SchematicHQ.Client;
var options = new ClientOptions()
.WithLocalCache(capacity: 10000, ttl: TimeSpan.FromSeconds(1));
Schematic schematic = new Schematic("YOUR_API_KEY", options);If you prefer to configure it explicitly, you can set CacheConfiguration yourself:
using SchematicHQ.Client;
using SchematicHQ.Client.Cache;
var options = new ClientOptions
{
CacheConfiguration = new CacheConfiguration
{
ProviderType = CacheProviderType.Local,
LocalCacheCapacity = 10000,
CacheTtl = TimeSpan.FromSeconds(1)
}
};You can also disable local caching entirely; bear in mind that, in this case, every flag check will result in a network request:
using SchematicHQ.Client;
var options = new ClientOptions()
.WithLocalCache(capacity: 0);
Schematic schematic = new Schematic("YOUR_API_KEY", options);For distributed applications or when you want cache persistence across application restarts, use Redis:
using SchematicHQ.Client;
using SchematicHQ.Client.Cache;
var options = new ClientOptions()
.WithRedisCache(new RedisCacheConfig
{
Configuration = "redis.example.com:6379",
KeyPrefix = "schematic:",
Database = 0,
CacheTTL = TimeSpan.FromMinutes(5)
});
Schematic schematic = new Schematic("YOUR_API_KEY", options);If you need more control over the connection, supply a ConfigurationOptions instance or a ConnectionMultiplexerFactory:
using SchematicHQ.Client;
using SchematicHQ.Client.Cache;
using StackExchange.Redis;
var redisOptions = ConfigurationOptions.Parse("redis-primary.example.com:6379,redis-replica.example.com:6379");
redisOptions.AbortOnConnectFail = false;
redisOptions.Ssl = true;
var options = new ClientOptions()
.WithRedisCache(new RedisCacheConfig
{
ConfigurationOptions = redisOptions,
KeyPrefix = "schematic:",
Database = 0,
CacheTTL = TimeSpan.FromMinutes(10)
});If you want to provide your own cache backend, implement ICacheProvider and assign it to ClientOptions.CacheProvider:
using SchematicHQ.Client;
using SchematicHQ.Client.Cache;
public sealed class MyCustomCache : ICacheProvider
{
// ...
}
var options = new ClientOptions
{
CacheProvider = new MyCustomCache()
};
var schematic = new Schematic("YOUR_API_KEY", options);Custom caches are useful if you need specialized eviction, a different backing store, or additional observability around cache access.
You may want to specify default flag values for your application, which will be used if there is a service interruption or if the client is running in offline mode (see below):
using SchematicHQ.Client;
using System.Collections.Generic;
var options = new ClientOptions
{
FlagDefaults = new Dictionary<string, bool>
{
{ "some-flag-key", true }
}
};
Schematic schematic = new Schematic("YOUR_API_KEY", options);In development or testing environments, you may want to avoid making network requests to the Schematic API. You can run Schematic in offline mode by specifying the Offline option; in this case, it does not matter what API key you specify:
using SchematicHQ.Client;
var options = new ClientOptions
{
Offline = true
};
Schematic schematic = new Schematic("", options); // API key doesn't matter in offline modeOffline mode works well with flag defaults:
using SchematicHQ.Client;
using System.Collections.Generic;
var options = new ClientOptions
{
FlagDefaults = new Dictionary<string, bool>
{
{ "some-flag-key", true }
},
Offline = true
};
Schematic schematic = new Schematic("", options);
bool flagValue = await schematic.CheckFlag("some-flag-key"); // Returns trueYou can also set flag defaults dynamically after the client has been constructed using SetFlagDefault and SetFlagDefaults. This is useful in automated testing contexts, where you may want to specify per-test flag values:
using SchematicHQ.Client;
using System.Collections.Generic;
var options = new ClientOptions { Offline = true };
Schematic schematic = new Schematic("", options);
// Set a single flag default
schematic.SetFlagDefault("some-flag-key", true);
// Or set multiple flag defaults at once
schematic.SetFlagDefaults(new Dictionary<string, bool>
{
{ "some-flag-key", true },
{ "another-flag-key", false }
});
bool flagValue = await schematic.CheckFlag("some-flag-key"); // Returns trueSchematic API uses an Event Buffer to batch Identify and Track requests and avoid multiple API calls. You can set the event buffer flush period in options:
using SchematicHQ.Client;
var options = new ClientOptions
{
DefaultEventBufferPeriod = TimeSpan.FromSeconds(5)
};You may also want to use your custom event buffer. To do so, your custom event buffer has to implement IEventBuffer interface, and pass an instance to the Schematic API through options:
using SchematicHQ.Client;
var options = new ClientOptions
{
EventBuffer = new MyCustomEventBuffer();//instance of your custom event buffer
}You can override the HttpClient:
schematic = new Schematic("YOUR_API_KEY", new ClientOptions{
HttpClient = ... // Override the Http Client
BaseURL = ... // Override the Base URL
})429 Rate Limit, and >=500 Internal errors will all be retried twice with exponential backoff. You can override this behavior globally or per-request.
var schematic = new Schematic("...", new ClientOptions{
MaxRetries = 1 // Only retry once
});The SDK defaults to a 60s timeout. You can override this behaviour globally or per-request.
var schematic = new Schematic("...", new ClientOptions{
TimeoutInSeconds = 20 // Lower timeout
});ClientOptions.CreditLeases enables credit reservation behavior on Check and TrackWithReservation. Omit it to keep the client credit-unaware. See Credit Leases and Reservations for the flow these knobs steer.
| Option | Type | Default | Description |
|---|---|---|---|
Mode |
CreditLeaseMode |
Auto |
Where credits are reserved; Auto picks client mode when datastream is enabled, server mode otherwise |
DefaultReservationTTL |
TimeSpan? |
60 seconds | How long an unsettled reservation is held |
DefaultLeaseDuration |
TimeSpan? |
5 minutes | (client mode) Lease lifetime |
DefaultLeaseSize |
double? |
10000 | (client mode) Credits requested per lease acquire or extend |
LowWaterMark |
double? |
0.25 | (client mode) Extend in the background when the lease balance dips below this fraction |
SweepInterval |
TimeSpan? |
1 second | (client mode) Sweep interval for expired reservations |
PrewarmResolveTimeout |
TimeSpan? |
5 seconds | (client mode) How long Prewarm waits for a freshly identified company to surface; zero resolves from the datastream cache only |
RedisClient |
ILeaseRedis? |
the cache's Redis | (client mode) A Redis backend you already hold, for lease and reservation state |
RedisConfig |
RedisCacheConfig? |
CacheConfiguration.RedisConfig |
(client mode) Connection settings the SDK builds a lease backend from |
RedisKeyPrefix |
string? |
the cache's key prefix | (client mode) Key prefix for lease and reservation keys |
Overrides |
Dictionary<string, LeaseOverride>? |
none | (client mode) Per-credit-type overrides of the four knobs above, keyed by credit type ID |
Without a Redis backend the SDK keeps lease and reservation state per process, which loses cross-pod gating, and warns at startup.
When the API returns a non-zero status code, (4xx or 5xx response), a subclass of SchematicException will be thrown:
using SchematicHQ;
try {
schematic.Accounts.ListApiKeysAsync(...);
} catch (SchematicException e) {
System.Console.WriteLine(e.Message)
System.Console.WriteLine(e.StatusCode)
}Datastream is Schematic's real-time connection service that optimizes flag check performance and reliability. When enabled, the Schematic client maintains a WebSocket connection to our servers, which pushes down feature flag definitions, company data, and user data as needed.
- Improved Performance: Flag checks become near-instantaneous after the initial data load
- Reduced API Load: Minimizes HTTP requests to the Schematic API
- Real-time Updates: Flag changes are immediately pushed to your application
- Fault Tolerance: Falls back to standard API requests when needed
Important: Datastream is disabled by default. You must explicitly enable it in your client options:
using SchematicHQ.Client;
// Create options with Datastream enabled
var options = new ClientOptions
{
UseDatastream = true // Enable Datastream
};
// Initialize client with options
var schematic = new Schematic("YOUR_API_KEY", options);You can customize Datastream's behavior through additional client options:
using SchematicHQ.Client;
using SchematicHQ.Client.Cache;
using SchematicHQ.Client.Datastream;
var options = new ClientOptions
{
UseDatastream = true,
DatastreamOptions = new DatastreamOptions
{
CacheTTL = TimeSpan.FromMinutes(10)
}
};
var schematic = new Schematic("YOUR_API_KEY", options);DatastreamOptions currently controls Datastream-specific TTL behavior; the cache provider itself still comes from ClientOptions.CacheConfiguration (or CacheProvider for custom implementations).
The flag checking experience remains the same whether Datastream is enabled or not:
// Check a feature flag with Datastream enabled
bool flagValue = await schematic.CheckFlag(
"premium-feature",
company: new Dictionary<string, string> { { "id", "company-123" } },
user: new Dictionary<string, string> { { "email", "user@example.com" } }
);
// Use the flag result
if (flagValue) {
// Enable premium feature
} else {
// Use standard feature
}The difference is that with Datastream enabled, after the initial data load, subsequent flag checks for the same company and user will be nearly instantaneous and won't require additional network requests.
Replicator mode is an advanced Datastream configuration that maintains a local replica of your Schematic data using a persistent cache layer. This mode provides enhanced performance and reliability for high-throughput applications.
using SchematicHQ.Client;
using SchematicHQ.Client.Cache;
using SchematicHQ.Client.Datastream;
var options = new ClientOptions()
.WithRedisCache(new RedisCacheConfig
{
Configuration = "localhost:6379",
KeyPrefix = "schematic:",
CacheTTL = TimeSpan.FromHours(24)
})
.WithReplicatorMode(); // health checks http://localhost:8090/ready
var schematic = new Schematic("YOUR_API_KEY", options);In replicator mode the client polls the replicator's health endpoint every 30 seconds to learn whether it is ready and which cache version to read. If you don't set a health URL, it uses http://localhost:8090/ready, the same default as the other Schematic SDKs. This applies whether you call .WithReplicatorMode() or set ReplicatorMode = true directly and leave ReplicatorHealthUrl unset (null, empty or whitespace). To point at a replicator elsewhere, pass its URL, .WithReplicatorMode("http://my-replicator:8090/ready"), or set ReplicatorHealthUrl. An explicit URL always takes precedence. Passing an empty or whitespace string to .WithReplicatorMode(url) throws an ArgumentException; call the overload with no arguments to use the default.
using SchematicHQ.Client;
using SchematicHQ.Client.Cache;
using SchematicHQ.Client.Datastream;
using StackExchange.Redis;
var redisOptions = ConfigurationOptions.Parse("redis-primary.example.com:6379,redis-replica.example.com:6379");
redisOptions.AbortOnConnectFail = false;
redisOptions.Ssl = true;
var options = new ClientOptions()
.WithRedisCache(new RedisCacheConfig
{
ConfigurationOptions = redisOptions,
KeyPrefix = "schematic:",
CacheTTL = TimeSpan.FromHours(24)
})
.WithReplicatorMode("https://health.your-app.com/schematic-replicator");
var schematic = new Schematic("YOUR_API_KEY", options);| Configuration Method | Description | Example |
|---|---|---|
.WithReplicatorMode() |
Enables replicator mode with the default health check URL, http://localhost:8090/ready |
|
.WithReplicatorMode(url) |
Enables replicator mode and sets the health check endpoint URL | "https://health.example.com/replicator" |
ReplicatorHealthUrl |
Health check endpoint URL. Defaults to http://localhost:8090/ready in replicator mode when unset |
"http://my-replicator:8090/ready" |
.WithRedisCache(config) |
Configures Redis as the cache provider for replicator data | Required for replicator mode |
RedisCacheConfig.KeyPrefix |
Prefix for every Redis key. In replicator mode this must be schematic: (the default): the replicator writes schematic:flags:..., schematic:company:... and schematic:user:... and has no prefix setting, so any other value makes every lookup miss |
"schematic:" |
While we value open-source contributions to this SDK, this library is generated programmatically. Additions made directly to this library would have to be moved over to our generation code, otherwise they would be overwritten upon the next generated release. Feel free to open a PR as a proof of concept, but know that we will not be able to schematic it as-is. We suggest opening an issue first to discuss with us!
On the other hand, contributions to the README are always very welcome!