Exporta archivos a DigitalOcean Spaces en .NET (C#)
Usa el SDK de AWS de código abierto para exportar archivos locales a un Space de DigitalOcean existente. Este tutorial proporciona un programa completo en .NET 10 para archivos de hasta 64 MiB.
Comprende la compatibilidad de DigitalOcean Spaces con S3
Spaces admite un subconjunto de la API de S3. Configura explícitamente el endpoint regional y la región de firma. Se admiten tanto las solicitudes con direccionamiento por ruta como las de alojamiento virtual; este ejemplo usa el estilo por ruta.
Instala los paquetes NuGet necesarios
Instala el SDK de .NET 10 y luego ejecuta:
dotnet new console --framework net10.0 --name SpacesExport
cd SpacesExport
dotnet add package AWSSDK.Core --version 4.0.102.6
dotnet add package AWSSDK.S3 --version 4.0.103.3
Usa AWS SDK for .NET con DigitalOcean Spaces
Define las siguientes variables de entorno mediante tu shell o gestor de secretos:
| Variable | Valor |
|---|---|
SPACES_ENDPOINT | Endpoint regional, como https://nyc3.digitaloceanspaces.com |
SPACES_REGION | Región correspondiente, como nyc3 |
SPACES_BUCKET | Nombre del Space existente |
SPACES_KEY_ID | Clave de acceso de Spaces |
SPACES_APPLICATION_KEY | Clave secreta de Spaces |
Reemplaza Program.cs por lo siguiente. La
guía del SDK de DigitalOcean describe la configuración del endpoint.
Proporciona las claves de objeto como cadenas de texto sin codificar, incluidos los espacios o
caracteres Unicode; el SDK se encarga de la codificación de URL y de Signature V4.
using Amazon.Runtime;
using Amazon.S3;
using Amazon.S3.Model;
public static class SpacesExporter
{
public static async Task<int> Main(string[] args)
{
using var deadline = new CancellationTokenSource(TimeSpan.FromMinutes(5));
Console.CancelKeyPress += (_, e) => { e.Cancel = true; deadline.Cancel(); };
try
{
if (args.Length != 2) throw new ArgumentException("Pass a local file and an object key.");
var endpoint = new Uri(Required("SPACES_ENDPOINT"));
if (endpoint.Scheme != "https" || endpoint.UserInfo.Length != 0 ||
endpoint.AbsolutePath != "/" || endpoint.Query.Length != 0 || endpoint.Fragment.Length != 0)
throw new ArgumentException("Use the HTTPS regional endpoint without a bucket or path.");
var config = new AmazonS3Config
{
ServiceURL = endpoint.AbsoluteUri,
AuthenticationRegion = Required("SPACES_REGION"),
ForcePathStyle = true,
MaxErrorRetry = 2,
RequestChecksumCalculation = RequestChecksumCalculation.WHEN_REQUIRED,
ResponseChecksumValidation = ResponseChecksumValidation.WHEN_REQUIRED
};
using var client = new AmazonS3Client(
Required("SPACES_KEY_ID"), Required("SPACES_APPLICATION_KEY"), config);
await UploadAsync(client, Required("SPACES_BUCKET"), args[0], args[1], deadline.Token);
Console.WriteLine("Uploaded.");
return 0;
}
catch (OperationCanceledException) { Console.Error.WriteLine("Upload canceled or timed out."); }
catch (AmazonS3Exception error) { Console.Error.WriteLine($"Storage returned HTTP {(int)error.StatusCode}."); }
catch (Exception) { Console.Error.WriteLine("Upload failed. Check the file and storage configuration."); }
return 1;
}
private static string Required(string name) =>
Environment.GetEnvironmentVariable(name) is { Length: > 0 } value
? value : throw new ArgumentException($"Missing {name}.");
public static async Task UploadAsync(IAmazonS3 client, string bucket, string path,
string key, CancellationToken cancellationToken)
{
if (string.IsNullOrWhiteSpace(key)) throw new ArgumentException("An object key is required.");
await using var input = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read);
if (input.Length > 64L * 1024 * 1024) throw new IOException("This example accepts at most 64 MiB.");
await client.PutObjectAsync(new PutObjectRequest
{
BucketName = bucket,
Key = key,
InputStream = input,
AutoCloseStream = false,
ContentType = "application/octet-stream",
UseChunkEncoding = false
}, cancellationToken);
}
}
Crea un archivo de entrada e inicia el programa desde el directorio del proyecto:
printf 'example export\n' > report.txt
dotnet run -- report.txt 'reports/report #1.txt'
Añade lógica de reintentos y manejo de errores
El SDK realiza hasta dos reintentos ante fallos que los admiten. Tanto el plazo de cinco minutos como Ctrl+C cancelan los reintentos y la subida. Los fallos permanentes de autorización hacen que el programa termine con un código distinto de cero, sin exponer credenciales ni cuerpos de respuesta del servicio. Comprueba el objeto remoto tras un fallo de red de resultado incierto antes de reintentar una operación cuyo comportamiento de reemplazo sea importante.
Optimiza el rendimiento con subidas multiparte y streaming
El programa transmite mediante una única solicitud PUT el contenido de un archivo abierto, con un
límite de 64 MiB impuesto por la aplicación. No realiza subidas multiparte. Mantén el archivo sin
cambios durante la subida. Para archivos más grandes, usa
TransferUtility del SDK de AWS y prepara la limpieza de las subidas multiparte
incompletas; consulta la documentación de transferencias de AWS.
Los recursos del flujo de archivo y del cliente se liberan incluso cuando falla una solicitud. Reutiliza un cliente entre subidas en una aplicación de larga duración y limita las operaciones simultáneas para ajustarlas a los recursos de memoria y red disponibles.
Gestiona las claves de acceso y los permisos de forma segura
Usa una clave de Spaces cuyo alcance se limite al bucket de destino. El ejemplo proporciona las credenciales explícitamente, usa HTTPS y deja el objeto privado de forma predeterminada. No modifica la política del bucket ni las ACL.
Compara los enfoques
El SDK de AWS gestiona la firma, la codificación de claves de objeto, los errores de respuesta y los
reintentos con una sola dependencia. Una abstracción de almacenamiento resulta útil cuando una
aplicación ya depende de varios proveedores. La integración directa con
HttpClient requiere una implementación completa de Signature V4; el SDK evita tener
que mantener esa implementación en el código de la aplicación.
Las subidas desde el navegador constituyen un flujo aparte: emite una URL prefirmada de corta duración desde tu backend y configura la política CORS del Space para el origen del navegador. Mantén la clave secreta en el servidor.
Resuelve problemas comunes
Ante un HTTP 403, comprueba la clave de acceso, la clave secreta, los permisos del bucket, el endpoint
y la región de firma. Si falta el bucket, crea primero el Space o corrige
SPACES_BUCKET. Si un archivo supera el límite de este ejemplo, cambia a un flujo de
trabajo multiparte diseñado para ese fin en lugar de eliminar el límite.
El Robot de exportación a DigitalOcean de Transloadit también puede guardar los resultados de un pipeline de procesamiento en tu Space.
