Sindika.AspNet.Common
1.14.3
dotnet add package Sindika.AspNet.Common --version 1.14.3
NuGet\Install-Package Sindika.AspNet.Common -Version 1.14.3
<PackageReference Include="Sindika.AspNet.Common" Version="1.14.3" />
<PackageVersion Include="Sindika.AspNet.Common" Version="1.14.3" />
<PackageReference Include="Sindika.AspNet.Common" />
paket add Sindika.AspNet.Common --version 1.14.3
#r "nuget: Sindika.AspNet.Common, 1.14.3"
#:package Sindika.AspNet.Common@1.14.3
#addin nuget:?package=Sindika.AspNet.Common&version=1.14.3
#tool nuget:?package=Sindika.AspNet.Common&version=1.14.3
Sindika.AspNet.Common.ExcelTemplate
Modul ExcelTemplate menyediakan infrastruktur generik untuk melakukan proses import data dari file Excel secara aman, fleksibel, dan terstruktur. Komponen ini dirancang agar mudah diintegrasikan dengan berbagai modul aplikasi .NET, mendukung validasi, preview, dan commit data dengan metadata berbasis atribut.
🚀 Fitur Utama
- Deklaratif via Attribute — Setiap properti DTO dapat ditandai dengan
ExcelColumnAttributeuntuk mendeskripsikan header kolom, contoh nilai, dan aturan wajib. - Preview Import — Menyediakan hasil pembacaan file Excel tanpa langsung melakukan commit ke database.
- Validasi Otomatis — Setiap sel dapat mengandung informasi error atau peringatan sebelum proses penyimpanan.
- Submit Import — Mendukung commit data berdasarkan hasil preview dengan laporan error yang detail.
- Permission dan Reference Sheet — Menyediakan konteks izin pengguna dan referensi antar sheet untuk validasi silang.
🧩 Struktur Kelas
| Kelas | Deskripsi |
|---|---|
ExcelColumnAttribute |
Menentukan metadata kolom pada DTO, seperti header, contoh, dan status wajib. |
ExcelMetadataAttribute |
Menyimpan metadata tambahan pada level kelas (sheet name, version, dsb). |
ImportPreviewResult<TDto, TEntity> |
Menyimpan hasil preview proses import, termasuk daftar baris dan ringkasan status. |
ImportRowResult<TDto, TEntity> |
Representasi setiap baris dalam hasil import (insert, update, ignore, error). |
ImportCellResult |
Menyimpan status dan pesan validasi untuk setiap sel Excel. |
ImportSummary |
Menyediakan ringkasan hasil import (jumlah insert, update, error, dll). |
ImportSubmitResult<TDto, TEntity> |
Hasil akhir setelah proses commit data ke database. |
ImportSubmitError |
Menyimpan detail kesalahan yang terjadi saat submit. |
ImportRowCategory |
Enum kategori baris (Valid, Invalid, Ignored, Warning). |
ImportAction |
Enum tindakan pada baris (Insert, Update, Delete, Ignore). |
PermissionInfo |
Informasi hak akses pengguna selama proses import. |
ReferenceSheet |
Menyimpan referensi ke sheet lain yang digunakan untuk validasi silang. |
🚀 Implementasi Fitur
- Generate Template Excel Menghasilkan file Excel sesuai metadata atribut pada DTO.
- Preview Import Melakukan validasi awal, menampilkan data yang valid, error, dan status update/insert.
- Submit Import Melakukan proses penyimpanan (insert/update) ke database berdasarkan hasil preview.
📦 Instalasi
Daftarkan modul ExcelTemplate di Program.cs:
builder.Services.AddExcelTools();
🧩 Endpoint Utama
1. Generate Template
[HttpGet("download-template")]
public async Task<IActionResult> DownloadTemplate()
{
var name = User.Claims.FirstOrDefault(c => c.Type == "name")?.Value ?? "Unknown User";
var excelBytes = await _excelTemplateWorkflowService.GenerateTemplateAsync<CostCenterTemplate, CostCenter>(
dataFunc: async () =>
{
return await _costcenterService.GetsAsync<CostCenter>(q => q.Include(c => c.ProfitCenter));
},
author: name,
referenceSheets: new[]
{
new ReferenceSheet
{
SheetName = nameof(ProfitCenter),
EntityType = typeof(ProfitCenter),
Columns = new[] { nameof(ProfitCenter.Id), nameof(ProfitCenter.Code), nameof(ProfitCenter.Name) },
Data = await _profitCenterService.GetsAsync<ProfitCenter>()
}
}
);
return File(excelBytes, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "CostCenterTemplate.xlsx");
}
📄 Hasil: file Excel siap diisi pengguna dengan referensi data ProfitCenter.
2. Preview Import
[HttpPost("preview-import")]
[ProducesResponseType(typeof(BaseResponse<ImportPreviewResult<CostCenterTemplate, CostCenter>, object>), StatusCodes.Status200OK)]
public async Task<IActionResult> PreviewImport(IFormFile file)
{
using var stream = file.OpenReadStream();
var filePath = $"template/{Guid.NewGuid()}{Path.GetExtension(file.FileName)}";
var validator = _excelValidatorFactory.Create<CostCenterTemplate>();
var permission = _excelPermissionFactory.Create<CostCenter>();
var result = await _excelTemplateWorkflowService.PreviewImportAsync<CostCenterTemplate, CostCenter>(
excelStream: stream,
filePath: filePath,
validators: new[] { validator },
permission: permission
);
await _storageService.UploadFile(filePath, stream);
return Ok(ResponseHelper.Success<object>(result, "Preview import successful", _costcenterService.GetInfo()));
}
📊 Hasil: JSON yang menampilkan status per baris (Insert, Update, Skip), validasi field, dan error detail.
3. Submit Import
[HttpPost("submit-import")]
[ProducesResponseType(typeof(BaseResponse<ImportSubmitResult<CostCenterTemplate, CostCenter>, object>), StatusCodes.Status200OK)]
public async Task<IActionResult> SubmitImport([FromBody] BaseRequest<string> request)
{
var stream = await _storageService.GetFile(request.Data);
var validator = _excelValidatorFactory.Create<CostCenterTemplate>();
var permission = _excelPermissionFactory.Create<CostCenter>();
var mapper = _excelMapperFactory.Create<CostCenterTemplate, CostCenter>();
var previewResult = await _excelTemplateWorkflowService.PreviewImportAsync<CostCenterTemplate, CostCenter>(
excelStream: stream,
filePath: request.Data,
validators: new[] { validator },
permission: permission
);
var result = await _excelTemplateWorkflowService.SubmitImportAsync<CostCenterTemplate, CostCenter, Context>(
preview: previewResult,
mapper: mapper,
batchSize: 200);
return Ok(ResponseHelper.Success<object>(result, "Submit import successful", _costcenterService.GetInfo()));
}
✅ Hasil: Data valid tersimpan ke database, hasil akhir menampilkan jumlah baris berhasil dan gagal.
🧱 Struktur Template Class
1. Template DTO
[ExcelMetadata(sheetName: "Template", systemName: "SINPRO", version: "1.0.0", Description = "Template untuk upload master data Cost Center")]
public class CostCenterTemplate
{
[ExcelColumn("Kode Cost Center", true, true, Example = "CST-1")]
public string Code { get; set; } = string.Empty;
[ExcelColumn("Nama Cost Center", true, false, Example = "COST CENTER 1")]
public string Name { get; set; } = string.Empty;
[ExcelColumn("Kode Profit Center", true, false, Example = "XXXX", Reference = "profitcenter.code")]
public string ProfitCenterCode { get; set; } = string.Empty;
[ExcelColumn("", false, false, Ignore = true)]
public Guid ProfitCenterId { get; set; }
[ExcelColumn("User", false, false, Example = "Gus Gus", Width = 100)]
public string CreatedBy { get; set; } = string.Empty;
}
2. Validator
public class CostCenterValidator : IExcelValidator<CostCenterTemplate>
{
private readonly IProfitCenterRepository _profitCenterRepository;
public CostCenterValidator(IProfitCenterRepository profitCenterRepository)
{
_profitCenterRepository = profitCenterRepository;
}
public async Task<List<string>> ValidateAsync(CostCenterTemplate dto)
{
var profitCenters = await _profitCenterRepository.GetsAsync();
var dict = profitCenters.ToDictionary(c => c.Code);
var errors = new List<string>();
if (!dict.TryGetValue(dto.ProfitCenterCode, out var profitCenter))
errors.Add($"ProfitCenterCode '{dto.ProfitCenterCode}' tidak ditemukan");
else dto.ProfitCenterId = profitCenter.Id;
return errors;
}
}
3. Permission
public class CostCenterPermission : IExcelPermission<CostCenter>
{
private readonly ICostCenterRepository _repo;
public CostCenterPermission(ICostCenterRepository repo) => _repo = repo;
public async Task<IDictionary<string, PermissionInfo<CostCenter>>> PermissionAsync()
{
var list = await _repo.GetsAsync(q => q.Where(c => !string.IsNullOrWhiteSpace(c.Code)));
return list.ToDictionary(c => c.Code, c => new PermissionInfo<CostCenter> { Allowed = true, Entity = c });
}
}
4. Mapper
public class CostCenterMapper : IExcelMapper<CostCenterTemplate, CostCenter>
{
public async Task<CostCenter> MapAsync(CostCenterTemplate dto, CostCenter? existing)
{
await Task.CompletedTask;
if (existing == null) return dto.Adapt<CostCenter>();
dto.Adapt(existing);
existing.UpdatedDate = DateTimeOffset.UtcNow;
return existing;
}
}
🪪 Lisensi
© PT Sinergi Dimensi Informatika
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | 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 was computed. 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. |
-
net9.0
- ClosedXML (>= 0.101.0)
- DynamicExpresso.Core (>= 2.19.3)
- Mapster (>= 7.4.0)
- Microsoft.EntityFrameworkCore.Tools (>= 9.0.0)
- Npgsql.EntityFrameworkCore.PostgreSQL (>= 9.0.0)
- Sindika.AspNet.Exception (>= 1.0.0)
- Sindika.AspNet.QueryBuilder (>= 1.5.0)
- Sindika.AspNet.RequestResponse (>= 1.3.1)
- StackExchange.Redis (>= 2.8.16)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on Sindika.AspNet.Common:
| Package | Downloads |
|---|---|
|
Sindika.AspNet.Authentication
Package Description |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.14.3 | 105 | 3/26/2026 |
| 1.14.2 | 104 | 2/9/2026 |
| 1.14.1 | 144 | 12/31/2025 |
| 1.14.0 | 115 | 12/31/2025 |
| 1.13.2 | 166 | 12/30/2025 |
| 1.13.1 | 108 | 12/29/2025 |
| 1.13.0 | 102 | 12/29/2025 |
| 1.12.0 | 192 | 12/23/2025 |
| 1.11.3 | 160 | 1/23/2026 |
| 1.11.2 | 136 | 1/2/2026 |
| 1.11.1 | 555 | 12/12/2025 |
| 1.11.0 | 148 | 12/12/2025 |
| 1.10.6 | 580 | 12/10/2025 |
| 1.10.5 | 194 | 11/28/2025 |
| 1.10.4 | 242 | 11/5/2025 |
| 1.10.3 | 221 | 11/4/2025 |
| 1.10.2 | 226 | 11/4/2025 |
| 1.10.1 | 161 | 11/1/2025 |
| 1.10.0 | 196 | 10/31/2025 |
| 1.9.0 | 317 | 10/8/2025 |