Skip to content

Commit 827f5f7

Browse files
authored
Merge pull request #66 from PandaTechAM/development
v5
2 parents ab6c475 + ab93231 commit 827f5f7

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

56 files changed

+1772
-2131
lines changed

FileExporter.sln

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@ VisualStudioVersion = 17.6.33723.286
55
MinimumVisualStudioVersion = 10.0.40219.1
66
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FileExporter", "src\FileExporter\FileExporter.csproj", "{37F75643-3F86-437F-9C88-21AD8C84E6B1}"
77
EndProject
8-
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FileExporter.Tests", "test\FileExporter.Tests\FileExporter.Tests.csproj", "{9828695B-4FB0-4D29-9F19-469A369DA131}"
9-
EndProject
108
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FileExporter.Demo", "test\FileExporter.Demo\FileExporter.Demo.csproj", "{4EBD2CC6-CA15-495C-AE54-337B23152710}"
119
EndProject
1210
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{1E6E6EA8-2623-46DA-8A61-53429EBCFE0D}"
@@ -32,10 +30,6 @@ Global
3230
{37F75643-3F86-437F-9C88-21AD8C84E6B1}.Debug|Any CPU.Build.0 = Debug|Any CPU
3331
{37F75643-3F86-437F-9C88-21AD8C84E6B1}.Release|Any CPU.ActiveCfg = Release|Any CPU
3432
{37F75643-3F86-437F-9C88-21AD8C84E6B1}.Release|Any CPU.Build.0 = Release|Any CPU
35-
{9828695B-4FB0-4D29-9F19-469A369DA131}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
36-
{9828695B-4FB0-4D29-9F19-469A369DA131}.Debug|Any CPU.Build.0 = Debug|Any CPU
37-
{9828695B-4FB0-4D29-9F19-469A369DA131}.Release|Any CPU.ActiveCfg = Release|Any CPU
38-
{9828695B-4FB0-4D29-9F19-469A369DA131}.Release|Any CPU.Build.0 = Release|Any CPU
3933
{4EBD2CC6-CA15-495C-AE54-337B23152710}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
4034
{4EBD2CC6-CA15-495C-AE54-337B23152710}.Debug|Any CPU.Build.0 = Debug|Any CPU
4135
{4EBD2CC6-CA15-495C-AE54-337B23152710}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -50,6 +44,5 @@ Global
5044
GlobalSection(NestedProjects) = preSolution
5145
{37F75643-3F86-437F-9C88-21AD8C84E6B1} = {4459D40A-17C0-4B8D-9F8A-5CBD596EB80E}
5246
{4EBD2CC6-CA15-495C-AE54-337B23152710} = {72F33894-D89A-4D2F-B897-58F7CD1F381E}
53-
{9828695B-4FB0-4D29-9F19-469A369DA131} = {72F33894-D89A-4D2F-B897-58F7CD1F381E}
5447
EndGlobalSection
5548
EndGlobal

README.md

Lines changed: 160 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -1,143 +1,200 @@
1-
# FileExporter
1+
# PandaTech.FileExporter
22

3-
FileExporter is a lightweight C# library that simplifies file export operations in .NET applications. With support for
4-
exporting data to CSV, Excel (XLSX), and PDF formats, FileExporter provides an intuitive interface for developers to
5-
quickly generate and download files.
3+
**Blazing‑fast, flexible, convention‑first CSV/XLSX exporter for .NET 9+**\
4+
Powered internally by two battle‑tested libraries:\
65

7-
## Features
6+
- **CsvHelper** --- industry‑standard CSV writer\
7+
- **SpreadCheetah** --- extremely fast, fully streaming XLSX generator
88

