Neue Seite
Hauptmerkmale
- ✅ Automatisierte Datenübernahme: Cron-basierte Planung für wiederkehrende Importprozesse
- ✅ Flexible Dateibeobachtung: Überwacht konfigurierbare Ordner mit Wildcard-Mustern
- ✅ Intelligente Datenverarbeitung: Unterstützt Zeilenfilterung, Spaltenfüllung und bedingte Löschung
- ✅ Dynamische Tabellenerstellung: Erstellt Datenbank-Tabellen und -Spalten automatisch
- ✅ Multi-Format-Unterstützung: Verarbeitet Excel-Dateien in den Formaten .xlsx und .xls
- ✅ Umfassendes Logging: Serilog-basierte Protokollierung mit konfigurierbaren Ausgabezielen
- ✅ Subfolder-Unterstützung: Rekursive Verzeichnissuche bei Bedarf
- ✅ Bulk-Import: Hochperformante Datenübernahme mittels SqlBulkCopy
- ✅ Flexible Deployment-Optionen: Windows-Service, Standalone-Anwendung oder Docker-Container
🏗️ Architektur
Komponenten-Übersicht
ExcelDataImporter
├── Program.cs # Einstiegspunkt und Service-Konfiguration
├── ImportJobWorker.cs # Job-Verwaltung und -Ausführung
├── TimedHostedService.cs # Basis-Klasse für zeitgesteuerte Services
├── ImportSettings.cs # Konfigurationsmodell für Import-Jobs
├── MissingSettingException.cs # Exception für fehlende Konfigurationen
└── Daten/
├── Importer.cs # SQL-Datenbank-Import-Logik
└── ExcelImporter.cs # Excel-Datei-Verarbeitung
Architektur-Diagramm
┌─────────────────────────────────────────────────────────────┐
│ ExcelDataImporter │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────┐ ┌─────────────────┐ │
│ │ Program.cs │───▶│ Configuration │ │
│ └──────────────┘ └─────────────────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌───────────────────────────────────┐ │
│ │ ImportJobWorker (n Jobs) │ │
│ │ extends TimedHostedService │ │
│ └───────────────────────────────────┘ │
│ │ │
│ ├────────────┬─────────────────┐ │
│ ▼ ▼ ▼ │
│ ┌────────────┐ ┌──────────────┐ ┌──────────┐ │
│ │ Cron │ │ExcelImporter │ │ Importer │ │
│ │ Scheduler │ │ (DevExpress)│ │ (SqlBulk)│ │
│ └────────────┘ └──────────────┘ └──────────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌──────────────┐ ┌───────────┐ │
│ │ Excel-Dateien│ │ SQL Server│ │
│ └──────────────┘ └───────────┘ │
└─────────────────────────────────────────────────────────────┘
Technologie-Stack
| Komponente | Technologie | Version | Zweck |
|---|---|---|---|
| Runtime | .NET | 10.0 | Basis-Framework |
| Service-Host | Microsoft.Extensions.Hosting | 10.0.0 | Background-Worker-Hosting |
| Windows-Service | Microsoft.Extensions.Hosting.WindowsServices | 10.0.0 | Windows-Service-Integration |
| Logging | Serilog | 4.3.0 | Strukturiertes Logging |
| Excel-Verarbeitung | DevExpress.Document.Processor | 25.1.7 | Excel-Datei-Parsing |
| Datenbank | Microsoft.Data.SqlClient | 6.1.3 | SQL Server-Verbindung |
| Scheduling | NCrontab | 3.4.0 | Cron-basierte Zeitplanung |
| ORM | DevExpress.Xpo | 25.1.7 | Object-Relational Mapping |
💻 Systemvoraussetzungen
Mindestanforderungen
- Betriebssystem: Windows Server 2016+ / Windows 10+ oder Linux mit .NET 10.0 Runtime
- .NET Runtime: .NET 10.0 oder höher
- Datenbank: Microsoft SQL Server 2016+ (Express, Standard, Enterprise)
- Speicher: Mindestens 512 MB RAM (abhängig von der Dateigröße)
- Festplatte: 100 MB für die Anwendung + Speicherplatz für Logs und temporäre Dateien
Empfohlene Anforderungen
- Betriebssystem: Windows Server 2022 oder neuere Linux-Distribution
- .NET Runtime: .NET 10.0
- Datenbank: Microsoft SQL Server 2019+ mit ausreichender Speicherkapazität
- Speicher: 2 GB RAM oder mehr
- Festplatte: SSD mit mindestens 1 GB freiem Speicherplatz
Netzwerk
- Zugriff auf den SQL Server (Standard-Port 1433 oder konfigurierter Port)
- Zugriff auf die zu überwachenden Ordner (lokal oder Netzwerkfreigabe)
- Schreibrechte für Log-Verzeichnis
📦 Installation
Option 1: Windows-Service-Installation
Schritt 1: Anwendung vorbereiten
# Repository klonen
git clone https://github.com/CSS-EDV-Support/ExcelDataImporter.git
cd ExcelDataImporter
# Projekt kompilieren
dotnet publish ExcelDataImporter/ExcelDataImporter.csproj -c Release -o C:\Services\ExcelDataImporter
Schritt 2: appsettings.json konfigurieren
Schritt 3:2: Windows-Service erstellen
# PowerShell als Administrator ausführen
sc.exe create ExcelDataImporter binPath="C:\Services\ExcelDataImporter\ExcelDataImporter.exe" start=auto
sc.exe description ExcelDataImporter "Automatisierter Excel-Datenimport-Service"
sc.exe start ExcelDataImporter
Schritt 4:3: Service überprüfen
# Service-Status prüfen
sc.exe query ExcelDataImporter
# Logs überprüfen
Get-Content C:\Services\ExcelDataImporter\Logs\log.txt -Tail 50 -Wait
Option 2: Standalone-Anwendung
# Anwendung starten
cd C:\Path\To\ExcelDataImporter
dotnet ExcelDataImporter.dll
Option 3: Docker-Container
Schritt 1: Docker-Image erstellen
# Im Repository-Verzeichnis
docker build -t exceldataimporter:latest -f ExcelDataImporter/Dockerfile .
Schritt 2: Container starten
# Mit Volume-Mapping für Konfiguration, Logs und Datenordner
docker run -d \
--name exceldataimporter \
-v /path/to/config:/app/config \
-v /path/to/logs:/app/Logs \
-v /path/to/data:/data \
exceldataimporter:latest
Schritt 3: Container-Logs überwachen
docker logs -f exceldataimporter
Deinstallation
Windows-Service entfernen
# Service stoppen und entfernen
sc.exe stop ExcelDataImporter
sc.exe delete ExcelDataImporter
# Optional: Dateien löschen
Remove-Item -Recurse -Force C:\Services\ExcelDataImporter
⚙️ Konfiguration
appsettings.json - Struktur
Die Konfiguration erfolgt vollständig über die appsettings.json-Datei:
{
"Serilog": {
"Using": [
"Serilog.Sinks.Console",
"Serilog.Sinks.File"
],
"MinimumLevel": "Debug",
"WriteTo": [
{
"Name": "Console",
"Args": {
"theme": "Serilog.Sinks.SystemConsole.Themes.AnsiConsoleTheme::Code, Serilog.Sinks.Console"
}
},
{
"Name": "File",
"Args": {
"path": "Logs/log.txt",
"rollingInterval": "Day",
"retainedFileCountLimit": 7
}
}
],
"Properties": {
"Application": "ExcelDataImporter"
}
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.Hosting.Lifetime": "Information"
},
"EventLog": {
"SourceName": "ExcelImportService",
"LogName": "Application",
"LogLevel": {
"Microsoft": "Information",
"Microsoft.Hosting.Lifetime": "Information"
}
}
},
"ImportJobs": [
{
"JobName": "DailyProductImport",
"CronExpression": "0 2 * * *",
"Pfad": "C:\\Import\\Products",
"ExcelFilePattern": "Products_*.xlsx",
"DestinationTable": "ProductData",
"CreateDateOfImportColumn": true,
"NameOfImportDateColumn": "ImportDate",
"TruncateDestinationTable": true,
"ExcelFormat": "xlsx",
"RemoveRows": 1,
"FillEmptyColumns": [0, 2],
"RemoveRowIfColumnIsEmpty": 0,
"IncludeSubfolders": true,
"ConnectionString": "Server=localhost;Database=ImportDB;User Id=sa;Password=YourPassword;TrustServerCertificate=True;"
}
],
"connectionStrings": {
"ConnectionString": "Server=localhost;Database=ImportDB;User Id=sa;Password=YourPassword;TrustServerCertificate=True;"
}
}
Import-Job-Konfiguration
Pflichtfelder
| Parameter | Typ | Beschreibung | Beispiel |
|---|---|---|---|
JobName |
string | Eindeutiger Name des Import-Jobs | "DailyProductImport" |
Pfad |
string | Quellverzeichnis für Excel-Dateien | "C:\\Import\\Products" |
ExcelFilePattern |
string | Suchmuster für Dateien (Wildcards erlaubt) | "Products_*.xlsx" |
DestinationTable |
string | Ziel-Tabelle in der Datenbank | "ProductData" |
Optionale Felder
| Parameter | Typ | Standard | Beschreibung |
|---|---|---|---|
CronExpression |
string | "* * * * *" |
Cron-Ausdruck für Zeitplanung (jede Minute) |
CreateDateOfImportColumn |
bool | false |
Erstellt eine Spalte für das Importdatum |
NameOfImportDateColumn |
string | null |
Name der Import-Datumsspalte |
TruncateDestinationTable |
bool | false |
Leert die Zieltabelle vor dem Import |
ExcelFormat |
string | "xlsx" |
Excel-Format: "xlsx" oder "xls" |
RemoveRows |
int? | null |
Anzahl der zu entfernenden Zeilen am Anfang |
FillEmptyColumns |
int[]? | null |
Spaltenindizes für Forward-Fill (0-basiert) |
RemoveRowIfColumnIsEmpty |
int? | null |
Entfernt Zeilen, wenn angegebene Spalte leer ist |
IncludeSubfolders |
bool | false |
Durchsucht Unterverzeichnisse |
ConnectionString |
string? | null |
Job-spezifischer Connection String (überschreibt global) |
Cron-Ausdrücke
Cron-Ausdrücke steuern die Ausführungszeit der Import-Jobs. Format: Minute Stunde Tag Monat Wochentag
Beispiele
| Cron-Ausdruck | Beschreibung |
|---|---|
* * * * * |
Jede Minute |
0 * * * * |
Jede Stunde |
0 2 * * * |
Täglich um 2:00 Uhr |
0 2 * * 1-5 |
Werktags um 2:00 Uhr |
0 */4 * * * |
Alle 4 Stunden |
0 0 1 * * |
Am ersten Tag des Monats um Mitternacht |
30 6 * * 1 |
Jeden Montag um 6:30 Uhr |
Hinweis: Nutzen Sie Online-Tools wie crontab.guru zur Validierung.
Logging-Konfiguration
Log-Level
| Level | Verwendung |
|---|---|
Trace |
Sehr detaillierte Informationen (Entwicklung) |
Debug |
Detaillierte Ablauf-Informationen |
Information |
Allgemeine Informationen über Systemverhalten |
Warning |
Warnungen bei potenziellen Problemen |
Error |
Fehler, die das System weiterhin betreiben lassen |
Fatal |
Kritische Fehler, die das System zum Absturz bringen |
Log-Ausgabeziele
Die Standardkonfiguration schreibt Logs in:
- Konsole: Für interaktive Anwendungsausführung
- Datei:
Logs/log.txtmit täglichem Rollover und 7-Tage-Aufbewahrung
Weitere Serilog-Sinks können hinzugefügt werden (z. B. EventLog, SQL Server, Elasticsearch).
Connection Strings
Globaler Connection String
"connectionStrings": {
"ConnectionString": "Server=localhost;Database=ImportDB;User Id=sa;Password=YourPassword;TrustServerCertificate=True;"
}
Job-spezifischer Connection String
Überschreibt den globalen Connection String für einen bestimmten Job:
{
"JobName": "SpecialImport",
"ConnectionString": "Server=server2;Database=SpecialDB;Integrated Security=True;",
...
}
Konfigurationsbeispiele
Beispiel 1: Einfacher täglicher Import
{
"JobName": "DailySalesImport",
"CronExpression": "0 6 * * *",
"Pfad": "\\\\fileserver\\Import\\Sales",
"ExcelFilePattern": "Sales_*.xlsx",
"DestinationTable": "SalesData",
"TruncateDestinationTable": true,
"CreateDateOfImportColumn": true,
"NameOfImportDateColumn": "ImportTimestamp"
}
Beispiel 2: Stündlicher Import mit Datenbereinigung
{
"JobName": "HourlyInventoryUpdate",
"CronExpression": "0 * * * *",
"Pfad": "C:\\Data\\Inventory",
"ExcelFilePattern": "inventory_*.xlsx",
"DestinationTable": "Inventory",
"TruncateDestinationTable": false,
"RemoveRows": 2,
"FillEmptyColumns": [0, 1, 3],
"RemoveRowIfColumnIsEmpty": 0,
"IncludeSubfolders": true
}
Beispiel 3: Multi-Job-Setup
{
"ImportJobs": [
{
"JobName": "MorningProductSync",
"CronExpression": "0 6 * * *",
"Pfad": "C:\\Import\\Products",
"ExcelFilePattern": "*.xlsx",
"DestinationTable": "Products",
"TruncateDestinationTable": true
},
{
"JobName": "EveningCustomerSync",
"CronExpression": "0 18 * * *",
"Pfad": "C:\\Import\\Customers",
"ExcelFilePattern": "*.xlsx",
"DestinationTable": "Customers",
"TruncateDestinationTable": true
},
{
"JobName": "HourlyOrderCheck",
"CronExpression": "0 * * * *",
"Pfad": "C:\\Import\\Orders",
"ExcelFilePattern": "orders_*.xlsx",
"DestinationTable": "Orders",
"TruncateDestinationTable": false,
"CreateDateOfImportColumn": true,
"NameOfImportDateColumn": "OrderImportDate"
}
]
}
🚀 Verwendung
Grundlegender Workflow
- Konfiguration erstellen: appsettings.json mit Import-Jobs konfigurieren
- Service starten: Windows-Service, Standalone oder Docker
- Dateien bereitstellen: Excel-Dateien in die konfigurierten Verzeichnisse legen
- Automatische Verarbeitung: Jobs werden gemäß Cron-Zeitplan ausgeführt
- Monitoring: Logs überprüfen und Datenbank-Einträge validieren
Excel-Datei-Anforderungen
Unterstützte Formate
.xlsx(Office Open XML).xls(Excel 97-2003)
Dateistruktur
- Erste Zeile: Standardmäßig als Spaltennamen verwendet
- Datenzeilen: Ab der zweiten Zeile (anpassbar mit
RemoveRows) - Mehrere Arbeitsblätter: Nur das erste Arbeitsblatt wird verarbeitet
Beispiel-Excel-Struktur
| ProductID | ProductName | Category | Price | Stock |
|---|---|---|---|---|
| 1001 | Laptop | Electronics | 999.99 | 50 |
| 1002 | Mouse | Accessories | 19.99 | 200 |
| 1003 | Keyboard | Accessories | 49.99 | 150 |
Datenbank-Interaktion
Automatische Tabellenerstellung
Wenn die Zieltabelle nicht existiert, wird sie automatisch erstellt:
// Die Tabelle wird basierend auf der Excel-Struktur generiert
// Spaltentypen werden automatisch erkannt:
// - Int32 → INT
// - String → NVARCHAR(MAX)
// - DateTime → DATETIME
// - Float → FLOAT
Bulk-Insert
Daten werden mit SqlBulkCopy hochperformant importiert:
// Beispiel für einen Import von 10.000 Zeilen:
// - Durchschnittliche Dauer: < 5 Sekunden
// - Speicherverbrauch: Minimal durch Streaming
Erweiterte Features
1. Spaltenfüllung (FillEmptyColumns)
Füllt leere Zellen mit dem letzten nicht-leeren Wert in der Spalte:
Vor der Füllung:
| Region | Product | Sales |
|---|---|---|
| North | Product A | 100 |
| Product B | 150 | |
| Product C | 200 | |
| South | Product D | 120 |
Nach der Füllung (FillEmptyColumns: [0]):
| Region | Product | Sales |
|---|---|---|
| North | Product A | 100 |
| North | Product B | 150 |
| North | Product C | 200 |
| South | Product D | 120 |
2. Bedingte Zeilenentfernung (RemoveRowIfColumnIsEmpty)
Entfernt Zeilen, bei denen eine bestimmte Spalte leer ist:
Vor der Filterung:
| ID | Name | |
|---|---|---|
| 1 | John | [email protected] |
| 2 | ||
| 3 | Jane | [email protected] |
Nach der Filterung (RemoveRowIfColumnIsEmpty: 1):
| ID | Name | |
|---|---|---|
| 1 | John | [email protected] |
| 3 | Jane | [email protected] |
3. Zeilen entfernen (RemoveRows)
Entfernt die ersten n Zeilen (z. B. Überschriften oder Zusammenfassungen):
{
"RemoveRows": 2 // Entfernt die ersten 2 Zeilen
}
4. Subfolder-Suche (IncludeSubfolders)
Durchsucht rekursiv alle Unterverzeichnisse:
Import/
├── 2024/
│ ├── January/
│ │ └── products_jan.xlsx ✓ Wird gefunden
│ └── February/
│ └── products_feb.xlsx ✓ Wird gefunden
└── Archive/
└── products_old.xlsx ✓ Wird gefunden
Bei IncludeSubfolders: false würden nur Dateien direkt in Import/ gefunden werden.
5. Importdatum-Spalte
Fügt automatisch eine Spalte mit dem Import-Zeitstempel hinzu:
-- Generierte Tabelle mit Importdatum
CREATE TABLE ProductData (
ProductID INT,
ProductName NVARCHAR(MAX),
Price FLOAT,
ImportDate DATETIME DEFAULT(GETDATE())
);
🔄 Import-Prozess
Detaillierter Ablauf
1. Job-Start (Cron-Trigger)
│
├─▶ 2. Verzeichnis-Scan
│ ├─ Pfad validieren
│ ├─ Dateimuster anwenden
│ └─ Neueste Datei pro Verzeichnis ermitteln
│
├─▶ 3. Excel-Datei-Verarbeitung
│ ├─ Temporäre Kopie erstellen
│ ├─ Datei laden (DevExpress)
│ ├─ Erstes Arbeitsblatt auswählen
│ ├─ Optionale Zeilen entfernen (RemoveRows)
│ ├─ Spaltenfüllung anwenden (FillEmptyColumns)
│ ├─ Zeilenfilterung (RemoveRowIfColumnIsEmpty)
│ └─ DataTable generieren
│
├─▶ 4. Datenbank-Vorbereitung
│ ├─ Connection-String abrufen
│ ├─ Verbindung öffnen
│ ├─ Tabelle erstellen (falls nicht vorhanden)
│ ├─ Importdatum-Spalte hinzufügen (optional)
│ └─ Tabelle leeren (optional, TruncateDestinationTable)
│
├─▶ 5. Daten-Import
│ ├─ SqlBulkCopy konfigurieren
│ ├─ Spaltenmapping (automatisch)
│ └─ Bulk-Insert ausführen
│
└─▶ 6. Abschluss
├─ Anzahl importierter Datensätze loggen
├─ Temporäre Dateien löschen
├─ Verbindung schließen
└─ Nächste Ausführung planen
Fehlerbehandlung
Der Service implementiert umfassende Fehlerbehandlung auf allen Ebenen:
- Konfigurationsfehler:
MissingSettingExceptionbei fehlenden Pflichtfeldern - Dateisystemfehler:
DirectoryNotFoundException,FileNotFoundException - Excel-Verarbeitungsfehler: Detailliertes Logging mit Dateinamen
- Datenbankfehler: SQL-Exceptions werden geloggt, Service läuft weiter
- Cron-Fehler: Ungültige Ausdrücke werden beim Start erkannt
Performance-Überlegungen
| Szenario | Dateigröße | Zeilen | Durchschnittliche Dauer |
|---|---|---|---|
| Klein | < 1 MB | < 1.000 | < 1 Sekunde |
| Mittel | 1-10 MB | 1.000-10.000 | 1-5 Sekunden |
| Groß | 10-50 MB | 10.000-50.000 | 5-30 Sekunden |
| Sehr groß | > 50 MB | > 50.000 | > 30 Sekunden |
Optimierungen:
- Bulk-Insert statt einzelner Inserts
- Temporäre Dateikopie zur Vermeidung von Locking
- Streaming-basierte Verarbeitung
- Minimaler Memory-Footprint
🔧 Troubleshooting
Häufige Probleme und Lösungen
Problem 1: Service startet nicht
Symptom:
Der Dienst "ExcelDataImporter" auf dem lokalen Computer wurde gestartet und dann beendet.
Mögliche Ursachen:
- Ungültige appsettings.json
- Fehlende .NET 10.0 Runtime
- Ungültige Cron-Ausdrücke
Lösung:
# Logs überprüfen
Get-Content C:\Services\ExcelDataImporter\Logs\log.txt -Tail 100
# Manuelle Ausführung zum Debuggen
cd C:\Services\ExcelDataImporter
.\ExcelDataImporter.exe
# .NET Runtime überprüfen
dotnet --list-runtimes
Problem 2: Keine Dateien gefunden
Symptom:
Keine Dateien mit dem Suchmuster *.xlsx in Pfad C:\Import gefunden.
Mögliche Ursachen:
- Falscher Pfad
- Falsches Dateimuster
- Fehlende Dateiberechtigungen
Lösung:
# Pfad und Dateien überprüfen
Get-ChildItem "C:\Import" -Filter "*.xlsx"
# Berechtigungen prüfen
icacls "C:\Import"
# Service-Account benötigt Leserechte auf den Ordner
# Für Windows-Service: Meist "NT AUTHORITY\LOCAL SERVICE"
Problem 3: Datenbankverbindung schlägt fehl
Symptom:
Fehler beim Importieren aus Pfad C:\Import
Exception: A network-related or instance-specific error occurred...
Mögliche Ursachen:
- SQL Server nicht erreichbar
- Falscher Connection String
- Firewall blockiert Port 1433
Lösung:
# SQL Server-Verbindung testen
Test-NetConnection -ComputerName localhost -Port 1433
# Connection String validieren
# Testen mit sqlcmd oder SQL Server Management Studio
Connection String debuggen:
// Beispiel mit detaillierten Optionen
{
"ConnectionString": "Server=localhost,1433;Database=ImportDB;User Id=sa;Password=YourPassword;TrustServerCertificate=True;Connect Timeout=30;Encrypt=False;"
}
Problem 4: Excel-Datei kann nicht geöffnet werden
Symptom:
Fehler beim Importieren der Datei C:\Import\data.xlsx
Exception: File is corrupted or locked
Mögliche Ursachen:
- Datei wird noch von Excel geöffnet
- Datei ist beschädigt
- Unzureichende Berechtigungen
Lösung:
# Prozesse prüfen, die die Datei sperren
$filePath = "C:\Import\data.xlsx"
$processes = Get-Process | Where-Object {$_.Modules.FileName -eq $filePath}
$processes | Stop-Process -Force
# Temporäres Verzeichnis überprüfen
$tempPath = [System.IO.Path]::GetTempPath()
Get-ChildItem $tempPath -Filter "*.xlsx" | Remove-Item -Force
Problem 5: Daten werden nicht importiert
Symptom:
- Service läuft ohne Fehler
- Keine Daten in der Zieltabelle
Mögliche Ursachen:
- Cron-Ausdruck noch nicht ausgelöst
- Falsches Datei-Muster
- Alle Zeilen durch Filter entfernt
Lösung:
-- Tabelle überprüfen
SELECT COUNT(*) FROM DestinationTable;
SELECT TOP 10 * FROM DestinationTable ORDER BY ImportDate DESC;
-- Tabelle leeren und neu testen
TRUNCATE TABLE DestinationTable;
Cron-Ausdruck testen:
// Für Tests: Jede Minute ausführen
{
"CronExpression": "* * * * *"
}
// Nach erfolgreichem Test: Produktiv-Zeitplan setzen
{
"CronExpression": "0 6 * * *"
}
Problem 6: Speicherverbrauch zu hoch
Symptom:
- Service verbraucht > 2 GB RAM
- System wird langsam
Mögliche Ursachen:
- Sehr große Excel-Dateien
- Mehrere parallele Jobs
- Memory Leak
Lösung:
// Jobs zeitlich staffeln
{
"ImportJobs": [
{"JobName": "Job1", "CronExpression": "0 1 * * *"},
{"JobName": "Job2", "CronExpression": "0 2 * * *"},
{"JobName": "Job3", "CronExpression": "0 3 * * *"}
]
}
# Service neu starten (setzt Speicher zurück)
Restart-Service ExcelDataImporter
# Prozess-Speicher überwachen
Get-Process ExcelDataImporter | Select-Object Name, @{Name="Memory (MB)";Expression={[Math]::Round($_.WorkingSet / 1MB, 2)}}
Logging-Analyse
Debug-Modus aktivieren
{
"Serilog": {
"MinimumLevel": "Debug"
}
}
Wichtige Log-Meldungen
| Log-Meldung | Bedeutung | Aktion |
|---|---|---|
Started ExcelImportService |
Service erfolgreich gestartet | ✓ Normal |
Adding Job {JobName} |
Job wurde registriert | ✓ Normal |
{Job} starting with CRON schedule |
Job-Scheduler initialisiert | ✓ Normal |
{Job} is working. Execution Count: {Count} |
Job wird ausgeführt | ✓ Normal |
Keine Dateien mit dem Suchmuster {Pattern} |
Keine passenden Dateien | ⚠️ Überprüfen |
Importiere Datei {Datei} |
Datei wird verarbeitet | ✓ Normal |
Anzahl zu importierende Datensätze: {Anzahl} |
Daten geladen | ✓ Normal |
Daten wurden erfolgreich in {Tabelle} importiert |
Import erfolgreich | ✓ Normal |
Fehler beim Importieren aus Pfad {Pfad} |
Import fehlgeschlagen | ❌ Fehler beheben |
Event Viewer (Windows)
Der Service schreibt auch ins Windows Event Log:
# Event Log überprüfen
Get-EventLog -LogName Application -Source ExcelImportService -Newest 50
# Fehler filtern
Get-EventLog -LogName Application -Source ExcelImportService -EntryType Error -Newest 20
📚 Best Practices
1. Konfiguration
- ✅ Verwenden Sie aussagekräftige Job-Namen:
DailySalesImportstattJob1 - ✅ Dokumentieren Sie Cron-Ausdrücke mit Kommentaren: Nicht in JSON möglich, aber in separater Dokumentation
- ✅ Verwenden Sie spezifische Dateimuster:
Sales_*.xlsxstatt*.xlsx - ✅ Setzen Sie angemessene Log-Level:
Informationfür Produktion,Debugnur bei Problemen - ✅ Verwenden Sie sichere Connection Strings: Windows-Authentifizierung bevorzugen
2. Dateiorganisation
-
✅ Strukturierte Ordnerstruktur:
Import/ ├── Products/ │ ├── Current/ │ └── Archive/ ├── Sales/ │ ├── Current/ │ └── Archive/ └── Customers/ ├── Current/ └── Archive/ -
✅ Automatisches Archivieren: Externe Skripte zum Verschieben verarbeiteter Dateien
-
✅ Konsistente Dateinamen:
[Kategorie]_[Datum]_[Version].xlsx -
✅ Nur neueste Datei verwenden: Service wählt automatisch die neueste Datei
3. Datenbank-Design
-
✅ Staging-Tabellen verwenden:
-- Import in Staging-Tabelle CREATE TABLE ProductData_Staging (...); -- Nach Validierung in Produktiv-Tabelle kopieren INSERT INTO ProductData SELECT * FROM ProductData_Staging WHERE ...; -
✅ Indexe für Performance:
-- Index auf häufig gefilterte Spalten CREATE INDEX IX_ImportDate ON ProductData(ImportDate); -
✅ Importdatum-Spalte aktivieren: Für Nachverfolgbarkeit
-
✅ Audit-Trails: Zusätzliche Spalten für Änderungsverfolgung
4. Monitoring
- ✅ Regelmäßige Log-Überprüfung: Tägliche Kontrolle der Logs
- ✅ Datenvalidierung: SQL-Queries zur Überprüfung importierter Daten
- ✅ Alerts einrichten: z. B. bei fehlenden Dateien oder Fehlern
- ✅ Performance-Metriken: Import-Dauer und Datensatzanzahl tracken
5. Sicherheit
- ✅ Minimale Berechtigungen: Service-Account nur mit notwendigen Rechten
- ✅ Connection Strings verschlüsseln: Windows DPAPI oder Azure Key Vault
- ✅ SQL-Injection vermeiden: Service verwendet parametrisierte Queries
- ✅ Netzwerkfreigaben: UNC-Pfade mit entsprechenden Credentials
6. Wartung
- ✅ Regelmäßige Updates: .NET Runtime und NuGet-Pakete aktualisieren
- ✅ Log-Rotation: Automatische Bereinigung alter Logs (konfiguriert: 7 Tage)
- ✅ Backup-Strategie: Datenbank-Backups vor großen Imports
- ✅ Test-Umgebung: Neue Konfigurationen zuerst testen
7. Fehlerbehandlung
- ✅ Graceful Degradation: Service läuft weiter bei einzelnen Job-Fehlern
- ✅ Retry-Mechanismen: Bei temporären Fehlern automatisch wiederholen
- ✅ Benachrichtigungen: Email oder Teams-Notification bei kritischen Fehlern
- ✅ Rollback-Plan: Strategie für fehlerhafte Imports
❓ FAQ
Allgemeine Fragen
F: Kann der Service mehrere Jobs parallel ausführen? A: Ja, jeder Job läuft als eigenständiger HostedService und kann parallel ausgeführt werden. Beachten Sie jedoch Ressourcen-Limits und potenzielle Datenbank-Locks.
F: Werden Excel-Dateien nach dem Import gelöscht? A: Nein, der Service löscht keine Quelldateien. Sie müssen externe Skripte oder Tools für Archivierung verwenden.
F: Kann ich den Service auf Linux betreiben? A: Ja, als eigenständige Anwendung oder Docker-Container. Windows-Service-Funktionalität ist nur auf Windows verfügbar.
F: Unterstützt der Service Excel-Dateien mit mehreren Arbeitsblättern? A: Nur das erste Arbeitsblatt wird verarbeitet. Für mehrere Arbeitsblätter benötigen Sie separate Jobs oder eine Anpassung des Codes.
F: Wie werden Excel-Formeln behandelt? A: Nur die berechneten Werte werden importiert, nicht die Formeln selbst.
Konfiguration
F: Kann ich denselben Job mehrmals mit verschiedenen Zeitplänen ausführen? A: Erstellen Sie separate Jobs mit unterschiedlichen Namen aber denselben Einstellungen:
{
"ImportJobs": [
{"JobName": "MorningImport", "CronExpression": "0 6 * * *", ...},
{"JobName": "EveningImport", "CronExpression": "0 18 * * *", ...}
]
}
F: Kann ich verschiedene Connection Strings für verschiedene Jobs verwenden?
A: Ja, mit dem ConnectionString-Parameter in der Job-Konfiguration.
F: Wie kann ich den Service im Test-Modus ausführen?
A: Setzen Sie CronExpression: "* * * * *" für minutliche Ausführung und TruncateDestinationTable: false für sichere Tests.
Datenverarbeitung
F: Was passiert bei doppelten Daten?
A: Abhängig von TruncateDestinationTable:
true: Tabelle wird geleert, keine Duplikatefalse: Daten werden angehängt, Duplikate möglich (verwenden SieUNIQUE-Constraints)
F: Wie gehe ich mit unterschiedlichen Excel-Strukturen um? A: Jeder Job benötigt eine konsistente Excel-Struktur. Für verschiedene Strukturen verwenden Sie separate Jobs mit eigenen Zieltabellen.
F: Können Spalten umbenannt werden? A: Nicht direkt. Verwenden Sie SQL-Views oder Stored Procedures für Transformationen:
CREATE VIEW ProductsView AS
SELECT
OldColumnName AS NewColumnName,
...
FROM ProductData;
Performance
F: Wie kann ich große Dateien schneller importieren? A:
- Verwenden Sie
TruncateDestinationTable: truestattDELETE - Deaktivieren Sie Indizes vor dem Import
- Erhöhen Sie SQL Server-Ressourcen
- Verwenden Sie SSD-Speicher
F: Wie viele Jobs kann ich gleichzeitig ausführen? A: Abhängig von:
- Verfügbarem RAM (ca. 100-500 MB pro Job)
- CPU-Kernen
- Datenbank-Verbindungen
- I/O-Performance
Empfehlung: Maximal 5-10 parallele Jobs auf Standard-Hardware.
Troubleshooting
F: Der Service läuft, aber Daten werden nicht importiert. Was nun? A: Prüfen Sie in dieser Reihenfolge:
- Logs auf Fehler untersuchen
- Dateien im konfigurierten Pfad vorhanden?
- Cron-Zeitpunkt bereits erreicht?
- Datenbankverbindung funktioniert?
- SQL-Berechtigungen ausreichend?
F: Wie kann ich die nächste Ausführungszeit eines Jobs ermitteln? A: Suchen Sie im Log nach:
{Job} next run: 06.12.2024 02:00:00
F: Was bedeutet "Anzahl Datensätze: System.Object in Tabelle"? A: Normalerweise ein Anzeichen für erfolgreichen Import. Die Anzahl wird geloggt, aber die Log-Ausgabe kann manchmal den Typ statt des Wertes anzeigen.
Sicherheit
F: Wie sichere ich den Connection String ab? A: Optionen:
-
User Secrets (Entwicklung):
dotnet user-secrets set "connectionStrings:ConnectionString" "Server=..." -
Umgebungsvariablen (Produktion):
[Environment]::SetEnvironmentVariable("ConnectionStrings__ConnectionString", "Server=...", "Machine") -
Azure Key Vault (Cloud):
builder.Configuration.AddAzureKeyVault(...);
F: Welche SQL-Berechtigungen werden benötigt? A: Mindestens:
CREATE TABLE(wenn Tabellen automatisch erstellt werden)ALTER TABLE(für Spalten hinzufügen)INSERT(für Datenimport)TRUNCATE(wennTruncateDestinationTable: true)SELECT(für Datenvalidierung)
Erweiterte Nutzung
F: Kann ich den Import-Prozess anpassen? A: Ja, durch:
- Anpassung der
ExcelImporter- oderImporter-Klasse - Eigene Implementierung von
IExcelImporter - Erweiterung der
ImportSettingsmit zusätzlichen Parametern
F: Kann ich den Service programmgesteuert steuern? A: Der Service ist für autonomen Betrieb konzipiert. Für manuelle Steuerung:
- Service stoppen/starten via
sc.exeoder PowerShell - REST-API hinzufügen (erfordert Code-Änderung)
- Message Queue für Job-Trigger implementieren
F: Kann ich Benachrichtigungen bei Fehlern erhalten? A: Nicht out-of-the-box. Implementierungsmöglichkeiten:
- Serilog-Sink für Email/Teams/Slack
- Windows Event Log + Task Scheduler
- Monitoring-Tools wie Application Insights
📞 Support und Kontakt
Dokumentation
- Repository: https://github.com/CSS-EDV-Support/ExcelDataImporter
- Issues: GitHub Issues
Interne Nutzung
Dieses Projekt ist für die interne Verwendung bei CSS EDV-Support konzipiert. Bei Fragen oder Problemen wenden Sie sich an das CSS EDV-Support Development Team.
Externe Nutzung
Für die externe Nutzung oder kommerzielle Lizenzen kontaktieren Sie bitte CSS EDV-Support.
📝 Lizenz
© CSS EDV-Support – Interne Nutzung oder nach Rücksprache.
📊 Anhang
Glossar
| Begriff | Beschreibung |
|---|---|
| Cron-Ausdruck | Zeitplan-Format für wiederkehrende Aufgaben (5 Felder: Minute Stunde Tag Monat Wochentag) |
| Bulk-Insert | Hochperformante Methode zum Einfügen vieler Datensätze auf einmal |
| SqlBulkCopy | .NET-Klasse für effiziente Massen-Datenimporte in SQL Server |
| DevExpress | Kommerzieller Anbieter von UI- und Dokumenten-Verarbeitungskomponenten |
| HostedService | .NET-Konzept für lang laufende Background-Dienste |
| Serilog | Strukturiertes Logging-Framework für .NET |
| NCrontab | .NET-Bibliothek für Cron-Expression-Parsing |
| Forward-Fill | Technik zum Füllen leerer Zellen mit vorherigen Werten |
| Truncate | SQL-Befehl zum schnellen Leeren einer Tabelle |
Änderungshistorie
| Version | Datum | Änderungen |
|---|---|---|
| 1.0.0 | 2024-12-05 | Initiale ausführliche Dokumentation erstellt |