Skip to content

Google Cloud Storage Provider

Prerequisites: Storage Providers Overview

The NPipeline.StorageProviders.Gcp package implements IStorageProvider for Google Cloud Storage. Supports Application Default Credentials (ADC), explicit service account credentials, resumable uploads with configurable chunk sizes, and exponential backoff retry.

Installation

bash
dotnet add package NPipeline.StorageProviders.Gcp

Dependencies: Google.Cloud.Storage.V1 4.x, Google.Apis.Auth 1.x

Quick Start

csharp
var options = new GcsStorageProviderOptions
{
    DefaultProjectId = "my-project",
    UseDefaultCredentials = true
};
var factory = new GcsClientFactory(options);
var provider = new GcsStorageProvider(factory, options);

var stream = await provider.OpenReadAsync(
    StorageUri.Parse("gs://my-bucket/data/orders.csv"));

URI Format

gs://bucket-name/object/path?projectId=my-project&contentType=text/csv
ComponentDescription
bucket-nameGCS bucket (URI host)
object/pathObject key (URI path)
projectIdOptional - override DefaultProjectId
contentTypeOptional - set content type on write
serviceUrlOptional - custom GCS endpoint
accessTokenOptional - per-request access token
credentialsPathOptional - path to service account JSON

Authentication

  1. Explicit credentials - DefaultCredentials (GoogleCredential instance)
  2. Application Default Credentials (default) - GOOGLE_APPLICATION_CREDENTIALS env var → GCE metadata → gcloud CLI
csharp
// Application Default Credentials (recommended)
var options = new GcsStorageProviderOptions
{
    DefaultProjectId = "my-project",
    UseDefaultCredentials = true    // default
};

// Explicit service account
var options = new GcsStorageProviderOptions
{
    DefaultProjectId = "my-project",
    DefaultCredentials = GoogleCredential.FromFile("/path/to/sa.json")
};

Configuration

PropertyTypeDefaultDescription
DefaultProjectIdstring?nullGCP project ID
DefaultCredentialsGoogleCredential?nullExplicit credentials
UseDefaultCredentialsbooltrueUse Application Default Credentials
ServiceUrlUri?nullCustom GCS endpoint (for emulator)
UploadChunkSizeBytesint16 MBResumable upload chunk size (must be multiple of 256 KiB)
UploadBufferThresholdByteslong64 MBReserved for future use
ClientCacheSizeLimitint100Max cached StorageClient instances
RetrySettingsGcsRetrySettings?nullRetry configuration

Retry Settings

PropertyTypeDefaultDescription
InitialDelayTimeSpan1sFirst retry delay
MaxDelayTimeSpan32sMaximum retry delay
DelayMultiplierdouble2.0Exponential backoff multiplier
MaxAttemptsint3Total attempts (0 = disable)
RetryOnRateLimitbooltrueRetry on HTTP 429
RetryOnServerErrorsbooltrueRetry on HTTP 5xx

Dependency Injection

csharp
services.AddGcsStorageProvider();

services.AddGcsStorageProvider(options =>
{
    options.DefaultProjectId = "my-project";
    options.RetrySettings = new GcsRetrySettings
    {
        MaxAttempts = 5,
        RetryOnRateLimit = true
    };
});

Registers: IStorageProvider, IStorageProviderMetadataProvider

Features

  • Resumable uploads - large files upload in chunks (256 KiB aligned)
  • Exponential backoff - configurable retry with rate-limit and server error handling
  • Client caching - StorageClient instances cached per project; LRU eviction
  • Metadata - Size, LastModified, ContentType, ETag

Configuration Examples

fake-gcs-server (Local Development)

csharp
services.AddGcsStorageProvider(options =>
{
    options.ServiceUrl = new Uri("http://localhost:4443");
    options.DefaultProjectId = "test-project";
    options.UseDefaultCredentials = true;
});

Service Account JSON

csharp
services.AddGcsStorageProvider(options =>
{
    options.DefaultProjectId = "my-project-id";
    options.DefaultCredentials = GoogleCredential.FromFile("/path/to/service-account.json");
});

Custom Upload Chunk Size

csharp
services.AddGcsStorageProvider(options =>
{
    options.UploadChunkSizeBytes = 32 * 1024 * 1024; // 32 MB (must be multiple of 256 KiB)
});

Examples

Reading

csharp
var uri = StorageUri.Parse("gs://my-bucket/data.csv");

using var stream = await provider.OpenReadAsync(uri);
using var reader = new StreamReader(stream);
var content = await reader.ReadToEndAsync();

Writing

csharp
var uri = StorageUri.Parse("gs://my-bucket/output.csv?contentType=text/csv");

using var stream = await provider.OpenWriteAsync(uri);
using var writer = new StreamWriter(stream);
await writer.WriteLineAsync("id,name,value");

Listing

csharp
var prefix = StorageUri.Parse("gs://my-bucket/data/");

await foreach (var item in provider.ListAsync(prefix, recursive: true))
{
    Console.WriteLine($"{item.Uri} - {item.Size} bytes");
}

Metadata

csharp
var metadata = await provider.GetMetadataAsync(uri);
if (metadata is not null)
    Console.WriteLine($"Size: {metadata.Size}, ContentType: {metadata.ContentType}");

Error Handling

HTTP Status.NET ExceptionDescription
401 (Unauthorized)UnauthorizedAccessExceptionAuthentication failure
403 (Forbidden)UnauthorizedAccessExceptionAuthorization failure
404 (Not Found)FileNotFoundExceptionBucket or object missing
400 (Bad Request)ArgumentExceptionInvalid request parameters
OtherIOExceptionGeneral GCS failure

IAM Permissions

OperationRequired IAM Role
Readroles/storage.objectViewer
Writeroles/storage.objectCreator
Full Accessroles/storage.objectAdmin
List Bucketsroles/storage.admin

Limitations

  • Flat storage - GCS uses prefix-based hierarchy (no real directories)
  • Chunk size - upload chunk size must be a multiple of 256 KiB
  • Authentication - ADC requires a GCP environment or service account JSON file

Next Steps

Released under the MIT License.