9-
- **Easy Exporting**: Simply call ToCsv(), ToXlsx(), or ToPdf() on your data collection to export to the desired format.
10-
- **Automatic Splitting**: Handles large datasets by automatically splitting files if the maximum line count or file
11-
size is exceeded, then zipping them for easy download.
12-
- **Flexible Configuration**: Customize export settings such as column headers, delimiter, and more to suit your needs.
13-
- **Effortless Integration**: Seamlessly integrate FileExporter into your existing .NET projects with minimal setup.
14-
- **Helper Extension Methods**: Use ToFileFormat(ExportType.Excel) as an alternative to directly calling ToCsv(),
15-
ToXlsx(), or ToPdf().
9+
`PandaTech.FileExporter` focuses on **performance**, **stability**, and
10+
**developer happiness**.\
11+
Version **5.x is a complete redesign** of 4.x --- simpler, safer,
12+
faster. API is fully modernized (minimal APIs, DI‑friendly,
13+
async‑ready).
1614

17-
## Installation
15+
> ⚠️ **Breaking Change Notice**\
16+
> v5 breaks compatibility with v4. Migration is straightforward: - enums
17+
> changed values --- **do not reuse v4 enum values** - PDF support
18+
> removed (too slow, not worth maintaining) - All exporters rebuilt
19+
> around a simpler, more predictable format system
1820
19-
You can install FileExporter via NuGet Package Manager by running the following command:
21+
------------------------------------------------------------------------
2022

21-
```bash
22-
Install-Package FileExporter
23-
```
23+
## ✨ Features
2424

25-
## Usage
25+
- **Convention‑based export** (zero config)\
26+
- **Fluent export rules** via `ExportRule<T>`\
27+
- **Super‑fast XLSX via SpreadCheetah** (safe for millions of rows)\
28+
- **CSV export** using CsvHelper\
29+
- **Automatic ZIP compression** when file size is large\
30+
- **Multi‑sheet XLSX** for datasets \> 1M rows\
31+
- **Async streaming support** (`IAsyncEnumerable<T>`)\
32+
- **Custom formatting & transforms**\
33+
- **Minimal API ready**\
34+
- **Simple DI registration**\
35+
- **No controllers required**
2636

27-
Here's a quick example of how to use FileExporter to export data to a CSV file with old way which is still supported:
37+
------------------------------------------------------------------------
2838

29-
```csharp
30-
using FileExporter;
39+
## 🚀 Installation
3140

32-
// Define your data
33-
var data = new List<MyDataClass>
34-
{
35-
new MyDataClass { Name = "John Doe", Age = 30, Email = "[email protected]" },
36-
new MyDataClass { Name = "Jane Smith", Age = 25, Email = "[email protected]" }
37-
};
41+
``` bash
42+
dotnet add package PandaTech.FileExporter
43+
```
3844

39-
// Export data to CSV
40-
var exportedFile = data.ToCsv().ToFile();
45+
------------------------------------------------------------------------
4146

42-
// Return the exported file to the caller
43-
return exportedFile;
44-
```
47+
## ⚙️ Quick Start
4548

46-
Starting from release 3.3.0, FileExporter supports exporting data using fluent rules.
49+
### 1. Configure in `Program.cs`
4750

48-
### Fluent Rules Example
51+
``` csharp
52+
var builder = WebApplication.CreateBuilder(args);
4953

50-
First, create an ExportRule for your model. In the constructor, call GenerateRules() to automatically create default
51-
rules based on the model. To customize the setup, use the RuleFor() method to configure specific rules for your model's
52-
properties. Here's a quick demonstration:
54+
builder.AddFileExporter(); // scans entry assembly for ExportRule<T>
55+
```
5356

54-
### Model Example:
57+
### 2. Export from your endpoint
5558

