Ledbim.Storage
1.2.0
dotnet add package Ledbim.Storage --version 1.2.0
NuGet\Install-Package Ledbim.Storage -Version 1.2.0
<PackageReference Include="Ledbim.Storage" Version="1.2.0" />
<PackageVersion Include="Ledbim.Storage" Version="1.2.0" />
<PackageReference Include="Ledbim.Storage" />
paket add Ledbim.Storage --version 1.2.0
#r "nuget: Ledbim.Storage, 1.2.0"
#:package Ledbim.Storage@1.2.0
#addin nuget:?package=Ledbim.Storage&version=1.2.0
#tool nuget:?package=Ledbim.Storage&version=1.2.0
Ledbim.Storage
<p align="center"> <img src="ledbim_storage_logo.png" alt="Ledbim.Storage" width="120" /> </p>
<p align="center"> <strong>FTP Upload · Base64 · Stream · Otomatik Klasör · Public URL</strong><br/> Ledbim ekosistemi için dosya depolama altyapısı. </p>
Kapsam
Ledbim.Storage paketi şu bileşenleri sağlar:
| Bileşen | Açıklama |
|---|---|
| IFileService | Dosya yükleme ve silme arayüzü |
| FileService | FluentFTP tabanlı IIS FTP implementasyonu |
| FtpSettings | Bağlantı ve public URL için tek adres yapılandırması |
| AddFileService() | Tek satır DI kaydı |
Kurulum
dotnet add package Ledbim.Storage
Bağımlılıklar
FluentFTP v52.1.0
Microsoft.Extensions.Configuration.Abstractions v10.0.0
Microsoft.Extensions.DependencyInjection.Abstractions v10.0.0
Microsoft.Extensions.Options.ConfigurationExtensions v10.0.0
Ledbim.Core (project reference)
Hızlı Başlangıç
1. appsettings.json
{
"FtpSettings": {
"FtpAddress": "cdn.example.com",
"Username": "ftpuser",
"Password": "ftppassword"
}
}
2. Program.cs
builder.Services.AddFileService(builder.Configuration);
3. Kullanım
public class UploadProfilePhotoCommandHandler(IFileService fileService)
: IRequestHandler<UploadProfilePhotoCommand, Result<string>>
{
public async Task<Result<string>> Handle(
UploadProfilePhotoCommand request, CancellationToken ct)
{
var uploadRequest = new FileUploadRequest
{
Content = request.FileStream,
FileName = request.FileName,
Length = request.FileStream.Length,
Folder = $"users/{request.UserId}/photos"
};
var result = await fileService.UploadAsync(uploadRequest, ct);
return Result<string>.Success(ResultType.Success, result.Path);
}
}
FtpAddress — Tek Alan, İki Görev
FtpAddress, hem FTP sunucusuna bağlantı kurmak hem de yüklenen dosyaların herkese açık HTTPS URL'sini oluşturmak için kullanılır.
FtpAddress = "cdn.example.com"
│
├── FTP bağlantısı → ftp://cdn.example.com:21
│
└── Public URL → https://cdn.example.com/uploads/image.jpg
Desteklenen Adres Formatları
{ "FtpAddress": "cdn.example.com" }
{ "FtpAddress": "ftp://cdn.example.com" }
{ "FtpAddress": "ftp://cdn.example.com:2121" }
{ "FtpAddress": "cdn.example.com:2121" }
Port belirtilmezse varsayılan 21 kullanılır.
IFileService
public interface IFileService
{
// Stream ile yükleme
Task<FileUploadResult> UploadAsync(
FileUploadRequest request,
CancellationToken cancellationToken = default);
// Base64 ile yükleme
Task<FileUploadResult> UploadBase64Async(
Base64UploadRequest request,
CancellationToken cancellationToken = default);
// Silme
Task RemoveAsync(
string pathOrUrl,
CancellationToken cancellationToken = default);
}
Upload — Stream
public sealed class FileUploadRequest
{
public required Stream Content { get; init; } // Dosya içeriği
public required string FileName { get; init; } // Özgün dosya adı (uzantı için kullanılır)
public required long Length { get; init; } // Bayt cinsinden dosya boyutu
public required string Folder { get; init; } // Hedef FTP klasörü
}
// IFormFile'dan
var request = new FileUploadRequest
{
Content = formFile.OpenReadStream(),
FileName = formFile.FileName, // Uzantı buradan alınır
Length = formFile.Length,
Folder = "invoices/2024"
};
FileUploadResult result = await fileService.UploadAsync(request, ct);
// result.Path → "https://cdn.example.com/invoices/2024/a1b2c3d4.pdf"
// result.Extension → ".pdf"
// result.SizeBytes → 204800
// result.SizeKb → 200
Sunucuda dosya adı olarak {Guid}.{extension} formatı kullanılır — özgün dosya adı iletilmez.
Upload — Base64
public sealed class Base64UploadRequest
{
public required string Base64Content { get; init; } // Base64 veya Data URI
public required string Folder { get; init; } // Hedef FTP klasörü
public string? Extension { get; init; } // ".jpg", "jpg" — opsiyonel
}
Base64Content alanı hem saf Base64 hem de data URI formatını kabul eder — prefix otomatik temizlenir:
// Saf Base64
var request = new Base64UploadRequest
{
Base64Content = "iVBORw0KGgoAAAANS...",
Folder = "avatars",
Extension = ".png"
};
// Data URI (mobil uygulamalar ve browser form'larından gelen format)
var request = new Base64UploadRequest
{
Base64Content = "data:image/jpeg;base64,/9j/4AAQSkZJRg...",
Folder = "avatars"
// Extension verilmezse uzantısız yüklenir
};
FileUploadResult result = await fileService.UploadBase64Async(request, ct);
Stream vs Base64 — hangisini seçmeli?
UploadAsync |
UploadBase64Async |
|
|---|---|---|
| Kaynak | IFormFile, FileStream |
API body'den gelen JSON string, browser canvas |
| Boyut bilgisi | Length gerekli |
Otomatik (byte array'den) |
| Dosya adı | FileName'dan uzantı alınır |
Extension parametresinden |
FileUploadResult
public sealed class FileUploadResult
{
public required string Path { get; init; } // HTTPS public URL
public required string Extension { get; init; } // ".jpg", ".pdf" vb.
public long SizeBytes { get; init; } // Dosya boyutu (byte)
public decimal SizeKb => SizeBytes / 1024m; // Hesaplanan değer (KB)
}
var result = await fileService.UploadAsync(request, ct);
Console.WriteLine(result.Path); // https://cdn.example.com/products/a1b2c3.jpg
Console.WriteLine(result.Extension); // .jpg
Console.WriteLine(result.SizeBytes); // 153600
Console.WriteLine(result.SizeKb); // 150
Otomatik Klasör Oluşturma
Folder parametresinde belirtilen dizin yapısı FTP sunucusunda yoksa otomatik olarak oluşturulur. Her segment ayrı ayrı kontrol edilir:
Folder = "products/electronics/images"
│
├── "products" → yoksa oluştur
├── "products/electronics" → yoksa oluştur
└── "products/electronics/images" → yoksa oluştur
Önceden klasör oluşturulması gerekmez — hem UploadAsync hem UploadBase64Async için otomatik çalışır.
Silme
// URL ile
await fileService.RemoveAsync("https://cdn.example.com/avatars/a1b2c3.jpg", ct);
// Göreli path ile
await fileService.RemoveAsync("avatars/a1b2c3.jpg", ct);
Güvenlik: Yalnızca FtpAddress'te tanımlı host'a ait dosyalar silinebilir. Farklı host belirtilirse metod sessizce döner — exception fırlatmaz.
Null/Boş değer: null veya boş string iletilirse metod sessizce döner.
Mimari Notlar
- Her işlemde yeni FTP bağlantısı:
FileServiceher upload/remove işlemindeAsyncFtpClientoluşturur, bağlanır ve işlem sonrası bağlantıyı kapatır. - Download desteği yok:
IFileServiceyalnızca upload ve silme işlemlerini kapsar. Dosya okuma içinPathüzerinden HTTPS ile doğrudan erişim önerilir. - Exists kontrolü yok:
IFileService'te public bir dosya varlık kontrolü metodu bulunmaz. - FTP credentials güvenliği:
FtpAddress,UsernamevePassworddeğerlerini appsettings'te düz metin olarak tutmak yerine Secret Manager veya Azure Key Vault gibi güvenli kaynaklardan yönetin.
Lisans
Bu paket Ledbim Bilişim tarafından geliştirilmektedir. Ticari kullanım için lisans bilgisi için iletişime geçiniz.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | 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. |
-
net10.0
- FluentFTP (>= 52.1.0)
- Ledbim.Core (>= 1.2.0)
- Microsoft.Extensions.Configuration.Abstractions (>= 10.0.0)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.0)
- Microsoft.Extensions.Options.ConfigurationExtensions (>= 10.0.0)
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.2.0 | 162 | 3/28/2026 |