Phase 1: Solution auf .NET 10 und zentrale Paketverwaltung

Zielframework aller Projekte auf net10.0 (WinFormsHost: net10.0-windows),
zentral in Directory.Build.props statt je csproj. SatelliteResourceLanguages
ebenfalls zentralisiert.

Neue Directory.Packages.props mit ManagePackageVersionsCentrally: 21 Pakete,
Versionsangaben aus allen csproj entfernt.

EF Core bleibt bewusst auf 9.0.18 mit Pomelo 9.0.0. Pomelo hat keine
EF-Core-10-Version; 9.0.0 pinnt EntityFrameworkCore.Relational auf
[9.0.0, 9.0.999]. Die EF-9-Pakete zielen auf net8.0 und laufen auf der
net10.0-Runtime. Begruendung als Kommentar in Directory.Packages.props.

Uebrige Pakete auf aktuellen Stand: Swashbuckle 10.2.3 (ohne Bruchstellen),
Serilog 4.4.0, Microsoft.Extensions 10.0.10, Test-SDK 18.8.1, coverlet 10.0.1.

Sicherheits-Pin: SQLitePCLRaw 2.1.12 statt transitiv 2.1.10
(GHSA-2m69-gcr7-jv3q, High). Dazu CentralPackageTransitivePinningEnabled.

