Kemenkeu.Repository.File 1.0.0

dotnet add package Kemenkeu.Repository.File --version 1.0.0
                    
NuGet\Install-Package Kemenkeu.Repository.File -Version 1.0.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Kemenkeu.Repository.File" Version="1.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Kemenkeu.Repository.File" Version="1.0.0" />
                    
Directory.Packages.props
<PackageReference Include="Kemenkeu.Repository.File" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Kemenkeu.Repository.File --version 1.0.0
                    
#r "nuget: Kemenkeu.Repository.File, 1.0.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Kemenkeu.Repository.File@1.0.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Kemenkeu.Repository.File&version=1.0.0
                    
Install as a Cake Addin
#tool nuget:?package=Kemenkeu.Repository.File&version=1.0.0
                    
Install as a Cake Tool

Kemenkeu.Repository.File

Kemenkeu.Repository.File is a file repository library for MinIO that provides simple and clean abstractions for file storage operations. It supports Store, Get, and Remove operations with configurable bucket and folder path settings.

Features

  • Store files to MinIO object storage
  • Get files as streams or with callback processing
  • Remove files from storage
  • Configurable bucket and folder path prefixes
  • Built-in error handling and logging
  • Multi-framework support (.NET 6, 7, 8, 9, 10)
  • Configurable via appsettings.json or code
  • Support for SSL/TLS connections

Installation

Install the library via NuGet:

dotnet add package Kemenkeu.Repository.File

Configuration

appsettings.json Configuration

Add the following configuration to your appsettings.json file:

{
  "MinIO": {
    "Endpoint": "localhost:9000",
    "AccessKey": "minioadmin",
    "SecretKey": "minioadmin",
    "UseSSL": false,
    "Region": "us-east-1",
    "BucketName": "my-bucket",
    "FolderPath": "documents"
  }
}

Configuration Options

Option Type Description Required
Endpoint string MinIO endpoint URL (e.g., "localhost:9000") Yes
AccessKey string Access key for MinIO authentication Yes
SecretKey string Secret key for MinIO authentication Yes
UseSSL bool Use SSL/TLS for connection No (default: false)
Region string Region for MinIO No
BucketName string Bucket name where files will be stored No (default: "default")
FolderPath string Optional folder path prefix for all files No

Usage

1. Setup in Program.cs (.NET 6+)

using Kemenkeu.Repository.File.Extensions;

var builder = WebApplication.CreateBuilder(args);

// Option 1: Configure from appsettings.json
builder.Services.AddFileRepository(builder.Configuration);

// Option 2: Configure with options object
var minioSettings = builder.Configuration.GetSection("MinIO").Get<MinioSettings>();
builder.Services.AddFileRepository(minioSettings);

// Option 3: Configure with action
builder.Services.AddFileRepository(options =>
{
    options.Endpoint = "localhost:9000";
    options.AccessKey = "minioadmin";
    options.SecretKey = "minioadmin";
    options.UseSSL = false;
    options.BucketName = "my-bucket";
    options.FolderPath = "documents";
});

var app = builder.Build();
app.Run();

2. Using the File Repository

using Kemenkeu.Repository.File.Abstractions;

public class DocumentService
{
    private readonly IFileRepository _fileRepository;
    private readonly ILogger<DocumentService> _logger;

    public DocumentService(
        IFileRepository fileRepository,
        ILogger<DocumentService> logger)
    {
        _fileRepository = fileRepository;
        _logger = logger;
    }

    // Store a file
    public async Task UploadDocumentAsync(string fileName, Stream fileStream)
    {
        await _fileRepository.Store(fileName, fileStream);
        _logger.LogInformation("Document {FileName} uploaded successfully", fileName);
    }

    // Get a file as stream
    public async Task<Stream?> DownloadDocumentAsync(string fileName)
    {
        var stream = await _fileRepository.Get(fileName);
        if (stream == null)
        {
            _logger.LogWarning("Document {FileName} not found", fileName);
            return null;
        }
        return stream;
    }

