![]() |
VOOZH | about |
dotnet add package TAF.CRUD.SDK --version 6.0.9
NuGet\Install-Package TAF.CRUD.SDK -Version 6.0.9
<PackageReference Include="TAF.CRUD.SDK" Version="6.0.9" />
<PackageVersion Include="TAF.CRUD.SDK" Version="6.0.9" />Directory.Packages.props
<PackageReference Include="TAF.CRUD.SDK" />Project file
paket add TAF.CRUD.SDK --version 6.0.9
#r "nuget: TAF.CRUD.SDK, 6.0.9"
#:package TAF.CRUD.SDK@6.0.9
#addin nuget:?package=TAF.CRUD.SDK&version=6.0.9Install as a Cake Addin
#tool nuget:?package=TAF.CRUD.SDK&version=6.0.9Install as a Cake Tool
Official .NET SDK for consuming TAF.CRUD microservice. Provides both synchronous and asynchronous CRUD operations with a fluent query builder API.
dotnet add package TAF.CRUD.SDK
Register both clients with a single method:
using TAF.CRUD.SDK.Extensions;
// Register both Sync and Async clients
builder.Services.AddCRUDClient(
// Sync client (with retry options)
syncOptions =>
{
syncOptions.BaseUrl = "https://api.example.com";
syncOptions.TimeoutSeconds = 30;
syncOptions.MaxRetryAttempts = 3;
syncOptions.RetryDelayMs = 1000;
syncOptions.ApiKey = "your-api-key";
},
// Async client (fire-and-forget)
asyncOptions =>
{
asyncOptions.BaseUrl = "https://api.example.com";
asyncOptions.TimeoutSeconds = 30;
asyncOptions.ApiKey = "your-api-key";
}
);
// Or register only Sync client
builder.Services.AddCRUDClient(
syncOptions => { syncOptions.BaseUrl = "https://api.example.com"; }
);
// Or register only Async client
builder.Services.AddCRUDClient(
asyncConfigure: asyncOptions => { asyncOptions.BaseUrl = "https://api.example.com"; }
);
Use for traditional request-response operations:
public class OrderService
{
private readonly SyncCRUDClient _client;
public OrderService(SyncCRUDClient client)
{
_client = client;
}
public async Task<Guid> CreateOrderAsync(string orderNumber, decimal amount)
{
var context = new Context
{
TenantId = Guid.Parse("tenant-id"),
AppId = Guid.Parse("app-id"),
EnvironmentId = Guid.Parse("env-id"),
UserId = Guid.Parse("user-id")
};
var orderId = await _client
.Query("Orders")
.Insert(new Dictionary<string, object>
{
["OrderNumber"] = orderNumber,
["Amount"] = amount,
["OrderDate"] = DateTime.UtcNow
})
.WithContext(context)
.ExecuteAsync();
return orderId; // Actual GUID returned immediately
}
public async Task<List<Dictionary<string, object>>> GetActiveOrdersAsync()
{
return await _client
.Query("Orders")
.Where(filter => filter
.And(c => c.Field("IsActive").EqualTo(true))
.And(c => c.Field("Amount").GreaterThan(100)))
.WithContext(context)
.ToListAsync();
}
public async Task<int> UpdateOrderAsync(Guid orderId, string status)
{
return await _client
.Query("Orders")
.Where(filter => filter.And(c => c.Field("Id").EqualTo(orderId)))
.WithContext(context)
.UpdateAsync(new Dictionary<string, object>
{
["Status"] = status,
["UpdatedDate"] = DateTime.UtcNow
});
}
public async Task<int> DeleteOldOrdersAsync()
{
return await _client
.Query("Orders")
.Where(filter => filter
.And(c => c.Field("OrderDate").LessThan(DateTime.UtcNow.AddYears(-1))))
.WithContext(context)
.DeleteAsync();
}
}
Use for microservice-to-microservice communication with event-driven results:
public class AsyncOrderService
{
private readonly AsyncCRUDClient _client;
public AsyncOrderService(AsyncCRUDClient client)
{
_client = client;
}
public async Task<Guid> CreateOrderAsync(string orderNumber, decimal amount)
{
var context = new Context
{
TenantId = Guid.Parse("tenant-id"),
AppId = Guid.Parse("app-id"),
EnvironmentId = Guid.Parse("env-id"),
UserId = Guid.Parse("user-id"),
// Pass metadata to event consumers
Properties = new Dictionary<string, object>
{
["OrderType"] = "StandardOrder",
["Source"] = "OrderService"
}
};
// Fire-and-forget: Returns CorrelationId immediately
var correlationId = await _client
.Query("Orders")
.Insert(new Dictionary<string, object>
{
["OrderNumber"] = orderNumber,
["Amount"] = amount
})
.WithContext(context)
.ExecuteAsync();
// Actual result arrives via RabbitMQ RecordInsertedEvent
return correlationId;
}
}
Consume RabbitMQ events to get operation results:
using TAF.CRUD.Domain.Events;
using MassTransit;
public class OrderInsertedEventConsumer : IConsumer<RecordInsertedEvent>
{
public async Task Consume(ConsumeContext<RecordInsertedEvent> context)
{
var @event = context.Message;
if (@event.EntityName != "Orders") return;
// Access custom metadata
var orderType = @event.Properties.GetValueOrDefault("OrderType")?.ToString();
if (@event.IsSuccess)
{
// @event.RecordId contains the new order's GUID
// @event.Properties contains your custom metadata
// Process successful creation
}
else
{
// Handle failure: @event.ErrorMessage, @event.ErrorCode
}
}
}
// Simple conditions
.Where(filter => filter.And(c => c.Field("Status").EqualTo("Active")))
// Multiple conditions
.Where(filter => filter
.And(c => c.Field("Status").EqualTo("Active"))
.And(c => c.Field("Amount").GreaterThan(1000))
.Or(c => c.Field("Priority").EqualTo("High")))
// Grouped conditions
.Where(filter => filter
.And(c => c.Field("IsActive").EqualTo(true))
.AndGroup(nested => nested
.And(c => c.Field("Status").EqualTo("Pending"))
.Or(c => c.Field("Status").EqualTo("InProgress"))))
// Conditional filtering
.Where(filter => filter
.And(c => c.Field("IsActive").EqualTo(true))
.AndIf(includeExpensive, c => c.Field("Price").GreaterThan(1000)))
Comparison: EqualTo, NotEqualTo, GreaterThan, GreaterThanOrEqualTo, LessThan, LessThanOrEqualTo
String: Contains, NotContains, StartsWith, NotStartsWith, EndsWith, NotEndsWith
List: In, NotIn
Range: Between, NotBetween
Null: IsNull, IsNotNull
// Select specific fields
.Select("OrderNumber", "Amount", "OrderDate")
// Ordering
.OrderBy("OrderDate")
.OrderByDescending("Amount")
// Single record
.FirstOrDefaultAsync()
The SDK uses a single registration method that supports three scenarios:
// Both clients
services.AddCRUDClient(syncOptions => {...}, asyncOptions => {...});
// Sync only
services.AddCRUDClient(syncOptions => {...});
// Async only
services.AddCRUDClient(asyncConfigure: asyncOptions => {...});
Benefits:
IQueryRepositoryConstructs endpoint URLs for all CRUD operations. Singleton lifetime.
string BuildSyncInsertUrl();
string BuildAsyncInsertUrl(); // CorrelationId in header, not URL
string BuildSelectUrl();
Creates HTTP requests and converts Context to headers. Singleton lifetime.
HttpRequestMessage CreatePostRequest<TRequest>(string url, TRequest body, Context context);
Context Headers (aligned with TAF.Infra.MassTransit):
TenantId from context.TenantIdAppId from context.AppIdEnvironmentId from context.EnvironmentIdUserId from context.UserIdCorrelationId from context.CorrelationIdResponse deserialization, error handling, and validation. Singleton lifetime.
Task<OperationResult<T>> ProcessResponseAsync<T>(HttpResponseMessage response);
Task EnsureSuccessAsync(HttpResponseMessage response, string operation);
| Feature | SyncCRUDClient | AsyncCRUDClient |
|---|---|---|
| Pattern | Request → Response | Fire-and-forget → Events |
| Returns | Actual results | CorrelationId |
| Retry Logic | ✅ Yes | ❌ No |
| Use Case | Traditional APIs | Microservice communication |
| Event Consumption | ❌ Not needed | ✅ Required |
| Performance | Waits for completion | Returns immediately |
The package includes all dependencies:
External NuGet dependencies (auto-resolved):
Benefit: Install one package, get everything needed. No version conflicts.
| Property | Type | Default | Description |
|---|---|---|---|
| BaseUrl | string | required | CRUD API base URL |
| TimeoutSeconds | int | 30 | HTTP timeout |
| MaxRetryAttempts | int | 3 | Retry attempts |
| RetryDelayMs | int | 1000 | Retry delay |
| ApiKey | string? | null | Optional API key |
| Property | Type | Default | Description |
|---|---|---|---|
| BaseUrl | string | required | CRUD API base URL |
| TimeoutSeconds | int | 30 | HTTP timeout |
| ApiKey | string? | null | Optional API key |
using TAF.CRUD.SDK.Exceptions;
try
{
var result = await _client.Query("Orders").Insert(fields).WithContext(context).ExecuteAsync();
}
catch (CRUDClientException ex)
{
Console.WriteLine($"Failed: {ex.Message}");
Console.WriteLine($"Status: {ex.StatusCode}, Code: {ex.ErrorCode}");
}
SyncCRUDClient or AsyncCRUDClient to choose specific clientContext.Properties for custom metadata in async operationsConnection Failures: Verify BaseUrl, network connectivity, API key validity
Event Not Received: Check MassTransit consumer registration, RabbitMQ connection, CorrelationId matching
Timeout Errors: Increase TimeoutSeconds (async client only waits for 202 Accepted)
Authentication Errors: Verify ApiKey and context headers (TenantId, AppId, etc.)
MIT License
For issues or questions, contact the TAF platform team.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 net8.0 is compatible. net8.0-android net8.0-android was computed. net8.0-browser net8.0-browser was computed. net8.0-ios net8.0-ios was computed. net8.0-maccatalyst net8.0-maccatalyst was computed. net8.0-macos net8.0-macos was computed. net8.0-tvos net8.0-tvos was computed. net8.0-windows net8.0-windows was computed. net9.0 net9.0 was computed. net9.0-android net9.0-android was computed. net9.0-browser net9.0-browser was computed. net9.0-ios net9.0-ios was computed. net9.0-maccatalyst net9.0-maccatalyst was computed. net9.0-macos net9.0-macos was computed. net9.0-tvos net9.0-tvos was computed. net9.0-windows net9.0-windows was computed. net10.0 net10.0 was computed. net10.0-android net10.0-android was computed. net10.0-browser net10.0-browser was computed. net10.0-ios net10.0-ios was computed. net10.0-maccatalyst net10.0-maccatalyst was computed. net10.0-macos net10.0-macos was computed. net10.0-tvos net10.0-tvos was computed. net10.0-windows net10.0-windows was computed. |
Showing the top 1 NuGet packages that depend on TAF.CRUD.SDK:
| Package | Downloads |
|---|---|
|
TAF.Infra.Configuration
Cross-service configuration management. Reads config from TABD_Settings via CRUD SDK, caches via ICacheService, and invalidates instantly via SettingsChangedEvent through MassTransit. |
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 6.0.9 | 110 | 5/25/2026 |
| 6.0.8 | 110 | 5/24/2026 |
| 6.0.7 | 107 | 5/23/2026 |
| 6.0.6 | 359 | 4/30/2026 |
| 6.0.5 | 223 | 4/22/2026 |
| 6.0.4 | 112 | 4/22/2026 |
| 6.0.3 | 140 | 3/19/2026 |
| 6.0.2 | 159 | 3/6/2026 |
| 6.0.1 | 181 | 2/10/2026 |
| 6.0.0 | 766 | 2/6/2026 |
| 5.2.1 | 130 | 1/28/2026 |
| 5.2.0 | 128 | 1/22/2026 |
| 5.1.5 | 127 | 1/21/2026 |
| 5.1.4 | 145 | 1/10/2026 |
| 5.1.3 | 159 | 1/2/2026 |
| 5.1.2 | 157 | 12/30/2025 |
| 5.1.1 | 219 | 12/22/2025 |
| 5.1.0 | 346 | 12/17/2025 |
| 5.0.0 | 477 | 12/9/2025 |
| 4.1.0 | 200 | 11/28/2025 |