Build: 0 Fehler, 8 Warnungen (alle vorbestehend).
Tests: 100 bestanden, 0 Fehler, 1 uebersprungen, Testhost net10.0.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Richard
2026-08-06 22:54:18 +02:00
co-authored by Claude Opus 5
parent f82a693818
commit c9eff9f75e
10 changed files with 146 additions and 64 deletions
+6
View File
@@ -1,8 +1,14 @@
<Project> <Project>
<PropertyGroup> <PropertyGroup>
<!-- Zielframework zentral. Ausnahme: Predictalytics.WinFormsHost setzt
net10.0-windows, weil WinForms das Windows-Desktop-Pack braucht. -->
<TargetFramework>net10.0</TargetFramework>
<LangVersion>latest</LangVersion> <LangVersion>latest</LangVersion>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors> <TreatWarningsAsErrors>false</TreatWarningsAsErrors>
<!-- Die Anwendung wird nicht lokalisiert; lokalisierte Satelliten-Assemblies
der Abhaengigkeiten blaehen nur das Publish-Output auf. -->
<SatelliteResourceLanguages>en</SatelliteResourceLanguages>
</PropertyGroup> </PropertyGroup>
</Project> </Project>
+68
View File
@@ -0,0 +1,68 @@
<Project>
<PropertyGroup>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
<!-- Erlaubt, transitive Abhaengigkeiten hochzuziehen (siehe Sicherheits-Pins unten). -->
<CentralPackageTransitivePinningEnabled>true</CentralPackageTransitivePinningEnabled>
</PropertyGroup>
<!-- Sicherheits-Pins fuer transitive Abhaengigkeiten.
SQLitePCLRaw kommt ueber Microsoft.EntityFrameworkCore.Sqlite (nur Testprojekt).
EF Core 9.0.18 zieht 2.1.10, das GHSA-2m69-gcr7-jv3q (High) aufweist. -->
<ItemGroup>
<PackageVersion Include="SQLitePCLRaw.lib.e_sqlite3" Version="2.1.12" />
<PackageVersion Include="SQLitePCLRaw.bundle_e_sqlite3" Version="2.1.12" />
<PackageVersion Include="SQLitePCLRaw.core" Version="2.1.12" />
<PackageVersion Include="SQLitePCLRaw.provider.e_sqlite3" Version="2.1.12" />
</ItemGroup>
<!-- ══════════════════════════════════════════════════════════════════════
Entity Framework Core — bewusst auf 9.x festgehalten.
Pomelo.EntityFrameworkCore.MySql hat keine EF-Core-10-Version; die
neueste stabile 9.0.0 pinnt Microsoft.EntityFrameworkCore.Relational
auf [9.0.0, 9.0.999] — eine harte Obergrenze. Die EF-9-Pakete zielen
auf net8.0 und laufen problemlos auf der net10.0-Runtime.
Vor einem Upgrade auf EF Core 10 zuerst pruefen, ob Pomelo nachgezogen
hat. Siehe docs/PLAN-Linux-Portierung.md, Abschnitt 0.1.
══════════════════════════════════════════════════════════════════════ -->
<ItemGroup>
<PackageVersion Include="Microsoft.EntityFrameworkCore" Version="9.0.18" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Relational" Version="9.0.18" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.18" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.InMemory" Version="9.0.18" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Sqlite" Version="9.0.18" />
<PackageVersion Include="Pomelo.EntityFrameworkCore.MySql" Version="9.0.0" />
</ItemGroup>
<!-- Microsoft.Extensions — passend zur net10.0-Runtime -->
<ItemGroup>
<PackageVersion Include="Microsoft.Extensions.Http" Version="10.0.10" />
<PackageVersion Include="Microsoft.Extensions.Hosting.Abstractions" Version="10.0.10" />
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.10" />
</ItemGroup>
<!-- Serilog -->
<ItemGroup>
<PackageVersion Include="Serilog" Version="4.4.0" />
<PackageVersion Include="Serilog.AspNetCore" Version="10.0.0" />
<PackageVersion Include="Serilog.Extensions.Logging" Version="10.0.0" />
<PackageVersion Include="Serilog.Sinks.File" Version="7.0.0" />
<PackageVersion Include="Serilog.Sinks.Console" Version="6.1.1" />
<PackageVersion Include="Serilog.Formatting.Compact" Version="3.0.0" />
</ItemGroup>
<!-- API-Dokumentation -->
<ItemGroup>
<PackageVersion Include="Swashbuckle.AspNetCore" Version="10.2.3" />
</ItemGroup>
<!-- Test -->
<ItemGroup>
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="18.8.1" />
<PackageVersion Include="xunit" Version="2.9.3" />
<PackageVersion Include="xunit.runner.visualstudio" Version="3.1.5" />
<PackageVersion Include="Moq" Version="4.20.72" />
<PackageVersion Include="coverlet.collector" Version="10.0.1" />
</ItemGroup>
</Project>
+34 -16
View File
@@ -145,23 +145,36 @@ sind aussagekräftig.
--- ---
## 3. Phase 1 — .NET 10 (1,52,5 PT) ## 3. Phase 1 — .NET 10 ✅ **erledigt (2026-08-06)**
Bewusst **vor** dem Avalonia-Umbau: eine Baustelle nach der anderen, und das Shell-Projekt **Abnahme erreicht:** `dotnet build` → 0 Fehler, 8 Warnungen (alle vorbestehend, 2 weniger
entsteht dann direkt auf dem Zielframework. als vorher). `dotnet test`**100 bestanden, 0 Fehler, 1 übersprungen**, Testhost
`net10.0`. Alle Projekte laufen auf `net10.0`, WinFormsHost auf `net10.0-windows`.
### AP 1.1 — Zentrale Frameworkverwaltung Ergebnis gegenüber der Planung:
`Directory.Build.props` erweitern:
```xml | Erwartung | Tatsächlich |
<TargetFramework>net10.0</TargetFramework> |---|---|
<LangVersion>latest</LangVersion> | Swashbuckle 6.9 → 10.x „wahrscheinlichster Reibungspunkt", ggf. Wechsel auf `AddOpenApi()` | **Keine Bruchstelle.** Der genutzte API-Ausschnitt (`AddSwaggerGen`/`SwaggerDoc`/`UseSwagger`/`UseSwaggerUI`) ist stabil geblieben. Kein Umbau nötig. |
<Nullable>enable</Nullable> | EF Core 8 → 9 „überschaubar" | Bestätigt, keine Anpassung nötig |
<ImplicitUsings>enable</ImplicitUsings> | SQLite-Sicherheitswarnung „löst sich mit dem EF-Bump von selbst" | **Falsch** — EF Core 9.0.18 zieht SQLitePCLRaw 2.1.10, weiterhin von GHSA-2m69-gcr7-jv3q betroffen. Behoben über einen expliziten transitiven Pin auf 2.1.12. |
```
`<TargetFramework>` aus allen `.csproj` entfernen (Ausnahme: WinFormsHost → Bewusst **vor** dem Avalonia-Umbau erledigt: eine Baustelle nach der anderen, und das
`net10.0-windows`). Empfohlen: zugleich `Directory.Packages.props` mit Shell-Projekt entsteht direkt auf dem Zielframework.
`ManagePackageVersionsCentrally` einführen — bei 7+ Projekten mit überlappenden Paketen
verhindert das künftige Versionsdrift. ### AP 1.1 — Zentrale Frameworkverwaltung ✅
`Directory.Build.props` setzt `TargetFramework=net10.0` zentral; `<TargetFramework>` aus
allen `.csproj` entfernt (Ausnahme: WinFormsHost → `net10.0-windows`). Zusätzlich zentral:
`SatelliteResourceLanguages=en`, das bisher in vier Projekten einzeln stand.
`Directory.Packages.props` mit `ManagePackageVersionsCentrally` eingeführt — 21 Pakete,
Versionen aus allen `.csproj` entfernt. Zusätzlich
`CentralPackageTransitivePinningEnabled`, um Sicherheits-Pins auf transitive
Abhängigkeiten setzen zu können.
**Nicht angefasst:** `Spike/Spike.csproj` — leeres Restprojekt ohne Quelldateien, nicht in
der Solution, baut auch im Ist-Zustand nicht (`CS5001: keine Main-Methode`). Kandidat zum
Löschen, aber nicht Teil dieser Portierung.
### AP 1.2 — Paketmatrix ### AP 1.2 — Paketmatrix
@@ -178,7 +191,12 @@ verhindert das künftige Versionsdrift.
| `Microsoft.Extensions.Http` / `.Hosting.Abstractions` / `.Logging.Abstractions` | 8.0.x | 10.0.x | | | `Microsoft.Extensions.Http` / `.Hosting.Abstractions` / `.Logging.Abstractions` | 8.0.x | 10.0.x | |
| `Microsoft.NET.Test.Sdk` / `xunit` / `Moq` / `coverlet` | aktuell | prüfen | | | `Microsoft.NET.Test.Sdk` / `xunit` / `Moq` / `coverlet` | aktuell | prüfen | |
### AP 1.3 — Erwartete Bruchstellen Tatsächlich aufgelöste Versionen (verifiziert über `dotnet list package`): EF Core 9.0.18,
Pomelo 9.0.0, Serilog 4.4.0 / Extensions.Logging 10.0.0 / Sinks.File 7.0.0 /
Sinks.Console 6.1.1, Swashbuckle 10.2.3, Test-SDK 18.8.1, coverlet 10.0.1.
Sicherheits-Pin: SQLitePCLRaw 2.1.12 (statt transitiv 2.1.10).
### AP 1.3 — Erwartete Bruchstellen *(Rückblick: keine eingetreten)*
* **Swashbuckle 6.9 → 10.x** ist der wahrscheinlichste Reibungspunkt: geänderte API-Oberfläche, * **Swashbuckle 6.9 → 10.x** ist der wahrscheinlichste Reibungspunkt: geänderte API-Oberfläche,
und ASP.NET Core 10 bringt mit `Microsoft.AspNetCore.OpenApi` eine eigene und ASP.NET Core 10 bringt mit `Microsoft.AspNetCore.OpenApi` eine eigene
OpenAPI-Generierung mit. Betrifft `Api/ApiConfiguration.cs:19-20` und OpenAPI-Generierung mit. Betrifft `Api/ApiConfiguration.cs:19-20` und
@@ -1,15 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk.Web"> <Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<RootNamespace>Predictalytics.Api</RootNamespace> <RootNamespace>Predictalytics.Api</RootNamespace>
<!-- This project is used as a library by WinFormsHost; it does not run standalone --> <!-- This project is used as a library by WinFormsHost; it does not run standalone -->
<OutputType>Library</OutputType> <OutputType>Library</OutputType>
<SatelliteResourceLanguages>en</SatelliteResourceLanguages>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.9.0" /> <PackageReference Include="Swashbuckle.AspNetCore" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
@@ -1,20 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable> <IsPackable>false</IsPackable>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="coverlet.collector" Version="6.0.4" /> <PackageReference Include="coverlet.collector" />
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="8.0.11" /> <PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.11" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1" /> <PackageReference Include="Microsoft.NET.Test.Sdk" />
<PackageReference Include="Moq" Version="4.20.72" /> <PackageReference Include="Moq" />
<PackageReference Include="xunit" Version="2.9.3" /> <PackageReference Include="xunit" />
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.4" /> <PackageReference Include="xunit.runner.visualstudio" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
@@ -1,12 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<RootNamespace>Predictalytics.Application</RootNamespace> <RootNamespace>Predictalytics.Application</RootNamespace>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.2" /> <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
@@ -1,7 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<RootNamespace>Predictalytics.Domain</RootNamespace> <RootNamespace>Predictalytics.Domain</RootNamespace>
</PropertyGroup> </PropertyGroup>
@@ -1,26 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<RootNamespace>Predictalytics.Infrastructure</RootNamespace> <RootNamespace>Predictalytics.Infrastructure</RootNamespace>
<SatelliteResourceLanguages>en</SatelliteResourceLanguages>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.11" /> <PackageReference Include="Microsoft.EntityFrameworkCore" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="8.0.11" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Relational" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.11"> <PackageReference Include="Microsoft.EntityFrameworkCore.Design">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="8.0.2" /> <PackageReference Include="Pomelo.EntityFrameworkCore.MySql" />
<PackageReference Include="Serilog" Version="4.2.0" /> <PackageReference Include="Serilog" />
<PackageReference Include="Serilog.Extensions.Logging" Version="8.0.0" /> <PackageReference Include="Serilog.Extensions.Logging" />
<PackageReference Include="Serilog.Sinks.File" Version="6.0.0" /> <PackageReference Include="Serilog.Sinks.File" />
<PackageReference Include="Serilog.Sinks.Console" Version="6.0.0" /> <PackageReference Include="Serilog.Sinks.Console" />
<PackageReference Include="Serilog.Formatting.Compact" Version="3.0.0" /> <PackageReference Include="Serilog.Formatting.Compact" />
<PackageReference Include="Microsoft.Extensions.Http" Version="8.0.1" /> <PackageReference Include="Microsoft.Extensions.Http" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="8.0.1" /> <PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
@@ -2,29 +2,30 @@
<PropertyGroup> <PropertyGroup>
<OutputType>WinExe</OutputType> <OutputType>WinExe</OutputType>
<TargetFramework>net8.0-windows</TargetFramework> <!-- Ueberschreibt Directory.Build.props: WinForms braucht das Windows-Desktop-Pack.
Entfaellt, sobald die Avalonia-Shell den WinForms-Host abloest. -->
<TargetFramework>net10.0-windows</TargetFramework>
<UseWindowsForms>true</UseWindowsForms> <UseWindowsForms>true</UseWindowsForms>
<RootNamespace>Predictalytics.WinFormsHost</RootNamespace> <RootNamespace>Predictalytics.WinFormsHost</RootNamespace>
<SatelliteResourceLanguages>en</SatelliteResourceLanguages>
<ApplicationHighDpiMode>SystemAware</ApplicationHighDpiMode> <ApplicationHighDpiMode>SystemAware</ApplicationHighDpiMode>
<ApplicationVisualStyles>true</ApplicationVisualStyles> <ApplicationVisualStyles>true</ApplicationVisualStyles>
<ApplicationManifest>app.manifest</ApplicationManifest> <ApplicationManifest>app.manifest</ApplicationManifest>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.11"> <PackageReference Include="Microsoft.EntityFrameworkCore.Design">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
</PackageReference> </PackageReference>
<PackageReference Include="Serilog" Version="4.2.0" /> <PackageReference Include="Serilog" />
<PackageReference Include="Serilog.AspNetCore" Version="8.0.3" /> <PackageReference Include="Serilog.AspNetCore" />
<PackageReference Include="Serilog.Extensions.Logging" Version="8.0.0" /> <PackageReference Include="Serilog.Extensions.Logging" />
<PackageReference Include="Serilog.Sinks.File" Version="6.0.0" /> <PackageReference Include="Serilog.Sinks.File" />
<PackageReference Include="Serilog.Sinks.Console" Version="6.0.0" /> <PackageReference Include="Serilog.Sinks.Console" />
<PackageReference Include="Serilog.Formatting.Compact" Version="3.0.0" /> <PackageReference Include="Serilog.Formatting.Compact" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.9.0" /> <PackageReference Include="Swashbuckle.AspNetCore" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.11" /> <PackageReference Include="Microsoft.EntityFrameworkCore" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="8.0.11" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Relational" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
@@ -1,17 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<RootNamespace>Predictalytics.Worker</RootNamespace> <RootNamespace>Predictalytics.Worker</RootNamespace>
<SatelliteResourceLanguages>en</SatelliteResourceLanguages>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.11"> <PackageReference Include="Microsoft.EntityFrameworkCore.Design">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
</PackageReference> </PackageReference>
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="8.0.1" /> <PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>