Working with S3 and Cloud Storage in C# (.NET): AWS SDK and MinIO

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Introduction to S3 and Cloud Storage for .NET Developers



Cloud object storage compatible with the Amazon S3 (Simple Storage Service) protocol has become the de facto standard for storing unstructured data: images, videos, backups, logs, and build artifacts. In the C# (.NET) ecosystem, working with such storage is implemented via the official AWS SDK for .NET or through lightweight clients for S3-compatible solutions (MinIO, Yandex Object Storage, DigitalOcean Spaces).



In this article, we will cover the main operations: connection, bucket creation, uploading, downloading, and deleting objects. All examples are written in C# using .NET 8.



Installing the AWS SDK for .NET Library



To work with S3 from C#, you need to install the NuGet package AWS SDK for .NET — S3:



dotnet add package AWSSDK.S3dotnet add package AWSSDK.Extensions.NETCore.Setup  // for DI integration


If you are using MinIO or other S3-compatible storage (not AWS), the same package is sufficient — it supports custom endpoints.



Basic S3 Client Configuration



Let's create a client for working with S3. The example below uses MinIO running locally on port 9000:



using Amazon;using Amazon.S3;using Amazon.Runtime;

var config = new AmazonS3Config{ ServiceURL = "http://localhost:9000", // for MinIO or other S3-compatible storage ForcePathStyle = true, // required for MinIO UseHttp = true};

var credentials = new BasicAWSCredentials("minioadmin", "minioadmin");var s3Client = new AmazonS3Client(credentials, config);


For AWS S3, simply specify the region and use standard credentials:



var s3Client = new AmazonS3Client(RegionEndpoint.EUWest1);


Creating and Deleting a Bucket



Creating a Bucket



public async Task CreateBucketAsync(string bucketName){    var putBucketRequest = new PutBucketRequest    {        BucketName = bucketName,        UseClientRegion = true    };    var response = await s3Client.PutBucketAsync(putBucketRequest);    Console.WriteLine($"Bucket {bucketName} created. HTTP status: {response.HttpStatusCode}");}


Checking if a Bucket Exists



public async Task<bool> DoesBucketExistAsync(string bucketName){    return await AmazonS3Util.DoesS3BucketExistAsync(s3Client, bucketName);}


Deleting a Bucket



public async Task DeleteBucketAsync(string bucketName){    await s3Client.DeleteBucketAsync(bucketName);    Console.WriteLine($"Bucket {bucketName} deleted.");}


Uploading Files



The most common scenario is uploading a file to a bucket. Use PutObjectAsync:



public async Task UploadFileAsync(string bucketName, string key, string filePath){    var putRequest = new PutObjectRequest    {        BucketName = bucketName,        Key = key,        FilePath = filePath,        ContentType = "application/octet-stream"    };

var response = await s3Client.PutObjectAsync(putRequest); Console.WriteLine($"File {key} uploaded. ETag: {response.ETag}");}


Uploading from a stream — useful for files received from a user via a web form:



public async Task UploadFromStreamAsync(string bucketName, string key, Stream inputStream){    var putRequest = new PutObjectRequest    {        BucketName = bucketName,        Key = key,        InputStream = inputStream    };    await s3Client.PutObjectAsync(putRequest);}


Downloading Files



You can download an object to a file or to a stream:



public async Task DownloadFileAsync(string bucketName, string key, string downloadPath){                    

Recommendations