Treat route ownership as an acceptance contract: the right application must handle each method, role, and fallback case before the migration slice ships.
The problem: correct content from the wrong application
Microsoft's incremental migration guidance puts an ASP.NET Core application in front of the existing ASP.NET Framework application. Local Core routes take precedence; unmatched requests fall through to the legacy application through YARP. That is useful for moving one capability at a time, but it makes route matching part of the release contract.
An AI-generated controller can be functionally plausible and still own too much. A broad template, a changed constraint, or an added HTTP verb may intercept a legacy export, authorization flow, or write operation. A test that checks only for status 200 can pass even though rollback, authentication, or side-effect ownership has changed.
Write the ownership table before generating code
Define the first slice by method, route, role, and side effect. For a read-only order-history migration, keep the write path explicitly legacy. Include nearby routes that must not move; these negative boundaries are what catch an over-broad route.
Give the coding agent this table, the allowed projects, and the existing authentication decision. Ask it to report any route it cannot classify instead of inventing a destination.
Slice MIG-ORDERS-READ GET /orders/42 authorized customer -> Core, read only GET /orders/42 other tenant -> Core, denied POST /orders/42 authorized customer -> Legacy, one write GET /orders/export authorized customer -> Legacy GET /not-a-real-route any -> Legacy, then 404 Do not broaden route templates, migrate writes, change authentication, or remove the YARP fallback. Return every unclassified route as a blocker.
Test the composed system, not only the new controller
ASP.NET Core integration tests can bootstrap the new application with WebApplicationFactory, which is useful for controller and middleware behavior. It does not by itself prove the deployed boundary between two applications. Add an acceptance suite against the composed Core-plus-Framework environment through the same public origin used by clients.
In that controlled environment, have each application emit an app-owner marker in the response or structured test log. Keep the marker non-sensitive and do not make production behavior depend on it. Assert owner, status, redirect target, authorization result, and any permitted state change for every row. For browser workflows, use Playwright through the proxy; use direct HTTP checks for routes with no meaningful UI.
Use a falsifiable route-capture check
Run two disposable mutations. First, widen the new route to capture /orders/export. The ownership suite must fail because the export moved from Legacy to Core, even if both return a successful page. Second, remove the new GET endpoint. The suite must fail because /orders/42 fell back to Legacy, even if the legacy response looks equivalent.
Restore the intended routes and require the complete table to pass. Record the commit, route table, application markers, and results. These are acceptance steps to execute in the customer's environment, not results claimed by this article.
- The unauthorized and cross-tenant cases remain denied and disclose no order data.
- The POST path reaches only the legacy application and performs exactly one persisted write.
- The legacy export still reaches the legacy application.
- An unknown URL keeps the agreed fallback and 404 behavior.
- A documented switch can return the migrated GET route to the legacy owner without a database reversal.
Buy a smaller modernization decision
Use the agent work kit to turn the table into a bounded implementation brief, then use the incremental-modernization playbook to include authentication, state compatibility, rollout signals, and rollback. This keeps the first decision about one capability rather than an estimate for rewriting the whole application.
For teams that need dedicated delivery capacity, the Mottobits offshore engineering pod is $8,000 per month for one dedicated senior developer, one dedicated QA automation engineer, and Adnan's technical guidance. Capacity, overlap, start date, and leadership cadence are agreed in the statement of work; client-controlled devices, repositories, approved AI tools, licenses, and cloud usage remain separate.
Sources
- Microsoft: get started with incremental ASP.NET to ASP.NET Core migration
- Microsoft: remote app setup and YARP fallback
- Microsoft: ASP.NET Framework to ASP.NET Core authentication migration
- Microsoft: integration tests in ASP.NET Core
- Mottobits: create an agent work kit
- Mottobits: move one .NET capability at a time
- Mottobits: AI-assisted .NET modernization