Migrate solution from .NET 7 to .NET 9 - #67
devin-ai-integration[bot] wants to merge 2 commits into
Conversation
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
| <PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.18" /> | ||
| <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.18"> | ||
| <PrivateAssets>all</PrivateAssets> | ||
| <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> | ||
| </PackageReference> | ||
| <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="7.0.10" /> | ||
| <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="7.0.10"> | ||
| <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="9.0.18" /> | ||
| <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="9.0.18"> |
There was a problem hiding this comment.
📝 Info: EF migration snapshot still records EF Core 7 product version
The retarget updates EF Core packages to 9.0.18, but the existing migration artifacts still declare .HasAnnotation("ProductVersion", "7.0.10") (src/Infrastructure/Migrations/SampleDbContextModelSnapshot.cs:20 and src/Infrastructure/Migrations/20240113141226_Initialize.Designer.cs:23). This is metadata only and does not break existing migrations, but the next Add-Migration under EF 9 will regenerate the snapshot; teams sometimes prefer regenerating explicitly during a major-version migration so the checked-in snapshot matches the toolchain.
Was this helpful? React with 👍 or 👎 to provide feedback.
| FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS base | ||
| WORKDIR /app | ||
| EXPOSE 5000 |
There was a problem hiding this comment.
🔍 Base image default port change in .NET 8+ only masked by compose env var
mcr.microsoft.com/dotnet/aspnet:9.0 defaults to ASPNETCORE_HTTP_PORTS=8080 (unlike the 7.0 image, which defaulted to port 80). The Dockerfile keeps EXPOSE 5000 and relies on ASPNETCORE_URLS=http://+:5000 supplied by docker-compose.yml. Running the image standalone (docker run -p 5000:5000) will now silently listen on 8080 instead, so consider setting ENV ASPNETCORE_HTTP_PORTS=5000 (or ASPNETCORE_URLS) in the Dockerfile to keep the image self-consistent.
Was this helpful? React with 👍 or 👎 to provide feedback.
| <PackageReference Include="FakeItEasy" Version="9.0.1" /> | ||
| <PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.8.1" /> | ||
| <PackageReference Include="xunit" Version="2.9.3" /> | ||
| <PackageReference Include="xunit.runner.visualstudio" Version="3.1.5"> | ||
| <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> | ||
| <PrivateAssets>all</PrivateAssets> | ||
| </PackageReference> |
There was a problem hiding this comment.
🔍 Test tooling major bumps worth verifying in CI
Microsoft.NET.Test.Sdk moves to an 18.x major and xunit.runner.visualstudio to 3.1.5 while xunit remains on the v2 line (2.9.3). The v3 VSTest runner does support xunit v2 assemblies, but the combination plus the Test.Sdk major bump changes the default test host/platform behavior, so confirm dotnet test --no-build in .github/workflows/dotnet.yml still discovers and runs all 20 tests rather than reporting zero tests as a pass.
Was this helpful? React with 👍 or 👎 to provide feedback.
Runtime testing of the .NET 9 migrationTested end-to-end with Testing surfaced two runtime regressions caused by the version bumps; both are now fixed in this PR (commit Fixed 1:
|
| Npgsql | Result |
|---|---|
| 7.0.6 (pre-PR) | OPEN OK |
| 8.0.3 | ArgumentException: Couldn't set integratedsecurity |
| 9.0.5 (this PR) | ArgumentException: Couldn't set integratedsecurity |
EducationsController swallows the exception, so the only symptom is a bare 500 with nothing in the logs.
-ConnectionStrings__DefaultConnection=User ID=sara;Password=mysecretpassword;Server=postgres_container;Port=5432;Database=SampleDB;IntegratedSecurity=true;Pooling=true;
+ConnectionStrings__DefaultConnection=Host=postgres_container;Port=5432;Database=SampleDB;Username=sara;Password=mysecretpassword;Pooling=true;appsettings.json was already in the modern Host=...;Username=... form.
Fixed 2: README's update-database step failed under EF Core 9
Microsoft.EntityFrameworkCore.Migrations.PendingModelChangesWarning:
The model for context 'SampleDbContext' changes each time it is built.
SampleDbContext.OnModelCreating seeded with Guid.NewGuid(); EF Core 7 logged this as a warning, EF Core 9 promotes it to an error. The seed id is now hard-coded to the one already baked into 20240113141226_Initialize (c92ea179-…), so there is no schema or data change. dotnet ef migrations has-pending-model-changes now reports No changes have been made to the model since the last migration.
Verified on .NET 9
Full CRUD lifecycle: create → read → update → restart the API container → delete, cross-checked in Postgres.
Swashbuckle 9 renders correctly and EF Core 9's generated migration SQL applies cleanly:
Pre-existing (not a regression): /health returns 404 — left unchanged
Program.cs calls AddHealthChecks().AddNpgSql(...) but never app.MapHealthChecks("/health"), so the endpoint has never existed. Out of scope for this migration.
Full assertion list
| Check | Result |
|---|---|
| aspnet:9.0 / sdk:9.0 images build; containers start; Kestrel on :5000 | pass |
| EF Core 9 migration SQL applies to Postgres | pass |
dotnet ef reports no pending model changes (after fix 2) |
pass |
| Swagger UI (Swashbuckle 9) loads, 5 ops + schema | pass |
| Compose config serves requests (after fix 1) | pass |
| GET list → seed row | pass |
| POST → 200 + server-assigned GUID | pass |
| GET by id | pass |
| PUT → 200, change persisted on re-GET | pass |
Survives docker restart webapi_container |
pass |
| DELETE → 200, row gone in API and psql | pass |
/health responds |
fail (pre-existing 404) |
| Unit tests (20/20) on net9.0 | pass |
Caveat: the CRUD run was executed with a temporary local override supplying the corrected connection string; that same fix is now committed, but the compose stack has not been re-run against the committed config.
Summary
Retargets all six projects to
net9.0and moves the dependency graph onto the 9.x lines (EF Core / OpenAPI9.0.18, Npgsql9.0.5+ Npgsql EF provider & NodaTime9.0.4, Swashbuckle9.0.6, HealthChecks.NpgSql9.0.0, Mapster7.4.0), plus current stable test tooling (Test.Sdk18.8.1, xunit2.9.3, runner.visualstudio3.1.5, FakeItEasy9.0.1, coverlet6.0.4).Dockerfile base images bumped to
aspnet:9.0/sdk:9.0; CI now usesdotnet-version: 9.0.xwithactions/checkout@v4andactions/setup-dotnet@v4(it was previously pinned to 6.0.x, i.e. not even matching the old target).No source changes were needed —
restore,build, andtestall succeed on net9.0 (20/20 tests pass) with no new warnings beyond the three pre-existing nullable warnings (Program.csAddNpgSqlconnection string, twonullliterals inEducationsControllerTests).Link to Devin session: https://app.devin.ai/sessions/b6a7699f1e004c54b18271326667eac3
Requested by: @detectiveharree
Devin Review