Asp.Net Core Mino Usage
What is Minio?
MinIO is an Amazon S3 compatible server-side software storage, which stores image, video, log, files etc.
Development Environment
- Windows 10
- Asp.net Core 3.1
Installing and Running Operations
We download minio from link. The Link is for Windows, We look link for macos and linux-like platforms, see this link.
After downloading Minio, We run cmdfrom file location. We create folder named "test" in the folder where is "minio.exe".
Minio's default username and password are "minioadmin". You can use following commands for change password
1 2 |
set MINIO_ROOT_USER=admin set MINIO_ROOT_PASSWORD=12345678 |
MinIo aşağıdaki komut ile ayağa kalkacaktır.
1 |
minio.exe server \test |
127.0.0.1:9000 is Minio url
We add bucket named "testbucket" to minio
Usage in .Net Core Projects
Firstly, We install Amazon.S3 package.
1 |
Install-Package AWSSDK.S3 |
We create minio settings in appsettings.json
1 2 3 4 5 6 |
"MinioAccessInfo": { "SecretKey": "admin", "Password": "12345678", "EndPoint": "http://127.0.0.1:9000", "BucketName": "testbucket" } |
Let's write the service that will do the file uploadand fetching
1 2 3 4 5 |
public interface IFileOperation { Task<string> UploadFile(IFormFile file); string GetFile(string key); } |
Let's create the client with the relevant settings in the constructor of the FileOperationclass.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
public class FileOperation:IFileOperation { private IConfiguration Configuration { get; set; } private ILogger<FileOperation> Logger { get; set; } private string minioSecretkey => Configuration["MinioAccessInfo:SecretKey"]; private string minIoPassword => Configuration["MinioAccessInfo:Password"]; private string minIoEndPoint => Configuration["MinioAccessInfo:EndPoint"]; private string bucketName => Configuration["MinioAccessInfo:BucketName"]; private readonly AmazonS3Client _client; public FileOperation(IConfiguration Configuration,ILogger<FileOperation> logger) { this.Configuration = Configuration; this.Logger = logger; var config = new AmazonS3Config { RegionEndpoint = RegionEndpoint.GetBySystemName("us-east-1"), ServiceURL = minIoEndPoint, ForcePathStyle = true, SignatureVersion = "2" }; _client = new AmazonS3Client(minioSecretkey, minIoPassword, config); } |
File Upload Function:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
public async Task<string> UploadFile(IFormFile file) { var key = String.Empty; try { key = Guid.NewGuid().ToString(); var stream = file.OpenReadStream(); var request = new PutObjectRequest() { BucketName = bucketName, InputStream = stream, AutoCloseStream = true, Key = key, ContentType = file.ContentType }; var encodedFilename = Uri.EscapeDataString(file.FileName); request.Metadata.Add("original-filename", encodedFilename); request.Headers.ContentDisposition = $"attachment; filename=\"{encodedFilename}\""; await _client.PutObjectAsync(request); } catch (Exception e) { Logger.LogError("Error ocurred In UploadFileAsync", e); } return key; } |
We set Guid to key because every file we upload must have a unique name
File Call Function:
1 2 3 4 5 6 7 8 9 10 11 |
public string GetFile(string key) { if (string.IsNullOrEmpty(key)) return null; return _client.GetPreSignedURL(new GetPreSignedUrlRequest() { BucketName = bucketName, Key = key, Expires = DateTime.Now.AddMinutes(30) }); } |
Let's create scope of the services in startup.cs
Let's make operations of file upload and view with a simple ui design.
Entity:
We create entity named "File".
1 2 3 4 5 6 7 |
public class File { [Key] public string Key { get; set; } public string Name { get; set; } public string ContentType { get; set; } } |
Controller:
1 2 3 4 |
public async Task<IActionResult> Index() { return View(); } |
View:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
@model MostUsedLibraries.Domain.ViewModels.FileUploadViewModel <div class="panel"> <form enctype="multipart/form-data" method="post" class="form"> <dl> <dt> <label asp-for="File"></label> </dt> <dd> <input asp-for="File" type="file"> </dd> </dl> <input asp-page-handler="Upload" class="btn btn-success" type="submit" value="Dosyayı Sisteme Yükle"> </form> </div> <br /> <br /> <a class="btn btn-primary" href="home/allImages">Yüklü Resimleri gör</a> <br /> <br /> <a class="btn btn-secondary" href="home/allpdf">Yüklü Pdfleri gör</a> |
Post Controller:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
[HttpPost] public async Task<IActionResult> Index(IFormFile file) { var key = await FileOperation.UploadFile(file); var entity = new File { ContentType = file.ContentType, Key = key, Name = file.FileName }; Db.Add(entity); Db.SaveChanges(); return View(); } |
With these actions, the files have been successfully uploaded.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
public IActionResult AllImages() { var images = Db.Files.Where(f => f.ContentType == "image/png").ToList(); var files = new List<string>(); images.ForEach(im => files.Add(FileOperation.GetFile(im.Key).Replace("https","http"))); return View(files); } public IActionResult AllPdf() { var images = Db.Files.Where(f => f.ContentType == "application/pdf").ToList(); var files = new Dictionary<string,string>(); images.ForEach(im => files.Add(FileOperation.GetFile(im.Key), im.Name)); return View(files); } |
There are two ActionResults. AllImages() function displays png images, AllPdf() lists files whose type is pdf
AllImages View:
1 2 3 4 5 6 7 8 9 |
@model List<string> <h3>Yüklü Resimler</h3> <br /> @foreach (var item in Model) { <img src="@item" alt="Alternate Text" /> <br /> <br /> } |
AllPdf View:
1 2 3 4 5 6 7 8 9 |
@model Dictionary<string, string> <h3>Yüklü Pdf listesi</h3> <br /> @foreach (var item in Model) { <a href="@item.Key.Replace("https","http")">@item.Value</a> <br /> <br /> } |
Başka bir yazıda görüşmek üzere 🙂