In jedem zweiten Erstgespräch sitzt nach 20 Minuten dieser Konflikt auf
dem Tisch:
Geschäftsführer: "Wir wollen weg von der Excel-Lawine. Das ist nicht
mehr tragfähig."Buchhalterin: "Wir brauchen Excel. Damit arbeiten wir seit 15 Jahren."
Beide haben Recht. Und beide übersehen das Gleiche.
Die Excel-Hölle entsteht, wenn Excel als Datenbank missbraucht wird —
multi-User, multi-Version, mit Formel-Spaghetti die keiner mehr anfasst
(siehe der Kipppunkt-Post). Daraus
schließen viele: Excel muss weg. Aber das ist die falsche Lehre. Die
richtige ist:
Excel ist nicht das Problem. Excel ist die Schnittstelle.
Eine schlanke, eigene Anwendung — Daten in einer richtigen Datenbank,
Logik in C#, Auswertungen als API — verträgt sich erstaunlich gut mit
einer Buchhaltung die "in Excel arbeitet". Wenn Excel der I/O-Layer
deiner ERP-Light wird (Import, Export, Report-Format, Bulk-Edit), bleiben
beide Seiten in ihrem Komfort: die Anwendung hält die Wahrheit, Excel
ist die Brücke zur menschlichen Nutzung.
Das Werkzeug für diese Brücke heißt im .NET-Universum meistens
EPPlus.
Was EPPlus ist (und was nicht)
EPPlus ist eine Bibliothek zum Lesen und Schreiben von .xlsx-Dateien
direkt aus C#. Sie arbeitet auf dem OOXML-Format (Office Open XML, der
ZIP-Container den Excel seit 2007 verwendet) und gibt dir eine
Objekt-API auf die Sheets, Zellen, Formeln, Charts, Pivot-Tables,
bedingten Formatierungen und Daten-Validierungen. Du sprichst nicht mit
einem laufenden Excel-Prozess (was im Server-Kontext sowieso eine
schlechte Idee wäre) — du baust die Datei programmatisch.
Eine 8-Zeilen-Tour, weil's wichtiger ist als jede Architektur-Tirade:
using OfficeOpenXml;
// Seit EPPlus 5 Pflicht: License-Context vor erstem Zugriff setzen
ExcelPackage.LicenseContext = LicenseContext.NonCommercial;
using var package = new ExcelPackage(new FileInfo("kunden.xlsx"));
var ws = package.Workbook.Worksheets[0];
var kunden = new List<Kunde>();
for (int row = 2; row <= ws.Dimension.End.Row; row++)
{
kunden.Add(new Kunde {
Name = ws.Cells[row, 1].Text,
Email = ws.Cells[row, 2].Text,
Umsatz = ws.Cells[row, 3].GetValue<decimal>()
});
}
Das ist nicht hübsch, aber es ist ehrlich. Du siehst was passiert,
du siehst woher die Daten kommen, du kannst debuggen. Wenn die
Buchhaltung sich beschwert dass Spalte C plötzlich leer ist, kannst du
in 30 Sekunden nachvollziehen warum.
Schreiben sieht spiegelbildlich aus:
using var package = new ExcelPackage();
var ws = package.Workbook.Worksheets.Add("Umsatz Juni 2026");
ws.Cells["A1"].LoadFromCollection(monatszahlen, PrintHeaders: true);
ws.Cells["A1:D1"].Style.Font.Bold = true;
ws.Cells["D2:D" + (monatszahlen.Count + 1)]
.Style.Numberformat.Format = "#,##0.00 €";
ws.Cells[ws.Dimension.Address].AutoFitColumns();
await package.SaveAsAsync(outputStream);
Vier Zeilen Formatierung — fettes Header, EUR-Format auf der Umsatz-
Spalte, automatische Spaltenbreite. Das Ergebnis sieht nach
"die Buchhaltung hat das selbst gebaut" aus, nicht nach "ein
Programmierer hat hier was aus einer Anwendung exportiert". Genau das
ist der Punkt.
4 Use-Cases die in jedem KMU-ERP-Light auftauchen
1) Stammdaten-Import beim Einrichten
Der Kunde fängt mit deiner neuen Anwendung an und hat — natürlich — 2400
Kundendatensätze in einer Excel-Datei aus der bisherigen Welt. Statt
einer Migrations-Vereinbarung mit Stunden-Aufwand für deine Seite gibt's
einen Upload-Endpoint:
[HttpPost("/api/import/kunden")]
public async Task<IActionResult> Importiere(IFormFile datei, CancellationToken ct)
{
using var stream = datei.OpenReadStream();
using var package = new ExcelPackage(stream);
var ws = package.Workbook.Worksheets[0];
var importiert = 0;
var fehler = new List<string>();
for (int row = 2; row <= ws.Dimension.End.Row; row++)
{
try
{
var kunde = new Kunde {
Name = ws.Cells[row, 1].Text.Trim(),
Email = ws.Cells[row, 2].Text.Trim(),
Umsatz = ws.Cells[row, 3].GetValue<decimal>()
};
await _kunden.AddAsync(kunde, ct);
importiert++;
}
catch (Exception ex)
{
fehler.Add($"Zeile {row}: {ex.Message}");
}
}
await _kunden.SaveChangesAsync(ct);
return Ok(new { importiert, fehler });
}
Der Kunde lädt seine Excel-Datei hoch, sieht "2387 importiert,
13 Fehler in Zeilen X, Y, Z", korrigiert die 13 Zeilen direkt in seiner
Datei, lädt nochmal hoch — fertig. Das ist UX die kein Custom-Web-Formular
schlägt.
2) Monats-Report-Export
Der Geschäftsführer will am Monatsende eine Tabelle. Nicht einen
"Dashboard-Link", nicht eine "Power BI-Ansicht". Eine Tabelle, die er
in den Anhang seiner Quartals-Vorstandssitzungs-Mail packen kann.
public async Task<byte[]> ErzeugeMonatsreport(int jahr, int monat)
{
var daten = await _reports.LadeMonatsumsatz(jahr, monat);
using var package = new ExcelPackage();
var ws = package.Workbook.Worksheets.Add($"{jahr:0000}-{monat:00}");
ws.Cells["A1"].LoadFromCollection(daten, PrintHeaders: true);
// Header-Styling
var header = ws.Cells["A1:E1"];
header.Style.Font.Bold = true;
header.Style.Fill.PatternType = ExcelFillStyle.Solid;
header.Style.Fill.BackgroundColor.SetColor(System.Drawing.Color.LightGray);
// Zahlen-Format auf der Umsatz-Spalte
ws.Cells[$"E2:E{daten.Count + 1}"]
.Style.Numberformat.Format = "#,##0.00 €";
// Summen-Zeile
var summe = daten.Count + 2;
ws.Cells[$"D{summe}"].Value = "Summe";
ws.Cells[$"D{summe}"].Style.Font.Bold = true;
ws.Cells[$"E{summe}"].Formula = $"SUM(E2:E{daten.Count + 1})";
ws.Cells[$"E{summe}"].Style.Font.Bold = true;
ws.Cells[ws.Dimension.Address].AutoFitColumns();
return await package.GetAsByteArrayAsync();
}
Das SUM-Formel-Ding ist nicht Kosmetik: die Excel-Datei rechnet am
Empfänger-Rechner weiter. Wenn der Geschäftsführer eine Zeile löscht
(weil sie zur Tochtergesellschaft gehört und nicht in den Vorstands-
Bericht soll), bleibt die Summe konsistent. Mit einem statischen
PDF-Export geht das nicht.
3) Bulk-Edit über Export-Edit-Import
Der schwierigste Use-Case zum Verkaufen, weil er aussieht wie ein Hack —
aber er funktioniert besser als jedes Web-Formular wenn jemand
200 Datensätze gleichzeitig ändern muss.
Workflow: User klickt in deiner Anwendung "Selektierte exportieren" →
bekommt eine .xlsx-Datei mit allen 200 Zeilen + einer technischen
ID-Spalte. Bearbeitet in Excel (Suche-Ersetzen, Spalten-Operationen,
Filter, Sort — alles was Excel kann und kein Web-Tool je gut macht).
Lädt das Ergebnis wieder hoch. Anwendung erkennt die IDs, updated die
Datensätze, zeigt einen Diff-Report "100 unverändert, 87 geändert,
3 mit Konflikten — bitte prüfen".
Das ist ehrliche UX. Die Buchhalterin liebt es. Du sparst dir das
Bauen von einer Inline-Edit-Tabelle, Excel-Style-Filtern, Bulk-Operation-
Buttons. Excel macht das schon.
4) Template-basierte Dokumente
Auftragsbestätigung, Lieferschein, Stundenabrechnung — alles
Dokumente die in 95% der Fälle den gleichen Look haben sollen wie das
Word-Template das die Firma seit 2014 nutzt.
EPPlus kann eine vorhandene Excel-Datei öffnen und Zellen befüllen.
Statt das Layout im Code zu konstruieren, legst du
Templates/Auftragsbestaetigung.xlsx in dein Projekt — mit Logo, Adresse,
Layout, allem — und sagst dem Code nur:
using var package = new ExcelPackage(new FileInfo("Templates/Auftragsbestaetigung.xlsx"));
var ws = package.Workbook.Worksheets["Vorlage"];
ws.Cells["B5"].Value = auftrag.Kunde.Name;
ws.Cells["B6"].Value = auftrag.Kunde.Adresse;
ws.Cells["E5"].Value = auftrag.Datum;
ws.Cells["E6"].Value = auftrag.Auftragsnummer;
for (int i = 0; i < auftrag.Positionen.Count; i++)
{
var row = 12 + i;
ws.Cells[row, 1].Value = auftrag.Positionen[i].Bezeichnung;
ws.Cells[row, 2].Value = auftrag.Positionen[i].Menge;
ws.Cells[row, 3].Value = auftrag.Positionen[i].Einzelpreis;
}
package.SaveAs(outputStream);
Der Designer im Haus kann das Template anpassen ohne Code-Änderung. Du
hast keine Custom-PDF-Engine im Hintergrund, keine LaTeX-Geschichte,
keinen WeasyPrint-Container. Excel macht den Druck — und Excel kann
auch nach PDF exportieren wenn es sein muss.
Die ehrliche Lizenz-Geschichte
Hier muss ich gerade sein:
| EPPlus-Version | Lizenz | Status |
|---|---|---|
| EPPlus 4.x | LGPL | Frei nutzbar (auch kommerziell), aber ohne Wartung seit 2020. API ist solide aber älter. |
| EPPlus 5–7 | Polyform Noncommercial 1.0.0 | Kommerziell kostenpflichtig — non-commercial gratis, in der Anwendung deines Mandanten brauchst du eine Lizenz. |
Preis-Realität (Stand 2026): EPPlus 7 Commercial liegt zwischen ~300
und 500 EUR pro Entwickler und Jahr. Im KMU-Projekt für eine
Anwendung mit ein, zwei Entwicklern ist das verkraftbar — aber kein
Selbstläufer den du nebenher zahlst.
Bevor du das einplanst, prüf' kurz ob du wirklich EPPlus brauchst.
Alternativen, wenn EPPlus zu schwer ist
| Bibliothek | Lizenz | Stärke | Schwäche |
|---|---|---|---|
| ClosedXML | MIT | Frei in allen Szenarien, lebendige Community, sauberer API-Stil | Pivot-Tables nur rudimentär, weniger Chart-Optionen |
| NPOI | Apache 2.0 | Frei, kann auch alte .xls |
API stammt aus Java-Welt, fühlt sich in C# fremd an |
| OpenXML SDK | MIT (Microsoft) | Maximale Kontrolle, offizielle Library | Sehr low-level — du arbeitest mit XML-Strukturen, nicht mit Excel-Konzepten |
Mein pragmatischer Filter für KMU-ERP-Light-Projekte:
- 80% der Fälle: ClosedXML reicht. Import, Export, Formatierung,
Formeln, einfache Charts. MIT-Lizenz, keine Sorgen, gleiche
Aufgabenklasse wie EPPlus. - Wenn du Pivot-Tables programmatisch brauchst, oder
Conditional-Formatting-Komplexität, oder die volle Chart-API:
EPPlus kaufen. Die 300 EUR/Jahr sind in einer Anwendung mit 100k+
Projektvolumen Hintergrundrauschen. - Wenn du genau eine kleine Sache machen musst und der Performance-
Footprint zählt: OpenXML SDK direkt. Ist Arbeit, aber die
schlankste Lösung.
Was das für dein nächstes ERP-Projekt heißt
Drei konkrete Architektur-Punkte:
Excel ist Eingang und Ausgang, nicht Persistenz. Daten leben in
einer Postgres- oder SQL-Server-Tabelle mit Schema, Constraints und
Migrations. Excel ist das Format, in dem Daten zu dir und von
dir reisen. Niemals der Speicherort.Bau Import-Endpoints früh. Pro Stammdaten-Typ einen
Upload-Endpoint, der mit dem Excel-Format zurechtkommt das die
Buchhaltung sowieso schon hat. Das ist die schnellste Onboarding-
Mechanik die es gibt — die User müssen ihre Daten nicht in deinem
System nachbauen.Erzwinge nicht Web-UI wo Excel besser ist. Bulk-Edits,
Spreadsheet-Style-Filter, Massen-Operations: Excel ist seit 35 Jahren
im Tuning. Du kannst da im Browser nicht mithalten, und du musst
es auch nicht.
Wenn das gut umgesetzt ist, hat der Geschäftsführer seine ERP-Light, die
Buchhalterin hat ihr Excel, und du hast eine Anwendung die nach 5 Jahren
noch wartbar ist.
Wenn ihr gerade an genau dieser Stelle steht und nicht sicher seid wie
ihr's aufsetzen sollt — 30 Minuten reichen meistens um zu klären welcher
der vier Use-Cases bei euch trägt und was die richtige Library-Wahl ist.
— Bernhard