MinIO Storage with C#

MinIO Storage with C#

MinIO is a high-performance, self-hosted object storage system that's S3-compatible.

I came across MinIO while looking fora self-hosted alternative to AWS S3. I needed a object storage that was lightweight and open source.

MinIO stood out because it has S3 API Compatbility while being simple to deploy with Docker.

In this guide, you'll learn how to:

  • Install and run MinIO using Docker
  • Set up a C# Minimal API
  • Perform basic CRUD operations (upload, download, list, and delete objects)
  • Understand the benefits of using MinIO

Prerequisites

Ensure you have the following installed:

  • Docker
  • .NET 8+ SDK
  • A code editor (e.g., Visual Studio Code or Visual Studio)

Step 1: Running MinIO with Docker

Start MinIO using the following command:

docker run -p 9000:9000 -p 9001:9001 --name minio \
    -e "MINIO_ROOT_USER=admin" \
    -e "MINIO_ROOT_PASSWORD=admin123" \
    -v $(pwd)/minio-data:/data \
    quay.io/minio/minio server /data --console-address ":9001"

Step 2: Creating a C# Minimal API

Create a new Minimal API project:

# creates a new c# project
> dotnet new web -n MinIOApi

# navigates to the created folder
> cd MinIOApi

# adds the package MinIO to the project
> dotnet add package Minio

Open Program.cs and set up the API:

using Minio;
using Minio.DataModel.Args;
using System.IO;
using System.Text;

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

var minio = new MinioClient()
    .WithEndpoint("http://localhost:9000")
    .WithCredentials("admin", "admin123")
    .WithSSL(false)
    .Build();

app.MapGet("/", () => "Welcome to MinIO API");
app.Run();

Run the API and it will be accessible at http://localhost:5000.

Step 3: Implementing CRUD Operations

Code to Create a Bucket

app.MapPost("/create-bucket/{bucketName}", async (string bucketName) =>
{
    await minio.MakeBucketAsync(new MakeBucketArgs().WithBucket(bucketName));
    return Results.Ok($"Bucket '{bucketName}' created successfully.");
});

Code to Upload a File

app.MapPost("/upload/{bucketName}/{objectName}", async (string bucketName, string objectName, IFormFile file) =>
{
    using var stream = file.OpenReadStream();
    await minio.PutObjectAsync(new PutObjectArgs()
        .WithBucket(bucketName)
        .WithObject(objectName)
        .WithStreamData(stream)
        .WithObjectSize(file.Length)
    );
    return Results.Ok($"File '{objectName}' uploaded to bucket '{bucketName}'.");
});

Code Download a File

app.MapGet("/download/{bucketName}/{objectName}", async (string bucketName, string objectName) =>
{
    var memoryStream = new MemoryStream();
    await minio.GetObjectAsync(new GetObjectArgs()
        .WithBucket(bucketName)
        .WithObject(objectName)
        .WithCallbackStream(async stream => await stream.CopyToAsync(memoryStream))
    );


    memoryStream.Position = 0;
    return Results.File(memoryStream, "application/octet-stream", objectName);
});

Code to List Files in a Bucket

app.MapGet("/list/{bucketName}", async (string bucketName) =>
{
    var objects = new List<string>();
    await foreach (var obj in minio.ListObjectsAsync(new ListObjectsArgs().WithBucket(bucketName)))
    {
        objects.Add(obj.Key);
    }
    return Results.Ok(objects);
});

Code to Delete a File

app.MapDelete("/delete/{bucketName}/{objectName}", async (string bucketName, string objectName) =>
{
    await minio.RemoveObjectAsync(new RemoveObjectArgs()
        .WithBucket(bucketName)
        .WithObject(objectName)
    );
    return Results.Ok($"File '{objectName}' deleted from bucket '{bucketName}'.");
});

Step 4: Testing the API

First start the API. dotnet run

Creating a bucket.

curl -X POST http://localhost:5000/create-bucket/my-bucket

Downloading a file.

curl -X GET http://localhost:5000/download/my-bucket/hello.txt -o hello.txt

Listing files.

curl -X GET http://localhost:5000/list/my-bucket

Deleting a file.

curl -X DELETE http://localhost:5000/delete/my-bucket/hello.txt

Benefits of Using MinIO

  • Self-hosted and Lightweight & Ideal for local development and private cloud storage.
  • S3 API Compatibility & Works seamlessly with AWS S3-compatible tools and libraries.
  • High Performance & Optimized for fast object storage operations.
  • Scalability & Supports both standalone and distributed deployments.
  • Open-Source & No licensing fees, with strong community support.

Conclusion

We've successfully set up MinIO, built a C# Minimal API, and implemented CRUD operations for object storage.

This setup provides a powerful alternative to AWS S3, offering full control over your data in a self-hosted environment.