Provides an easy way to export enumerables as Excel spreadsheets and import Excel data back into C# objects. Built on ClosedXML.
- .NET Standard 2.0
Install the LazySpreadsheets NuGet package:
dotnet add package LazySpreadsheetsFor attribute-based configuration, also install:
dotnet add package LazySpreadsheets.AbstractionsTo use preview builds from the main branch:
-
Add GitHub Packages as a NuGet source:
dotnet nuget add source \ --username YOUR_GITHUB_USERNAME \ --password YOUR_GITHUB_PAT \ --store-password-in-clear-text \ --name github \ "https://nuget.pkg.github.com/johnnypen/index.json"
-
Install the preview package:
dotnet add package LazySpreadsheets --prerelease
Note: All packages are strongly-named and signed with Sigstore for security and authenticity.
Comprehensive documentation is available in the /docs folder:
- API Reference - Complete API reference for WorkbookBuilder, WorksheetBuilder, and ColumnBuilder
- Usage Examples - Code examples for simple, intermediate, and advanced export scenarios
- Attributes Reference - Complete reference for all export and import attributes
- Locale & Timezone Support - Comprehensive guide for regional formatting and timezone conversion
- API Reference - Complete API reference for WorkbookReader, WorksheetReader, and PropertyReader
- Usage Examples - Code examples for simple, intermediate, and advanced import scenarios
- Type Conversion - Enhanced parsing for boolean, enum, DateTime, and DateTimeOffset types
- Validation System - Cell-level, value, and row-level validation with error handling
- Value Converters - Named converters, type overrides, and converter resolution hierarchy
- Code Coverage Report - Comprehensive test coverage metrics and quality report (80.7% coverage, 286 tests)
- Quick Start CI/CD Setup - Get your CI/CD pipeline running in 10 minutes
- NuGet Publishing Guide - Complete guide for strong naming, Sigstore signing, and package publishing
- Automated Release Notes - How release notes are auto-generated from commits
- Workflow Triggers - When builds run and why (path filters explained)
- Contributing Guide - Commit message format, development workflow, and code style guidelines
using ClosedXML.Excel;
using LazySpreadsheets.Export;
using LazySpreadsheets.Extensions;
// Simple export
public void SaveToFile(IEnumerable<Book> books)
{
using var workbook = books.ToWorkbook();
workbook.ToFile("my-books.xlsx");
}
// Export with custom formatting
public byte[] SaveToBytes(IEnumerable<Book> books)
{
using var workbook = WorkbookBuilder.Create()
.Sheet(books, sheet => sheet
.Name("Book Prices")
.Column(book => book.Title)
.Column(book => book.Published, col => col
.Header("Publish Date")
.Format(NumberFormats.DateTime)
)
.Column(book => book.Price, col => col
.Format(CellFormats.AccountingGBP)
)
)
.ToWorkbook();
return workbook.ToBytes();
}LazySpreadsheets supports automatic date/time formatting based on culture and timezone conversion:
using LazySpreadsheets.Export;
// Export with regional date formatting and timezone conversion
public IXLWorkbook ExportWithLocaleAndTimezone(IEnumerable<Event> events)
{
return WorkbookBuilder.Create()
.UseLocale("en-US") // Format dates as MM/DD/YYYY
.UseTimezone("America/New_York") // Convert to Eastern Time
.Sheet(events, sheet => sheet
.Column(e => e.EventTimeUtc) // Auto-converts UTC properties
.Column(e => e.LocalTime, c => c
.SourceTimezone("Europe/London")) // Explicit source timezone
.Column(e => e.EventName)
)
.ToWorkbook();
}Features:
.UseLocale(culture)- Apply culture-specific date/time formatting (e.g., "en-US", "fr-FR", "de-DE").UseTimezone(timezone)- Convert dates to target timezone (IANA IDs or UTC offsets like "+01:00").SourceTimezone(timezone)- Specify source timezone for individual columns- Auto-detection - Properties ending with "Utc" or "UTC" are automatically converted from UTC
using LazySpreadsheets.Import;
// Simple import - no sheet name needed if only one sheet per type
public List<Book> ImportBooks(string filePath)
{
using var reader = WorkbookReader.FromFile(filePath);
reader.Sheet<Book>(sheet => sheet
.Name("Books")
.AutoMapProperties() // Automatically maps properties by name/DisplayName attribute
);
var result = reader.Import<Book>(); // Sheet name optional when only one sheet of this type
return result.Data.ToList();
}
// Import with custom configuration and validation
public List<Book> ImportBooksWithValidation(string filePath)
{
using var reader = WorkbookReader.FromFile(filePath);
reader.Sheet<Book>(sheet => sheet
.Name("Books")
.Column(book => book.Title, col => col
.Header("Book Title")
.Required()
)
.Column(book => book.Price, col => col
.Validate(price => price > 0, "Price must be positive")
)
.Column(book => book.Published, col => col
.Header("Publish Date")
)
.ValidateRow((book, context) => {
var errors = new List<string>();
if (book.Published > DateTime.Now)
errors.Add("Publish date cannot be in the future");
return errors;
})
);
var result = reader.ImportWithValidation<Book>(); // Or specify sheet name explicitly
if (!result.IsSuccess)
{
// Handle validation errors
foreach (var row in result.Rows.Where(r => !r.IsSuccess))
{
Console.WriteLine($"Row {row.RowNumber} has errors:");
foreach (var cell in row.Cells.Where(c => !c.IsSuccess))
{
Console.WriteLine($" {cell.ColumnName}: {string.Join(", ", cell.ErrorMessages)}");
}
}
}
return result.Data.ToList();
}# Restore dependencies
dotnet restore
# Build the solution
dotnet build
# Build in release mode
dotnet build -c Release
# Run tests
dotnet test
# Pack as NuGet packages
dotnet packSee LICENSE for details.