56-
```csharp
57-
public class FileData
59+
``` csharp
60+
app.MapGet("/export", async () =>
5861
{
59-
public long Id { get; set; }
60-
public string Name { get; set; }
61-
public string Description { get; set; }
62-
public DateTime CreatedAt { get; set; }
63-
public string? Comment { get; set; }
64-
}
62+
var data = new List<MyRow>
63+
{
64+
new() { Id = 1, Name = "Alice" },
65+
new() { Id = 2, Name = "Bob" }
66+
};
67+
68+
var file = await data.ToFileFormatAsync(ExportFormat.Xlsx);
69+
return file.ToFileResult();
70+
});
6571
```
6672

67-
### Export Rule Example:
73+
Done. Zero configuration required.
74+
75+
------------------------------------------------------------------------
6876

69-
This sample includes two constructors, one with a default name and one with a custom name.
77+
## 📄 Defining Custom Rules (Optional)
7078

71-
```csharp
72-
namespace FileExporter.Tests.ExportRuleTests;
79+
``` csharp
80+
using FileExporter.Rules;
7381

74-
public class FileDataExportRule : ExportRule<FileData>
82+
public sealed class MyRowExportRule : ExportRule<MyRow>
7583
{
76-
public FileDataExportRule()
84+
public MyRowExportRule()
7785
{
78-
GenerateRules();
86+
WithName("My Custom Export");
7987

80-
// Custom rules
81-
RuleFor(x => x.Description)
82-
.WriteToColumn("Description")
83-
.WithDefaultValue("Default text here");
88+
RuleFor(x => x.Id)
89+
.HasOrder(0)
90+
.HasFormat(ColumnFormatType.Integer);
8491

85-
RuleFor(x => x.CreatedAt)
86-
.WriteToColumn("Creation date")
87-
.WithDefaultValue("22/08/2024");
88-
}
89-
90-
// OR with custom name
91-
public FileDataExportRule() : base("File Data")
92-
{
93-
GenerateRules();
94-
95-
// Custom rules
96-
RuleFor(x => x.Description)
97-
.WriteToColumn("Description")
98-
.WithDefaultValue("Default text here");
99-
100-
RuleFor(x => x.CreatedAt)
101-
.WriteToColumn("Creation date")
102-
.WithDefaultValue("22/08/2024");
92+
RuleFor(x => x.Name)
93+
.HasOrder(1)
94+
.WriteToColumn("Full Name");
10395
}
10496
}
10597
```
10698

107-
If a property is incorrectly set up, an InvalidPropertyNameException will be thrown with a relevant message.
99+
Just add this class; it will be auto‑discovered.
100+
101+
------------------------------------------------------------------------
102+
103+
## 🔍 Supported Formats
104+
105+
ExportFormat Description
106+
-------------- -------------------------------------------------
107+
**Csv** UTF‑8 CSV, auto‑quote, stable for huge datasets
108+
**Xlsx** Multi‑sheet, streaming, low memory usage
109+
110+
------------------------------------------------------------------------
111+
112+
## 📦 File Naming
113+
114+
Every file receives a timestamp:
115+
116+
Orders 2025-01-01 10:33:00.xlsx
117+
118+
Automatically sanitized for safety.
119+
120+
------------------------------------------------------------------------
121+
122+
## 🔧 Property Rule Options
123+
124+
-----------------------------------------------------------------------
125+
Option Description
126+
--------------------------- -------------------------------------------
127+
`WriteToColumn("Name")` Override header text
128+
129+
`HasOrder(1)` Column ordering
108130

109-
### Controller Example:
131+
`Ignore()` Exclude property
110132

111-
Here is an example of how to integrate FileExporter into a web API controller:
133+
`HasFormat(...)` Text, Integer, Decimal, Currency,
134+
Percentage, Boolean, Date, DateTime
112135

