Configuration & Dependency Injection
Learn how to configure the .NET Custody SDK with dependency injection, environment settings, and authentication options.
SDK-Only Access
To ensure your integration remains stable and supported, always use the official SDKs. The underlying API endpoints are internal implementation details that may change in purpose, functionality, or be removed at any time without notice. Direct API access is not supported. Learn more →
The SDK handles environment routing automatically — use the provided environment methods rather than targeting endpoints directly.
Basic Configuration
Register the Custody Client in your ASP.NET Core application's Program.cs:
using CoxAuto.Vecu.CustodySdk.DependencyInjection;
var builder = WebApplication.CreateBuilder(args);
// Register Custody Client with token provider
builder.Services.AddCustodyClient(options =>
{
options.Environment = CustodyEnvironment.Sandbox;
options.TokenProvider = async (cancellationToken) =>
{
var token = await myAuthClient.GetTokenAsync(cancellationToken);
return token.AccessToken;
};
});
var app = builder.Build();
Configuration Options
The SDK provides comprehensive configuration through CustodyClientOptions:
EnvironmentCustodyEnvironmentrequiredTarget environment (Sandbox, NonProd, PreProd, or Production). Defaults to Sandbox.
TokenProviderFunc<CancellationToken, Task<string>>requiredCallback that the SDK invokes to obtain a bearer token. Required unless UseMockData is true. The SDK exchanges this token for an internal service token automatically.
InitialTokenstringOptional initial bearer token to use before invoking TokenProvider. Useful when a token is already available at startup to avoid the first callback.
TimeoutSecondsintRequest timeout in seconds (1-300). Defaults to 30 seconds.
MaxRetriesintMaximum retry attempts for failed requests (0-10). Defaults to 3 retries with exponential backoff.
BaseUrlOverridestring?For local mock server testing only. The SDK automatically routes to the correct environment URL. Do not use this to target API endpoints directly.
EnableDetailedLoggingboolEnable detailed request/response logging. Not recommended for production due to performance impact.
UseMockDataboolEnable mock mode for testing without API calls. Returns realistic mock data. Defaults to false.
Environment Configuration
Available Environments
The SDK supports four environments, all using the same authentication model:
| Environment | Authentication | Use Case |
|---|---|---|
| Sandbox | Token Provider | Development & testing |
| NonProd | Token Provider | Integration testing |
| PreProd | Token Provider | Pre-production validation |
| Production | Token Provider | Live production |
Using Environment Presets
Configure for specific environments using the Environment property. All environments use the same TokenProvider callback:
// Sandbox
builder.Services.AddCustodyClient(options =>
{
options.Environment = CustodyEnvironment.Sandbox;
options.TokenProvider = async (ct) => await myAuthClient.GetTokenAsync(ct);
});
// NonProd
builder.Services.AddCustodyClient(options =>
{
options.Environment = CustodyEnvironment.NonProd;
options.TokenProvider = async (ct) => await myAuthClient.GetTokenAsync(ct);
});
// Production
builder.Services.AddCustodyClient(options =>
{
options.Environment = CustodyEnvironment.Production;
options.TokenProvider = async (ct) => await myAuthClient.GetTokenAsync(ct);
});
Authentication
Token Provider Callback
The SDK uses a single authentication model across all environments. You provide a TokenProvider callback that returns a bearer token (e.g., a CIP token from your auth system). The SDK then exchanges it internally for a VECU service token.
builder.Services.AddCustodyClient(options =>
{
options.Environment = CustodyEnvironment.Production;
options.TokenProvider = async (cancellationToken) =>
{
// Return a bearer token from your auth system (e.g., CIP token)
var token = await myAuthClient.GetTokenAsync(cancellationToken);
return token.AccessToken;
};
});
The CancellationToken parameter allows the SDK to cancel the token request
if the overall operation is cancelled. Always pass it through to your async
auth calls.
Initial Token (Optional)
If you already have a valid bearer token at startup (e.g., from a previous session), provide it as InitialToken to skip the first TokenProvider callback:
builder.Services.AddCustodyClient(options =>
{
options.Environment = CustodyEnvironment.Production;
options.TokenProvider = async (ct) => await myAuthClient.GetTokenAsync(ct);
options.InitialToken = cachedBearerToken; // Used until first refresh
});
When TokenProvider Is Called
The SDK calls your TokenProvider callback in these scenarios:
- First request — unless
InitialTokenis provided - Token refresh — when the cached VECU token expires (refreshed automatically 5 minutes before expiry)
- Stale client token — if the token exchange endpoint returns 401 or 410, the SDK clears the cached client token, calls
TokenProvideragain - API token rejection — if the Custody API returns 401, the SDK invalidates the cached VECU token and re-acquires from step 1
The VECU token is cached as a singleton — it is shared across all requests to your application. Your TokenProvider is only called when a new client token is actually needed, not on every request.
TokenProvider is required unless UseMockData = true. If neither is
configured, the SDK throws a validation error on startup.
Configuration from appsettings.json
Bind configuration from appsettings.json for better separation of concerns. Note that TokenProvider is a code callback and cannot be represented in JSON — it must be set in code:
{
"CustodyClient": {
"Environment": "Sandbox",
"TimeoutSeconds": 30,
"MaxRetries": 3,
"EnableDetailedLogging": false
}
}
Register with configuration binding and token provider:
builder.Services.AddCustodyClient(
builder.Configuration,
tokenProvider: async (cancellationToken) =>
{
var token = await myAuthClient.GetTokenAsync(cancellationToken);
return token.AccessToken;
});
Environment-Specific Configuration
Use different appsettings.{Environment}.json files for each environment:
appsettings.Development.json
{
"CustodyClient": {
"Environment": "Sandbox",
"EnableDetailedLogging": true
}
}
appsettings.Production.json
{
"CustodyClient": {
"Environment": "Production",
"TimeoutSeconds": 60,
"MaxRetries": 5,
"EnableDetailedLogging": false
}
}
Store any credentials used by your TokenProvider callback (client IDs, secrets, certificates) in Azure Key Vault, AWS Secrets Manager, or environment variables rather than committing them to source control.
Timeout & Retry Configuration
Configure resilience settings for production workloads:
builder.Services.AddCustodyClient(options =>
{
options.Environment = CustodyEnvironment.Production;
options.TokenProvider = async (ct) => await myAuthClient.GetTokenAsync(ct);
// Increase timeout for long-running operations
options.TimeoutSeconds = 60; // 1 minute
// More aggressive retry policy
options.MaxRetries = 5; // Retry up to 5 times
});
The SDK uses exponential backoff for retries with the following pattern:
- 1st retry: 2 seconds
- 2nd retry: 4 seconds
- 3rd retry: 8 seconds
- 4th retry: 16 seconds
- 5th retry: 32 seconds
Retries are only attempted for transient failures (network errors, 5xx server errors, rate limiting). Client errors (4xx) are not retried.
Advanced Configuration
Local Mock Server Testing
Override the base URL when testing against a local mock server:
builder.Services.AddCustodyClient(options =>
{
options.BaseUrlOverride = "http://localhost:8080";
options.TokenProvider = async (ct) => await myAuthClient.GetTokenAsync(ct);
});
Detailed Logging for Debugging
Enable detailed HTTP request/response logging:
builder.Services.AddCustodyClient(options =>
{
options.Environment = CustodyEnvironment.Sandbox;
options.TokenProvider = async (ct) => await myAuthClient.GetTokenAsync(ct);
options.EnableDetailedLogging = true; // Log all requests/responses
});
Detailed logging can impact performance and may log sensitive data. Only enable in development environments.
Mock Mode for Testing
Enable mock mode to return realistic test data without making API calls:
builder.Services.AddCustodyClient(options =>
{
options.Environment = CustodyEnvironment.Sandbox;
options.UseMockData = true; // No real API calls, no TokenProvider needed
});
When mock mode is enabled:
- No authentication required
- No network calls made
- Deterministic mock data returned
- In-memory state management for authorizations
See Testing for detailed mock mode usage.
Using the Client
Once registered, inject ICustodyServiceClient into your services:
public class VehicleCustodyService
{
private readonly ICustodyServiceClient _custodyClient;
public VehicleCustodyService(ICustodyServiceClient custodyClient)
{
_custodyClient = custodyClient;
}
public async Task<AuthorizationResponse> CreateAuthorizationAsync(
string vin,
string origin,
string destination)
{
var request = new CreateAuthorizationRequest
{
Vin = vin,
Origin = origin,
Destination = destination,
PersonIdentityKey = "DL-109-283-745",
MakeModel = "Toyota Camry",
AuthorizedBy = "SYSTEM",
Role = AuthorizationRole.DRIVER
};
return await _custodyClient.CreateAuthorizationAsync(request);
}
}
Next Steps
- ASP.NET Core Integration - Integrate with controllers and middleware
- Error Handling - Handle exceptions and errors
- Testing - Test with mock data and test utilities