    // Get a file with callback processing
    public async Task ProcessDocumentAsync(string fileName)
    {
        await _fileRepository.Get(fileName, stream =>
        {
            // Process the stream directly without loading into memory
            using var reader = new StreamReader(stream);
            var content = reader.ReadToEnd();
            _logger.LogInformation("Document content length: {Length}", content.Length);
        });
    }

    // Remove a file
    public async Task DeleteDocumentAsync(string fileName)
    {
        await _fileRepository.Remove(fileName);
        _logger.LogInformation("Document {FileName} deleted successfully", fileName);
    }

    // Get full path (with folder prefix)
    public string GetFullPath(string relativePath)
    {
        return _fileRepository.GetPath(relativePath);
    }
}

3. Controller Example

using Kemenkeu.Repository.File.Abstractions;
using Microsoft.AspNetCore.Mvc;

[ApiController]
[Route("api/[controller]")]
public class DocumentsController : ControllerBase
{
    private readonly IFileRepository _fileRepository;

    public DocumentsController(IFileRepository fileRepository)
    {
        _fileRepository = fileRepository;
    }

    [HttpPost("upload")]
    public async Task<IActionResult> Upload(IFormFile file)
    {
        if (file == null || file.Length == 0)
            return BadRequest("No file uploaded");

        using var stream = file.OpenReadStream();
        await _fileRepository.Store(file.FileName, stream);
        
        return Ok(new { message = "File uploaded successfully", fileName = file.FileName });
    }

    [HttpGet("download/{fileName}")]
    public async Task<IActionResult> Download(string fileName)
    {
        var stream = await _fileRepository.Get(fileName);
        if (stream == null)
            return NotFound($"File {fileName} not found");

        return File(stream, "application/pdf", fileName);
    }

    [HttpDelete("{fileName}")]
    public async Task<IActionResult> Delete(string fileName)
    {
        await _fileRepository.Remove(fileName);
        return Ok(new { message = "File deleted successfully", fileName });
    }
}

Advanced Usage

Custom Content Types

The default implementation uses application/pdf as the content type. To support different content types, you can extend the FileRepository class:

public class CustomFileRepository : FileRepository
{
    public CustomFileRepository(
        ILogger<FileRepository> logger,
        IMinioClient minioClient,
        IOptions<MinioSettings> minioSettings)
        : base(logger, minioClient, minioSettings)
    {
    }

    public async Task Store(string path, Stream stream, string contentType)
    {
        // Override Store method to accept custom content type
        path = GetPath(path);
        var putObjectArgs = new PutObjectArgs()
            .WithBucket(_bucketName)
            .WithObject(path)
            .WithStreamData(stream)
            .WithObjectSize(stream.Length)
            .WithContentType(contentType);
        
        await _minioClient.PutObjectAsync(putObjectArgs);
    }
}

Error Handling

The repository handles ObjectNotFoundException gracefully:

public async Task<Stream?> SafeGet(string fileName)
{
    try
    {
        return await _fileRepository.Get(fileName);
    }
    catch (Exception ex)
    {
        _logger.LogError(ex, "Error retrieving file {FileName}", fileName);
        return null;
    }
}

Best Practices

  1. Use Folder Paths: Organize files using the FolderPath configuration to group related files
  2. Stream Processing: Use the callback-based Get method for large files to avoid loading them entirely into memory
  3. Error Handling: Always check for null returns when using Get method
  4. Content Types: Consider extending the repository to support different content types based on file extensions
  5. Bucket Management: Ensure buckets are created before storing files
  6. Path Validation: Validate file paths before storing to prevent security issues

Troubleshooting

Connection Issues

  • Ensure the MinIO endpoint is correct and accessible
  • Verify access key and secret key credentials
  • Check network connectivity to MinIO server
  • For SSL connections, ensure certificates are properly configured

File Not Found Errors

  • Verify the file path is correct (including folder prefix if configured)
  • Check that the file exists in the specified bucket
  • Ensure the bucket name is correct

Upload Failures

  • Verify the bucket exists and is accessible
  • Check file size limits
  • Ensure the stream is readable and positioned correctly
  • Verify permissions for the access key

License

This project is licensed under the MIT License.

Product Compatible and additional computed target framework versions.
.NET net6.0 is compatible.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 is compatible.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.0 254 12/4/2025