![]() |
VOOZH | about |
dotnet add package Linger.Excel.Contracts --version 1.4.2
NuGet\Install-Package Linger.Excel.Contracts -Version 1.4.2
<PackageReference Include="Linger.Excel.Contracts" Version="1.4.2" />
<PackageVersion Include="Linger.Excel.Contracts" Version="1.4.2" />Directory.Packages.props
<PackageReference Include="Linger.Excel.Contracts" />Project file
paket add Linger.Excel.Contracts --version 1.4.2
#r "nuget: Linger.Excel.Contracts, 1.4.2"
#:package Linger.Excel.Contracts@1.4.2
#addin nuget:?package=Linger.Excel.Contracts&version=1.4.2Install as a Cake Addin
#tool nuget:?package=Linger.Excel.Contracts&version=1.4.2Install as a Cake Tool
A unified, efficient, and extensible Excel operation framework that supports multiple Excel library implementations
| Implementation | Package Name | Features |
|---|---|---|
| NPOI | Linger.Excel.Npoi |
No Office required, supports .xls and .xlsx |
| EPPlus | Linger.Excel.EPPlus |
High performance, supports richer Excel features |
| ClosedXML | Linger.Excel.ClosedXML |
User-friendly API, good performance |
βββββββββββββββββββ
β IExcelService β βββββ Non-generic interface, provides basic Excel operations
ββββββββββ¬βββββββββ
β
βinherits
βΌ
βββββββββββββββββββββββ
β IExcel<TWorksheet> β βββββ Generic interface, inherits IExcelService and provides advanced operations (with Action delegates)
ββββββββββ¬βββββββββββββ
β
βimplements
βΌ
βββββββββββββββββββββββββββββββ
βAbstractExcelService<T1,T2> β βββββ Abstract base class, implements common logic and backward compatibility methods
ββββββββββββββ¬βββββββββββββββββ
β
βinherits
βΌ
βββββββββββββββββββββββββββββββ
β ExcelBase<TWorkbook,TSheet> β βββββ Excel implementation base, more common logic
ββββββββββββββ¬βββββββββββββββββ
β
βinherits
βΌ
βββββββββββββββββββββββββββββββ
β Concrete Implementation β βββββ Specific Excel library implementation
β(NpoiExcel, EPPlusExcel, etc)β
βββββββββββββββββββββββββββββββ
Design Highlights:
IExcel<TWorksheet> inherits from IExcelService, automatically gaining all basic methodsAction<TWorksheet> parameters without affecting basic usage# Install core interface package
dotnet add package Linger.Excel.Contracts
# Install your chosen implementation
dotnet add package Linger.Excel.Npoi
# or
dotnet add package Linger.Excel.ClosedXML
// In Startup.cs or Program.cs
// NPOI implementation
services.AddExcelNpoi(options =>
{
options.DefaultDateFormat = "yyyy-MM-dd";
options.EnableFormulaEvaluation = true;
});
// Or use ClosedXML implementation
services.AddExcelClosedXML(options =>
{
options.DefaultDateFormat = "yyyy-MM-dd";
options.AutoFitColumns = true;
});
public class ExcelReportService
{
private readonly IExcelService _excelService;
public ExcelReportService(IExcelService excelService)
{
_excelService = excelService;
}
public List<User> ImportUsers(string filePath)
{
return _excelService.ExcelToList<User>(filePath) ?? new List<User>();
}
public string ExportUsers(List<User> users, string filePath)
{
return _excelService.CollectionToExcel(users, filePath, "UserList");
}
public async Task<string> ExportUsersAsync(List<User> users, string filePath)
{
// True async file I/O
return await _excelService.CollectionToExcelAsync(users, filePath, "UserList");
}
}
Use the import extension overloads when you want to avoid reflection during object materialization:
using Linger.Excel.Contracts;
using Linger.Extensions.Data;
var users = excelService.ExcelToList(
filePath,
row => new User
{
Id = Convert.ToInt32(row["Id"]),
Name = row["Name"]?.ToString() ?? string.Empty
});
var imported = await excelService.ExcelToListAsync(
filePath,
() => new ImportUser("excel"),
new Dictionary<string, Action<ImportUser, object?>>
{
["Id"] = DataTableExtensions.CreateColumnSetter<ImportUser, int>((user, value) => user.Id = value),
["Name"] = DataTableExtensions.CreateColumnSetter<ImportUser, string?>((user, value) => user.Name = value)
});
These overloads first import Excel into a DataTable, then reuse the existing AOT-friendly DataTable mapping APIs.
Use explicit columns when you want to avoid reflection during collection export and template generation:
using Linger.Excel.Contracts;
var columns = new[]
{
new ExcelExportColumn<User>("User Id", user => user.Id, typeof(int)),
new ExcelExportColumn<User>("Name", user => user.Name, typeof(string)),
new ExcelExportColumn<User>("Department", user => user.Department, typeof(string))
};
await excelService.CollectionToExcelAsync(users, columns, filePath, "Users");
using var template = excelService.CreateExcelTemplate(columns, "Users");
These overloads build a DataTable from explicit column definitions and then reuse the existing DataTable export pipeline, so no property reflection is required.
Provides all fundamental Excel import/export functionality:
public interface IExcelService
{
#region Import Functions
// Import single worksheet as DataTable
DataTable? ExcelToDataTable(string filePath, string? sheetName = null, int headerRowIndex = 0, bool addEmptyRow = false);
DataTable? StreamToDataTable(Stream stream, string? sheetName = null, int headerRowIndex = 0, bool addEmptyRow = false);
// Import single worksheet as object list
List<T>? ExcelToList<T>(string filePath, string? sheetName = null, int headerRowIndex = 0, bool addEmptyRow = false) where T : class, new();
List<T>? StreamToList<T>(Stream stream, string? sheetName = null, int headerRowIndex = 0, bool addEmptyRow = false) where T : class, new();
// Import entire workbook as DataSet (multiple overloads)
DataSet? ExcelToDataSet(string filePath, int headerRowIndex = 0, bool addEmptyRow = false);
DataSet? ExcelToDataSet(string filePath, IEnumerable<string>? sheetNames, int headerRowIndex = 0, bool addEmptyRow = false);
DataSet? ExcelToDataSet(string filePath, Func<string, int?> headerRowIndexSelector, bool addEmptyRow = false);
DataSet? StreamToDataSet(Stream stream, int headerRowIndex = 0, bool addEmptyRow = false);
DataSet? StreamToDataSet(Stream stream, IEnumerable<string>? sheetNames, int headerRowIndex = 0, bool addEmptyRow = false);
DataSet? StreamToDataSet(Stream stream, Func<string, int?> headerRowIndexSelector, bool addEmptyRow = false);
// Async imports - True async file I/O
Task<DataTable?> ExcelToDataTableAsync(string filePath, string? sheetName = null, int headerRowIndex = 0, bool addEmptyRow = false);
Task<List<T>?> ExcelToListAsync<T>(string filePath, string? sheetName = null, int headerRowIndex = 0, bool addEmptyRow = false) where T : class, new();
Task<DataSet?> ExcelToDataSetAsync(string filePath, int headerRowIndex = 0, bool addEmptyRow = false);
Task<DataSet?> ExcelToDataSetAsync(string filePath, IEnumerable<string>? sheetNames, int headerRowIndex = 0, bool addEmptyRow = false);
Task<DataSet?> ExcelToDataSetAsync(string filePath, Func<string, int?> headerRowIndexSelector, bool addEmptyRow = false);
// Async Stream processing - Virtual methods, subclasses can override for true async
Task<DataTable?> StreamToDataTableAsync(Stream stream, string? sheetName = null, int headerRowIndex = 0, bool addEmptyRow = false);
Task<List<T>?> StreamToListAsync<T>(Stream stream, string? sheetName = null, int headerRowIndex = 0, bool addEmptyRow = false) where T : class, new();
Task<DataSet?> StreamToDataSetAsync(Stream stream, int headerRowIndex = 0, bool addEmptyRow = false);
Task<DataSet?> StreamToDataSetAsync(Stream stream, IEnumerable<string>? sheetNames, int headerRowIndex = 0, bool addEmptyRow = false);
Task<DataSet?> StreamToDataSetAsync(Stream stream, Func<string, int?> headerRowIndexSelector, bool addEmptyRow = false);
#endregion
#region Export Functions
// Export to Excel file
string DataTableToExcel(DataTable dataTable, string fullFileName, string sheetsName = "Sheet1", string title = "");
string DataSetToExcel(DataSet dataSet, string fullFileName, string defaultSheetName = "Sheet");
string CollectionToExcel<T>(List<T> list, string fullFileName, string sheetsName = "Sheet1", string title = "") where T : class;
// Export to memory stream
MemoryStream CollectionToMemoryStream<T>(List<T> list, string sheetsName = "Sheet1", string title = "") where T : class;
MemoryStream DataTableToMemoryStream(DataTable dataTable, string sheetsName = "Sheet1", string title = "");
// Async exports
Task<string> DataTableToExcelAsync(DataTable dataTable, string fullFileName, string sheetsName = "Sheet1", string title = "");
Task<string> CollectionToExcelAsync<T>(List<T> list, string fullFileName, string sheetsName = "Sheet1", string title = "") where T : class;
// Create template
MemoryStream CreateExcelTemplate<T>() where T : class, new();
#endregion
}
Inherits from IExcelService and provides advanced customization with Action<TWorksheet> delegates:
public interface IExcel<out TWorksheet> : IExcelService where TWorksheet : class
{
#region Advanced Export Functions - Support Custom Operations
// Export with custom cell and style operations
string DataTableToExcel(DataTable dataTable, string fullFileName, string sheetsName = "Sheet1", string title = "",
Action<TWorksheet, DataColumnCollection, DataRowCollection>? action = null,
Action<TWorksheet>? styleAction = null);
string DataSetToExcel(DataSet dataSet, string fullFileName, string defaultSheetName = "Sheet",
Action<TWorksheet, DataColumnCollection, DataRowCollection>? action = null,
Action<TWorksheet>? styleAction = null);
string CollectionToExcel<T>(List<T> list, string fullFileName, string sheetsName = "Sheet1", string title = "",
Action<TWorksheet, PropertyInfo[]>? action = null,
Action<TWorksheet>? styleAction = null) where T : class;
MemoryStream CollectionToMemoryStream<T>(List<T> list, string sheetsName = "Sheet1", string title = "",
Action<TWorksheet, PropertyInfo[]>? action = null,
Action<TWorksheet>? styleAction = null) where T : class;
MemoryStream DataTableToMemoryStream(DataTable dataTable, string sheetsName = "Sheet1", string title = "",
Action<TWorksheet, DataColumnCollection, DataRowCollection>? action = null,
Action<TWorksheet>? styleAction = null);
// Async exports
Task<string> DataTableToExcelAsync(DataTable dataTable, string fullFileName, string sheetsName = "Sheet1", string title = "",
Action<TWorksheet, DataColumnCollection, DataRowCollection>? action = null,
Action<TWorksheet>? styleAction = null);
Task<string> CollectionToExcelAsync<T>(List<T> list, string fullFileName, string sheetsName = "Sheet1", string title = "",
Action<TWorksheet, PropertyInfo[]>? action = null,
Action<TWorksheet>? styleAction = null) where T : class;
#endregion
}
Interface Usage Recommendations:
IExcelService for most import/export needsIExcel<TWorksheet> when you need custom cell styles, merged cells, etc.IExcel<TWorksheet> instances can be upcast to IExcelServiceAsync Implementation Notes:
FileStream with useAsync: true)Task.Run to wrap sync methods (library limitation)StreamToXXXAsync methods for custom async implementationsExcelToDataSet allows you to import an entire Excel workbook or specified worksheets as a DataSet, where each worksheet corresponds to a DataTable:
// 1. Import all worksheets with uniform header row (row 0)
DataSet? allSheets = excelService.ExcelToDataSet("workbook.xlsx", headerRowIndex: 0);
// 2. Import only specified worksheets
var selectedSheets = new[] { "UserData", "OrderData", "ProductData" };
DataSet? specificSheets = excelService.ExcelToDataSet("workbook.xlsx", selectedSheets, headerRowIndex: 0);
// 3. Specify different header rows for each worksheet
DataSet? flexibleHeaders = excelService.ExcelToDataSet("workbook.xlsx", sheetName =>
{
return sheetName switch
{
"UserData" => 0, // Row 1 is header
"Financial" => 2, // Row 3 is header (skip first 2 rows)
"RawData" => null, // No header, all rows are data rows
_ => 0 // Default: row 1 is header
};
});
// 4. Async import
DataSet? result = await excelService.ExcelToDataSetAsync("large-workbook.xlsx", headerRowIndex: 0);
// 5. Backward compatibility mode - compatible with old NPOIHelper.ImportExcelToDs method
// Supports comma-separated worksheet name strings
DataSet? compatibleResult = excelService.ExcelToDataSet("workbook.xlsx", "Sheet1,Sheet2,Sheet3", headerRowIndex: 0);
DataSet? asyncCompatible = await excelService.ExcelToDataSetAsync("workbook.xlsx", "UserData, OrderData", headerRowIndex: 1);
// Access imported data
if (result is not null)
{
foreach (DataTable table in result.Tables)
{
Console.WriteLine($"Worksheet: {table.TableName}, Rows: {table.Rows.Count}, Columns: {table.Columns.Count}");
}
}
Parameter Description:
headerRowIndex: Header row index (0-based). All worksheets use the same header rowsheetNames:
IEnumerable<string>? - List of worksheet names to import. Pass null or empty collection to import all worksheetsstring? - Comma-separated worksheet name string (backward compatible). Automatically handles whitespace, pass null to import all worksheetsheaderRowSelector: Specify different header rows for each worksheet. Pass worksheet name, return header row index for that worksheetaddEmptyRow: Whether to include empty rows. Default is falseBackward Compatibility:
The framework provides fully compatible method signatures with the legacy NPOIHelper.ImportExcelToDs, allowing migration without modifying existing code.
DataSet dataSet = new DataSet();
dataSet.Tables.Add(CreateUserTable());
dataSet.Tables.Add(CreateOrderTable());
dataSet.Tables.Add(CreateProductTable());
// Export DataSet, each DataTable becomes a worksheet
string filePath = excelService.DataSetToExcel(dataSet, "multi-sheet-workbook.xlsx");
Use the advanced overload methods in IExcel<TWorksheet> interface to customize cell operations during export:
// Inject IExcel<TWorksheet> instead of IExcelService
public class AdvancedExcelService
{
private readonly IExcel<ISheet> _npoiExcel; // NPOI's worksheet type is ISheet
public AdvancedExcelService(IExcel<ISheet> npoiExcel)
{
_npoiExcel = npoiExcel;
}
public string ExportWithCustomStyle(List<User> users, string filePath)
{
return _npoiExcel.CollectionToExcel(users, filePath, "UserList", "User Data Report",
// Custom cell operations
action: (sheet, properties) =>
{
// Access native ISheet object for advanced operations
var row = sheet.GetRow(0);
row.Height = 500; // Set header row height
// Merge cells
sheet.AddMergedRegion(new CellRangeAddress(0, 0, 0, properties.Length - 1));
},
// Custom style operations
styleAction: (sheet) =>
{
// Set column widths
sheet.SetColumnWidth(0, 3000);
sheet.SetColumnWidth(1, 5000);
// Freeze panes
sheet.CreateFreezePane(0, 2);
}
);
}
}
Use attributes to control how object properties map to Excel columns:
public class User
{
[ExcelColumn(Index = 0, Name = "User ID")]
public int Id { get; set; }
[ExcelColumn(Index = 1, Name = "Username")]
public string Username { get; set; }
[ExcelColumn(Index = 2, Name = "Email Address", Width = 30)]
public string Email { get; set; }
[ExcelColumn(Index = 3, Name = "Registration Date", Format = "yyyy-MM-dd")]
public DateTime RegistrationDate { get; set; }
[ExcelColumn(Ignore = true)]
public string Password { get; set; }
}
// Use IExcel<TWorksheet> advanced overloads for style customization
public class StyledExcelService
{
private readonly IExcel<ISheet> _npoiExcel;
public StyledExcelService(IExcel<ISheet> npoiExcel)
{
_npoiExcel = npoiExcel;
}
public string ExportWithStyles(List<User> users, string filePath)
{
return _npoiExcel.CollectionToExcel(users, filePath, "UserData", "User Information",
styleAction: (sheet) =>
{
// Create styles
var workbook = sheet.Workbook;
var headerStyle = workbook.CreateCellStyle();
var headerFont = workbook.CreateFont();
// Header style
headerFont.IsBold = true;
headerFont.FontHeightInPoints = 12;
headerFont.Color = IndexedColors.White.Index;
headerStyle.SetFont(headerFont);
headerStyle.FillForegroundColor = IndexedColors.Blue.Index;
headerStyle.FillPattern = FillPattern.SolidForeground;
// Apply to header row
var headerRow = sheet.GetRow(1); // Row 2 is data header
for (int i = 0; i < headerRow.LastCellNum; i++)
{
headerRow.GetCell(i)?.SetCellStyle(headerStyle);
}
// Auto-size columns
for (int i = 0; i < headerRow.LastCellNum; i++)
{
sheet.AutoSizeColumn(i);
}
}
);
}
}
// Async export of large datasets
var largeDataList = GetLargeDataSet(); // Assume 100k records
// Use true async I/O
string filePath = await excelService.CollectionToExcelAsync(
largeDataList,
"huge_data.xlsx",
"DataExport"
);
Console.WriteLine($"Export completed: {filePath}");
Note: Template functionality implementation depends on the chosen Excel library. Please refer to the specific implementation library's documentation.
public class MyCustomExcel : AbstractExcelService<MyWorkbook, MyWorksheet>
{
public MyCustomExcel(ExcelOptions? options = null) : base(options) { }
// Implement abstract methods...
protected override MyWorkbook CreateWorkbookInternal() { /* ... */ }
protected override MyWorksheet GetWorksheetInternal(MyWorkbook workbook, string sheetName) { /* ... */ }
// More method implementations...
}
// Register custom implementation
services.AddSingleton<IExcelService, MyCustomExcel>();
services.AddSingleton<IExcel<MyWorksheet>, MyCustomExcel>();
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 net5.0 was computed. net5.0-windows net5.0-windows was computed. net6.0 net6.0 was computed. net6.0-android net6.0-android was computed. net6.0-ios net6.0-ios was computed. net6.0-maccatalyst net6.0-maccatalyst was computed. net6.0-macos net6.0-macos was computed. net6.0-tvos net6.0-tvos was computed. net6.0-windows net6.0-windows was computed. net7.0 net7.0 was computed. net7.0-android net7.0-android was computed. net7.0-ios net7.0-ios was computed. net7.0-maccatalyst net7.0-maccatalyst was computed. net7.0-macos net7.0-macos was computed. net7.0-tvos net7.0-tvos was computed. net7.0-windows net7.0-windows was computed. net8.0 net8.0 is compatible. net8.0-android net8.0-android was computed. net8.0-browser net8.0-browser was computed. net8.0-ios net8.0-ios was computed. net8.0-maccatalyst net8.0-maccatalyst was computed. net8.0-macos net8.0-macos was computed. net8.0-tvos net8.0-tvos was computed. net8.0-windows net8.0-windows was computed. net9.0 net9.0 is compatible. net9.0-android net9.0-android was computed. net9.0-browser net9.0-browser was computed. net9.0-ios net9.0-ios was computed. net9.0-maccatalyst net9.0-maccatalyst was computed. net9.0-macos net9.0-macos was computed. net9.0-tvos net9.0-tvos was computed. net9.0-windows net9.0-windows was computed. net10.0 net10.0 is compatible. net10.0-android net10.0-android was computed. net10.0-browser net10.0-browser was computed. net10.0-ios net10.0-ios was computed. net10.0-maccatalyst net10.0-maccatalyst was computed. net10.0-macos net10.0-macos was computed. net10.0-tvos net10.0-tvos was computed. net10.0-windows net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 netcoreapp2.0 was computed. netcoreapp2.1 netcoreapp2.1 was computed. netcoreapp2.2 netcoreapp2.2 was computed. netcoreapp3.0 netcoreapp3.0 was computed. netcoreapp3.1 netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 netstandard2.0 is compatible. netstandard2.1 netstandard2.1 was computed. |
| .NET Framework | net461 net461 was computed. net462 net462 was computed. net463 net463 was computed. net47 net47 was computed. net471 net471 was computed. net472 net472 is compatible. net48 net48 was computed. net481 net481 was computed. |
| MonoAndroid | monoandroid monoandroid was computed. |
| MonoMac | monomac monomac was computed. |
| MonoTouch | monotouch monotouch was computed. |
| Tizen | tizen40 tizen40 was computed. tizen60 tizen60 was computed. |
| Xamarin.iOS | xamarinios xamarinios was computed. |
| Xamarin.Mac | xamarinmac xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos xamarinwatchos was computed. |
Showing the top 4 NuGet packages that depend on Linger.Excel.Contracts:
| Package | Downloads |
|---|---|
|
Linger.Excel.Npoi
Excel operations implementation based on NPOI library for the Linger.Excel framework. Provides high-performance Excel file reading, writing, and manipulation capabilities with support for both .xlsx and legacy .xls formats without requiring Microsoft Office. |
|
|
Linger.Excel.ClosedXML
Excel operations implementation based on ClosedXML library for the Linger.Excel framework. Provides high-performance Excel file reading, writing, styling, and manipulation capabilities with a clean, abstracted API. |
|
|
Linger.Excel.EPPlus
Excel operations implementation based on EPPlus library for the Linger.Excel framework. Provides high-performance Excel file reading, writing, styling, and manipulation capabilities with a clean, abstracted API. |
|
|
Linger.Excel
Package Description |
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.4.4-preview | 155 | 6/16/2026 |
| 1.4.3-preview | 207 | 6/15/2026 |
| 1.4.2 | 234 | 5/20/2026 |
| 1.4.1-preview | 221 | 5/12/2026 |
| 1.4.0 | 229 | 5/6/2026 |
| 1.3.3-preview | 211 | 5/5/2026 |
| 1.3.2-preview | 217 | 4/29/2026 |
| 1.3.1-preview | 212 | 4/28/2026 |
| 1.3.0-preview | 216 | 4/27/2026 |
| 1.2.0-preview | 231 | 3/29/2026 |
| 1.1.0 | 243 | 2/4/2026 |
| 1.0.3-preview | 239 | 1/9/2026 |
| 1.0.2-preview | 234 | 1/8/2026 |
| 1.0.0 | 442 | 11/12/2025 |
| 1.0.0-preview2 | 298 | 11/6/2025 |
| 1.0.0-preview1 | 296 | 11/5/2025 |
| 0.9.9 | 336 | 10/16/2025 |
| 0.9.8 | 285 | 10/14/2025 |
| 0.9.7-preview | 283 | 10/13/2025 |
| 0.9.6-preview | 250 | 10/12/2025 |