Re-platform SampleMvcWebApp from ASP.NET MVC 5 / .NET 4.5.1 to ASP.NET Core MVC / .NET 10 - #29
Conversation
…ET 10 re-platform gotchas
…+ EF Core 10 - SDK-style net10.0 projects, packages.config/App.config/AssemblyInfo removed - SampleWebAppDb rewritten for EF Core: DbContextOptions ctor, TagPosts join table and unique Tag.Slug index kept, EF6 ValidateEntity replaced by validation inside the SaveChanges overrides plus SaveChangesWithValidation - initial EF Core migration, design-time factory and MigrateAndSeed helper - Autofac modules replaced by AddDataLayer/AddBizLayer/AddServiceLayer - ServiceLayer DTOs moved to EfCore.GenericServices ILinkToEntity<T>, with hand-written IPostDtoService/IPostDtoServiceAsync for the blogger and tags handling that GenericServices no longer provides Co-Authored-By: sameer.husain <sameer.husain@cognition.ai>
…MVC on .NET 10
- SDK-style Microsoft.NET.Sdk.Web project targeting net10.0; drop packages.config,
Global.asax, App_Start, Web*.config, AssemblyInfo, Settings.settings and Log4Net.xml
- Program.cs minimal hosting replaces Global.asax.cs/App_Start/WebUiInitialise, registers
AddServiceLayer and migrates+seeds the database in a guarded scope on startup
- appsettings(.Development).json + launchSettings.json replace Web.config; HostTypes is
bound from AppSettings:HostType via IOptions and injected into _Layout
- all six controllers moved to Microsoft.AspNetCore.Mvc/IActionResult with [FromServices]
action injection (replaces DiModelBinder) and EfCore.GenericServices ICrudServices(Async)
- ValidationHelper rewritten over StatusGeneric.IStatusGeneric and the built-in JsonResult,
keeping the {"errorsDict":{...}} shape; TempData now holds plain html strings
- static assets moved to wwwroot/, SignalR 2 client dropped, bundles replaced by script/link tags
- InternalsInfo no longer uses the Windows-only PerformanceCounter so /Home/Internals
renders on Linux
Co-Authored-By: sameer.husain <sameer.husain@cognition.ai>
Converts Tests to an SDK-style net10.0 project (NUnit 4.6.1, NUnit3TestAdapter 6, Microsoft.NET.Test.Sdk 18.8.1, EF Core 10 SqlServer) and ports every fixture: - NUnit 2 classic asserts -> constraint model, [TestFixtureSetUp] -> [OneTimeSetUp], all fixtures made public so NUnit 4 discovers them - new Tests/Helpers/TestDbHelper builds DbContextOptions from the SampleWebAppDb environment variable (localhost SQL Server default) and replaces new SampleWebAppDb() - DbSnapShot uses Database.SqlQueryRaw over the still-named TagPosts join table - ModelStateTester uses ASP.NET Core IObjectModelValidator + ModelStateDictionary, JsonHelper uses System.Text.Json - SaveChangesWithChecking -> SaveChangesWithValidation, ISuccessOrErrors -> StatusGeneric - Autofac module tests replaced by Test11ServiceRegistration, which checks the AddDataLayer/AddServiceLayer registrations resolve from a scope Co-Authored-By: sameer.husain <sameer.husain@cognition.ai>
… and update README
🤖 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:
|
…C5/Autofac copy in the views
Phase 2 — verified end-to-end in a VMRan the migrated app on this branch (.NET SDK 10.0.301, EF Core 10, The two hand-rewritten paths, which is where a re-platform like this actually breaks1. Duplicate tag slug. EF Core has no 2. Posts CRUD — drop-down and many-to-many round-tripCreated a post picking a blogger from the drop-down (which contained a blogger created moments earlier, so it is built from live data) and ctrl-clicking two tags; the row shows exactly those tags. Reopening Edit shows the saved many-to-many pre-selected, so the Results per flow
Persistence was verified by navigating away and back: tags/posts returned to their seeded counts with no leftovers, while an intentionally-retained edited blogger survived. Coverage is the golden paths, not exhaustive regression — the Blogs |
Summary
Full re-platform of all five projects to
net10.0: EF6 → EF Core 10,GenericServices1.0.9 →EfCore.GenericServices10.0.0,System.Web.Mvc→ ASP.NET Core MVC, Autofac +DiModelBinder→ the built-in container +[FromServices],packages.config→ SDK-style projects.MIGRATION_NOTES.md(Phase 0) records the audit behind every decision here.Solution builds clean on the .NET 10 SDK (only
NU1903, see below), 45/45 tests pass against SQL Server, and a recorded browser pass over the Blogs/Posts/Tags CRUD flows in a VM found no failures — see the Phase 2 comment for the video and §12 of the notes.The two things that aren't mechanical
1.
EfCore.GenericServices10.0.0 is an API rewrite, not an upgrade. All thirteen EF6-era service interfaces collapse into two stateful scoped services, and DTOs lose their base class:ICrudServicescarries the status on itself (IsValid/Errors/Message), so controllers must inspect it immediately after the call rather than reading a returnedISuccessOrErrors.The old DTO hooks (
SetupSecondaryData,CreateDataFromDto,UpdateDataFromDto,ResetDto) have no equivalent, and they were doing real work for Posts: populating the blogger drop-down and the tag multi-select, validating the selections, and writing the chosen tags back. That logic now lives in a hand-writtenServiceLayer/PostServices/PostDtoService.cs(+PostDtoServiceAsync) behindIPostDtoService, which the Posts controllers use for create/edit while everything else stays generic.PerDtoConfigclasses stop the read-only UI properties mapping back on save.2. EF Core has no
ValidateEntityand does not validate at all on save. EF6 ran data annotations +IValidatableObjectinsideSaveChanges, and this app leans on that (Post title!/?rules, the "no sentence ending incow." rules,Tag.Sluguniqueness).SampleWebAppDbnow does it explicitly:Tag.Slugalso gets a real unique index; the pre-save query is what produces the friendly "The Slug on tag 'x' must be unique and is already being used." instead of a SQL constraint violation.Other notable points
AutoMapperis pinned to 14.0.0 and this raisesNU1903. 15.x throwsMethodAccessExceptioninsideEfCore.GenericServices'SetupDtosAndMappings.CreateConfigAndMapperat runtime (reproduced), and 13.x/14.x are covered by GHSA-rvv3-g6hj-g44x. No version is both patched and compatible; 14.0.0 is the newest that works. Revisit when upstream moves to AutoMapper 15.<authentication mode="None" />, noIdentityDbContext/ApplicationUser/account controller, and noHubsubclass orMapSignalRanywhere. The packages and the orphanedjquery.signalR-2.0.3.jsclient are removed rather than ported; §5/§6 of the notes document this.TagPostsjoin table with itsTag_TagId/Post_PostIdcolumns, which EF Core convention would otherwise have namedPostTag/PostsPostId.DataLayerInitialise.MigrateAndSeed(Database.Migrate()+ seed if empty) runs at startup fromProgram.cs;ResetBlogskeeps the Posts → Tags → Blogs delete order.appsettings.json— the app fails fast with a pointed message unless one is supplied; the local Docker SQL Server string lives inappsettings.Development.jsonand is documented in the README.<link>/<script>tags overwwwroot/;MvcHtmlStringinTempData→ raw strings rendered with@Html.Raw;SampleWebApp.slnregenerated (it was also missingBizLayer).Tests
Testsmoves to NUnit 4 /Microsoft.NET.Test.Sdk; 45 pass.Test10DiSimple.cswas deleted — its 11 tests only exercised Autofac's own container (Test01AutoFacSimple,Test04AutoFacLifeTimeScope, …), which is no longer a dependency.Test11AutoFacModules.cs→Test11ServiceRegistration.cs, same test names, now asserting theAddServiceLayerregistrations resolve per scope.Phase 2 verification
Ran on a VM against SQL Server 2022 in Docker and drove every CRUD flow through the browser. All assertions passed; the server log had zero
Unhandled exception/DbUpdateException/SqlException/HTTP/1.1 500over the whole run (64×200, 11×302, 22×304, no 4xx or 5xx). Video, screenshots and the per-flow table are in the Phase 2 comment andMIGRATION_NOTES.md§12. The run also surfaced stale "Entity Framework 6"/"MVC5"/Autofac copy in the views, fixed here; the longCodeViewessays still describe the EF6-era design and are left as follow-up.Link to Devin session: https://app.devin.ai/sessions/d5054a98ded8483289c0bfbebc691af2
Requested by: @sameerhusain81
Devin Review