113-
```csharp
114-
namespace FileExporter.Demo.Controllers
136+
`HasPrecision(2)` Decimal digit precision (not rounding, for rounding refer `.Transform()`)
137+
138+
`HasWidth(20)` XLSX column width override
139+
140+
`WithDefaultValue("N/A")` Replaces null values
141+
142+
`Transform(v => ...)` Custom transformation
143+
144+
145+
------------------------------------------------------------------------
146+
147+
## 🧬 Enum Formatting
148+
149+
Rules support:
150+
151+
- `MixedIntAndName` *(default)*`"1 - Active"`
152+
- `Int``"1"`
153+
- `Name``"Active"`
154+
155+
------------------------------------------------------------------------
156+
157+
## 🔥 Performance Notes
158+
159+
- Handles **millions of rows** with **constant memory** usage\
160+
- XLSX splits automatically into multiple sheets\
161+
- ZIP is only applied when final file exceeds threshold\
162+
- Async pipelines (`IAsyncEnumerable<T>`) supported
163+
164+
------------------------------------------------------------------------
165+
166+
## 🪄 Tips
167+
168+
- Keep DTOs simple; exporters use reflection only once\
169+
- Add custom rules **only for overrides** --- conventions already
170+
cover:
171+
- ordering\
172+
- decimal precision\
173+
- date formatting\
174+
- booleans\
175+
- For extremely large exports: prefer `IAsyncEnumerable<T>`
176+
177+
------------------------------------------------------------------------
178+
179+
## 🧭 Demo
180+
181+
``` csharp
182+
app.MapGet("/export/orders", async (ExportFormat format) =>
115183
{
116-
[ApiController]
117-
[Route("api/")]
118-
public class FileDataExportController(ApiDbContext context) : Controller
119-
{
120-
[HttpGet("export-xlsx-via-rules")]
121-
public IActionResult ExportXlsxViaRules()
122-
{
123-
var exportData = context.FileData.ToList();
124-
125-
var rule = new FileDataExportRule();
126-
127-
return rule.ToCsv(exportData).ToFile();
128-
// OR alternative solution with extension method
129-
return rule.ToFileFormat(exportData, ExportType.Xlsx).ToFile();
130-
}
131-
}
132-
}
133-
```
184+
var orders = Enumerable.Range(1, 2000000)
185+
.Select(i => new OrderDto { Id = i, Total = i * 1.25m });
134186

135-
You can also export data to Excel (XLSX) or PDF formats by calling ToXlsx() or ToPdf() respectively.
187+
var file = await orders.ToFileFormatAsync(format);
188+
return file.ToFileResult();
189+
});
190+
```
136191

137-
## Contributing
192+
Exports 2M rows in under a few seconds (depending on disk/CPU).
138193

139-
Contributions are welcome! Please feel free to submit issues, feature requests, or pull requests.
194+
------------------------------------------------------------------------
140195

141-
## License
196+
## 🏁 Conclusion
142197

143-
This project is licensed under the MIT License.
198+
`PandaTech.FileExporter` is built to stay small, clean, and blazing
199+
fast.\
200+
If you need CSV/XLSX export without pain --- you're covered.
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
using System.Reflection;
2+
using FileExporter.Rules;
3+
4+
namespace FileExporter.Dtos;
5+
6+
internal sealed class ExportColumn
7+
{
8+
public required PropertyInfo Property { get; init; }
9+
public required IPropertyRule Rule { get; init; }
10+
}
Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,8 @@
1-
using Microsoft.AspNetCore.Mvc;
2-
31
namespace FileExporter.Dtos;
42

5-
public class ExportFile(string name, MimeTypes mimeType, byte[] data)
3+
public sealed class ExportFile(string name, MimeTypes mimeType, byte[] content)
64
{
7-
public string Name { get; set; } = name + mimeType.Extension;
8-
public MimeTypes Type { get; set; } = mimeType;
9-
public byte[] Data { get; set; } = data;
10-
11-
public FileContentResult ToFile()
12-
{
13-
return new FileContentResult(Data, Type)
14-
{
15-
FileDownloadName = Name
16-
};
17-
}
5+
public string Name { get; } = name;
6+
public MimeTypes MimeType { get; } = mimeType;
7+
public byte[] Content { get; } = content;
188
}

0 commit comments

Comments
 (0)