![]() |
VOOZH | about |
dotnet add package Excalibur.Data.Firestore --version 3.0.0-alpha.208
NuGet\Install-Package Excalibur.Data.Firestore -Version 3.0.0-alpha.208
<PackageReference Include="Excalibur.Data.Firestore" Version="3.0.0-alpha.208" />
<PackageVersion Include="Excalibur.Data.Firestore" Version="3.0.0-alpha.208" />Directory.Packages.props
<PackageReference Include="Excalibur.Data.Firestore" />Project file
paket add Excalibur.Data.Firestore --version 3.0.0-alpha.208
#r "nuget: Excalibur.Data.Firestore, 3.0.0-alpha.208"
#:package Excalibur.Data.Firestore@3.0.0-alpha.208
#addin nuget:?package=Excalibur.Data.Firestore&version=3.0.0-alpha.208&prereleaseInstall as a Cake Addin
#tool nuget:?package=Excalibur.Data.Firestore&version=3.0.0-alpha.208&prereleaseInstall as a Cake Tool
Google Cloud Firestore data provider implementation for Excalibur cloud-native data access.
dotnet add package Excalibur.Data.Firestore
// In Program.cs or Startup.cs
services.AddFirestore(options =>
{
options.ProjectId = "your-gcp-project-id";
options.DatabaseId = "(default)"; // Optional, defaults to (default)
options.DefaultCollection = "your-collection";
});
// Or using configuration
services.AddFirestore(configuration.GetSection("Firestore"));
{
"Firestore": {
"ProjectId": "your-gcp-project-id",
"DatabaseId": "(default)",
"DefaultCollection": "your-collection",
"UseEmulator": false,
"EmulatorHost": "localhost:8080"
}
}
public class OrderService
{
private readonly FirestorePersistenceProvider _provider;
public OrderService(FirestorePersistenceProvider provider)
{
_provider = provider;
}
public async Task<Order?> GetOrderAsync(string orderId, string tenantId)
{
var partitionKey = new PartitionKey(tenantId, "/tenantId");
return await _provider.GetByIdAsync<Order>(orderId, partitionKey);
}
public async Task<CloudOperationResult<Order>> CreateOrderAsync(Order order)
{
var partitionKey = new PartitionKey(order.TenantId, "/tenantId");
return await _provider.CreateAsync(order, partitionKey);
}
public async Task<CloudOperationResult<Order>> UpdateOrderAsync(Order order, string etag)
{
var partitionKey = new PartitionKey(order.TenantId, "/tenantId");
return await _provider.UpdateAsync(order, partitionKey, etag);
}
}
public async Task<IReadOnlyList<Order>> GetOrdersByStatusAsync(
string tenantId,
string status)
{
var partitionKey = new PartitionKey(tenantId, "/tenantId");
// Firestore uses collection path as partition key
var result = await _provider.QueryAsync<Order>(
"status = @status",
partitionKey,
new Dictionary<string, object> { ["status"] = status });
return result.Documents;
}
public async Task<CloudBatchResult> ProcessOrderBatchAsync(
string tenantId,
Order order,
OrderLine[] lines)
{
var partitionKey = new PartitionKey(tenantId, "/tenantId");
var operations = new List<ICloudBatchOperation>
{
new CloudBatchCreateOperation(order.Id, order)
};
foreach (var line in lines)
{
operations.Add(new CloudBatchCreateOperation(line.Id, line));
}
return await _provider.ExecuteBatchAsync(partitionKey, operations);
}
public async Task SubscribeToChangesAsync(CancellationToken cancellationToken)
{
var subscription = await _provider.CreateChangeFeedSubscriptionAsync<Order>(
"orders",
new ChangeFeedOptions
{
StartPosition = ChangeFeedStartPosition.Now,
MaxBatchSize = 100
},
cancellationToken);
await subscription.StartAsync(cancellationToken);
await foreach (var change in subscription.ReadChangesAsync(cancellationToken))
{
Console.WriteLine($"Change detected: {change.DocumentId}, Type: {change.EventType}");
// Process the change
}
}
public async Task<CloudOperationResult<Order>> SafeUpdateAsync(
Order order,
string etag)
{
var partitionKey = new PartitionKey(order.TenantId, "/tenantId");
// ETag is derived from Firestore UpdateTime
var result = await _provider.UpdateAsync(order, partitionKey, etag);
if (!result.Success && result.StatusCode == 412)
{
// Precondition failed - document was modified since etag
Console.WriteLine("Concurrent modification detected");
}
return result;
}
services.AddHealthChecks()
.AddCheck<FirestoreHealthCheck>(
name: "firestore",
tags: new[] { "database", "gcp" });
| Option | Description | Default |
|---|---|---|
Name |
Provider instance name for identification | Firestore |
ProjectId |
GCP project ID | Required* |
DefaultCollection |
Default collection name for operations | - |
CredentialsPath |
Path to service account JSON file | - |
CredentialsJson |
Service account JSON content (for containers) | - |
*Required unless using EmulatorHost.
| Option | Description | Default |
|---|---|---|
TimeoutInSeconds |
Operation timeout | 30 |
MaxRetryAttempts |
Maximum retry attempts for transient failures | 3 |
| Option | Description | Default |
|---|---|---|
EmulatorHost |
Firestore emulator host:port (e.g., "localhost:8080") | - |
The provider returns CloudOperationResult<T> with status codes for error handling:
var result = await _provider.UpdateAsync(order, partitionKey, etag);
if (!result.Success)
{
switch (result.StatusCode)
{
case 404:
Console.WriteLine("Document not found");
break;
case 409:
Console.WriteLine("Document already exists");
break;
case 412:
Console.WriteLine("Precondition failed - document was modified (ETag mismatch)");
break;
case 429:
Console.WriteLine("Resource exhausted - too many requests");
break;
case 503:
Console.WriteLine("Service unavailable - retry with backoff");
break;
}
}
| gRPC Status | HTTP Code | Description |
|---|---|---|
NOT_FOUND |
404 | Document or collection not found |
ALREADY_EXISTS |
409 | Document already exists (on create) |
FAILED_PRECONDITION |
412 | Precondition failed (ETag mismatch) |
RESOURCE_EXHAUSTED |
429 | Quota exceeded |
ABORTED |
409 | Transaction aborted (retry) |
UNAVAILABLE |
503 | Service temporarily unavailable |
Firestore uses Google Cloud authentication. Configure one of:
# Local development
gcloud auth application-default login
# In GCP (GKE, Cloud Run, etc.)
# Automatically uses service account
services.AddFirestore(options =>
{
options.ProjectId = "your-project";
options.CredentialPath = "/path/to/service-account.json";
});
export GOOGLE_APPLICATION_CREDENTIALS="/path/to/service-account.json"
For containerized environments where file paths are impractical:
services.AddFirestore(options =>
{
options.ProjectId = "your-project";
// JSON content from Kubernetes secret or environment variable
options.CredentialsJson = Environment.GetEnvironmentVariable("GCP_CREDENTIALS_JSON");
});
Firestore uses a hierarchical document model:
// Root collection
var partitionKey = new PartitionKey("orders", "/collection");
// Subcollection
var subPartitionKey = new PartitionKey("orders/order-123/items", "/collection");
For local development and testing:
# Start Firestore emulator
gcloud emulators firestore start --host-port=localhost:8080
services.AddFirestore(options =>
{
options.ProjectId = "test-project";
options.UseEmulator = true;
options.EmulatorHost = "localhost:8080";
});
See LICENSE files in the repository root.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 net10.0 is compatible. 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 5 NuGet packages that depend on Excalibur.Data.Firestore:
| Package | Downloads |
|---|---|
|
Excalibur.EventSourcing.Firestore
Google Cloud Firestore event store implementation for Excalibur event sourcing. |
|
|
Excalibur.Outbox.Firestore
Google Cloud Firestore implementation of the cloud-native outbox pattern for Excalibur event sourcing. |
|
|
Excalibur.Inbox.Firestore
Google Cloud Firestore implementation of the inbox pattern for Excalibur, providing idempotent message processing. |
|
|
Excalibur.Saga.Firestore
Google Cloud Firestore saga store implementation for Excalibur. |
|
|
Excalibur.Cdc.Firestore
Google Cloud Firestore Change Data Capture (CDC) implementation for Excalibur. |
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 3.0.0-alpha.208 | 68 | 6/11/2026 |
| 3.0.0-alpha.207 | 69 | 6/11/2026 |
| 3.0.0-alpha.205 | 72 | 6/10/2026 |
| 3.0.0-alpha.204 | 87 | 6/8/2026 |
| 3.0.0-alpha.203 | 79 | 6/8/2026 |
| 3.0.0-alpha.202 | 74 | 6/8/2026 |
| 3.0.0-alpha.201 | 81 | 6/8/2026 |
| 3.0.0-alpha.199 | 74 | 6/8/2026 |
| 3.0.0-alpha.198 | 77 | 5/28/2026 |
| 3.0.0-alpha.197 | 89 | 5/28/2026 |
| 3.0.0-alpha.194 | 85 | 5/20/2026 |
| 3.0.0-alpha.193 | 75 | 5/13/2026 |
| 3.0.0-alpha.192 | 79 | 5/13/2026 |
| 3.0.0-alpha.191 | 84 | 5/13/2026 |
| 3.0.0-alpha.189 | 78 | 5/12/2026 |
| 3.0.0-alpha.187 | 89 | 5/8/2026 |
| 3.0.0-alpha.185 | 86 | 5/7/2026 |
| 3.0.0-alpha.183 | 77 | 5/7/2026 |
| 3.0.0-alpha.182 | 68 | 5/6/2026 |
| 3.0.0-alpha.181 | 87 | 5/6/2026 |