diff --git a/EnvelopeGenerator.Server/EnvelopeGenerator.Server/README.md b/EnvelopeGenerator.Server/EnvelopeGenerator.Server/README.md new file mode 100644 index 00000000..4f63e138 --- /dev/null +++ b/EnvelopeGenerator.Server/EnvelopeGenerator.Server/README.md @@ -0,0 +1,225 @@ +# EnvelopeGenerator.Server — Publish & Deployment Guide + +## Inhaltsverzeichnis + +1. [Unterschied zu einer normalen ASP.NET Core API](#unterschied-zu-einer-normalen-aspnet-core-api) +2. [Warum Self-Contained Publish?](#warum-self-contained-publish) +3. [Publish-Befehl (Terminal)](#publish-befehl-terminal) +4. [IIS-Konfiguration](#iis-konfiguration) +5. [Verzeichnisstruktur nach dem Publish](#verzeichnisstruktur-nach-dem-publish) +6. [Häufige Fehler](#häufige-fehler) + +--- + +## Unterschied zu einer normalen ASP.NET Core API + +`EnvelopeGenerator.Server` ist **keine** gewöhnliche ASP.NET Core Web API. Es handelt sich um eine **Blazor Auto (Server + WebAssembly Hybrid)**-Anwendung. + +| Merkmal | Normale ASP.NET Core API | EnvelopeGenerator.Server (Blazor Auto) | +|---|---|---| +| Projekttyp | `Microsoft.NET.Sdk.Web` | `Microsoft.NET.Sdk.Web` + WASM Client | +| Frontend | Keins / Razor Pages | Blazor Server + Blazor WASM | +| WASM-Komponente | Nein | Ja (`EnvelopeGenerator.Server.Client`) | +| Framework-DLL-Bindung | Tolerant gegenüber Runtime-Versionen | **Strikt**: WASM erwartet exakte Assembly-Versionen | +| Publish ohne .NET auf Zielserver | Nicht nötig (FDD reicht meist) | **Self-Contained Pflicht** empfohlen | +| IIS Application Pool | `.NET CLR v4.0` oder `No Managed Code` | **Zwingend: `No Managed Code`** | +| Publish-Paketgröße | ~5–20 MB | **~500 MB** (enthält .NET Runtime) | +| `web.config processPath` | `dotnet` + `.dll` | **`.\EnvelopeGenerator.Server.exe`** | + +### Warum die WASM-Komponente den Unterschied macht + +Die WASM-Seite der Anwendung (`EnvelopeGenerator.Server.Client`) bindet Assemblies wie +`Microsoft.Extensions.DependencyInjection.Abstractions` in einer **fest definierten Version**. +Bei einem **Framework-Dependent Deployment** werden diese Assemblies nicht mitgeliefert und +müssen auf dem Zielserver vorhanden sein — in der exakt passenden Version. + +Fehlt die passende .NET-Runtime auf dem Zielserver, erscheint folgender Fehler beim Start: + +``` +Unhandled exception. System.IO.FileNotFoundException: +Could not load file or assembly +'Microsoft.Extensions.DependencyInjection.Abstractions, Version=8.0.0.0' +``` + +--- + +## Warum Self-Contained Publish? + +Beim **Self-Contained Deployment** werden **alle benötigten .NET Runtime-DLLs** in das +Ausgabeverzeichnis kopiert. Die Anwendung ist damit vollständig unabhängig von der auf dem +Zielserver installierten .NET-Version. + +| | Framework-Dependent | Self-Contained | +|---|---|---| +| .NET auf Zielserver nötig | Ja | **Nein** | +| Paketgröße | ~20 MB | ~500 MB | +| `runtimeconfig.json` | `frameworkVersion` vorhanden | `includedFrameworks` (Runtime eingebettet) | +| Fehleranfälligkeit auf Fremd-PC | Hoch | Minimal | + +--- + +## Publish-Befehl (Terminal) + +### Empfohlener Befehl (Self-Contained, win-x64) + +```bat +dotnet publish EnvelopeGenerator.Server\EnvelopeGenerator.Server\EnvelopeGenerator.Server.csproj ^ + -c Release ^ + -f net8.0 ^ + --self-contained true ^ + --runtime win-x64 ^ + -o .\publish-output +``` + +> Dieser Befehl muss vom **Solution-Root-Verzeichnis** aus ausgefuehrt werden. +> Alternativ: `publish.bat` im selben Verzeichnis wie diese README ausfuehren. + +### Parameter-Erklaerung + +| Parameter | Bedeutung | +|---|---| +| `-c Release` | Release-Konfiguration (optimiert, kein Debug-Code) | +| `-f net8.0` | Ziel-Framework explizit angeben (Pflicht, da `` mehrere Werte haben kann) | +| `--self-contained true` | Alle .NET Runtime-DLLs ins Ausgabeverzeichnis kopieren | +| `--runtime win-x64` | Zielplattform: Windows 64-Bit | +| `-o .\publish-output` | Ausgabeverzeichnis | + +### Doğrulama nach dem Publish + +Nach erfolgreichem Publish folgende Dateien im Ausgabeverzeichnis prüfen: + +```powershell +# Diese Dateien MÜSSEN vorhanden sein (Self-Contained-Nachweis): +Test-Path ".\publish-output\hostfxr.dll" # .NET Host +Test-Path ".\publish-output\coreclr.dll" # .NET Core Runtime +Test-Path ".\publish-output\Microsoft.Extensions.DependencyInjection.Abstractions.dll" +Test-Path ".\publish-output\EnvelopeGenerator.Server.exe" +Test-Path ".\publish-output\web.config" +``` + +Alle Ergebnisse müssen `True` sein. + +--- + +## IIS-Konfiguration + +> **WICHTIG:** Diese Einstellungen unterscheiden sich von einer normalen ASP.NET Core API +> und sind zwingend erforderlich. + +### 1. Application Pool — `No Managed Code` + +ASP.NET Core (und damit auch Blazor) verwaltet seinen eigenen Runtime-Lifecycle. +IIS darf **keinen** .NET CLR-Managed-Code-Kontext aktivieren. + +**Einstellung:** + +``` +IIS Manager + → Application Pools + → [Pool-Name der Anwendung] → Basic Settings + → .NET CLR Version: "No Managed Code" ← ZWINGEND +``` + +> **Fehler bei falscher Einstellung:** HTTP 500.30 — ASP.NET Core app failed to start +> (sc-win32-status: 574 in IIS-Logs) + +### 2. ASP.NET Core Module V2 + +Das IIS-Modul `AspNetCoreModuleV2` muss installiert sein. +Es wird über das **.NET Hosting Bundle** mitgeliefert. + +Prüfen: +``` +IIS Manager → Modules → "AspNetCoreModuleV2" vorhanden? +``` + +Falls nicht installiert: [.NET 8 Hosting Bundle herunterladen](https://dotnet.microsoft.com/en-us/download/dotnet/8.0) +und nach der Installation IIS neu starten: + +```cmd +net stop was /y && net start w3svc +``` + +### 3. web.config — Korrekte Konfiguration für Self-Contained + +Nach dem Publish wird `web.config` automatisch generiert. Für Self-Contained muss sie so aussehen: + +```xml + + + + + + + + + + + +``` + +**Kritische Unterschiede zu Framework-Dependent:** + +| Eigenschaft | Framework-Dependent (FALSCH) | Self-Contained (RICHTIG) | +|---|---|---| +| `processPath` | `dotnet` | `.\EnvelopeGenerator.Server.exe` | +| `arguments` | `.\EnvelopeGenerator.Server.dll` | *(leer oder weggelassen)* | + +### 4. Berechtigungen für das `logs`-Verzeichnis + +Wenn `stdoutLogEnabled="true"` gesetzt wird (zur Fehlerdiagnose), muss das `logs`-Verzeichnis +existieren und der IIS-Prozess muss Schreibrechte haben: + +```powershell +New-Item -ItemType Directory -Path "C:\inetpub\wwwroot\\logs" -Force +icacls "C:\inetpub\wwwroot\\logs" /grant "IIS_IUSRS:(OI)(CI)F" +``` + +> Ohne dieses Verzeichnis kann die Anwendung bei aktiviertem Logging **nicht starten**. + +### 5. Application Pool Recycle nach Deployment + +Nach jedem Deployment den Application Pool neu starten: + +```cmd +# IIS Manager → Application Pools → [Pool] → Recycle +# oder per Kommandozeile (als Administrator): +%windir%\system32\inetsrv\appcmd recycle apppool /apppool.name:"" +``` + +--- + +## Verzeichnisstruktur nach dem Publish + +``` +publish-output\ +├── EnvelopeGenerator.Server.exe ← Startpunkt (Self-Contained) +├── EnvelopeGenerator.Server.dll ← Managed Assembly +├── EnvelopeGenerator.Server.runtimeconfig.json +├── EnvelopeGenerator.Server.deps.json +├── web.config ← IIS-Konfiguration (auto-generiert) +├── hostfxr.dll ← .NET Host (Self-Contained-Nachweis) +├── coreclr.dll ← .NET Core Runtime +├── Microsoft.Extensions.*.dll ← Framework-DLLs (jetzt enthalten!) +├── DevExpress.*.dll ← UI-Komponenten +├── wwwroot\ ← Statische Web-Assets +│ ├── _framework\ ← WASM-Binaries +│ └── ... +└── logs\ ← Stdout-Logs (manuell anlegen!) +``` + +--- + +## Häufige Fehler + +| Fehler | Ursache | Lösung | +|---|---|---| +| `FileNotFoundException: Microsoft.Extensions.DependencyInjection.Abstractions` | Framework-Dependent Publish auf Server ohne .NET 8 | Self-Contained Publish verwenden | +| `HTTP 500.30` in IIS | App startet nicht | Application Pool auf `No Managed Code` setzen | +| `HTTP 500.30` + `sc-win32-status: 574` | App Pool falsch oder `AspNetCoreModuleV2` fehlt | Pool prüfen + Hosting Bundle installieren | +| App startet per `.exe`, aber nicht in IIS | `web.config` hat noch `processPath="dotnet"` | `web.config` auf `.\EnvelopeGenerator.Server.exe` korrigieren | +| Logs-Verzeichnis fehlt → App startet nicht | `stdoutLogEnabled="true"` aber `logs\` existiert nicht | `logs\`-Ordner anlegen + IIS_IUSRS Schreibrecht geben |