Add Publish & Deployment Guide to README.md

Added a detailed "Publish & Deployment Guide" to the README for the `EnvelopeGenerator.Server` project. The guide includes:

- Table of contents for easy navigation.
- Explanation of differences between `EnvelopeGenerator.Server` and a standard ASP.NET Core API.
- Justification for self-contained publishing and its benefits.
- Recommended `dotnet publish` command with parameter explanations.
- IIS configuration steps, including Application Pool settings, `web.config` adjustments, and module requirements.
- Verification checklist for published output files.
- Instructions for setting up logging and recycling the IIS Application Pool.
- Directory structure overview post-publish.
- Troubleshooting common deployment errors with solutions.

This guide ensures developers and administrators can successfully publish and deploy the application.
This commit is contained in:
2026-07-02 15:44:36 +02:00
parent 33439f4a65
commit b2c205b160

View File

@@ -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 | ~520 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 `<TargetFrameworks>` 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
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<location path="." inheritInChildApplications="false">
<system.webServer>
<handlers>
<add name="aspNetCore" path="*" verb="*"
modules="AspNetCoreModuleV2" resourceType="Unspecified" />
</handlers>
<aspNetCore processPath=".\EnvelopeGenerator.Server.exe"
stdoutLogEnabled="false"
stdoutLogFile=".\logs\stdout"
hostingModel="inprocess" />
</system.webServer>
</location>
</configuration>
```
**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\<App-Pfad>\logs" -Force
icacls "C:\inetpub\wwwroot\<App-Pfad>\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:"<Pool-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 |