A .NET architecture decision is often scoped as a framework evaluation followed by an implementation estimate. That sequence hides the expensive work: changing course, connecting the framework to an existing product, and proving who owns failures. I would fund a small exit drill before approving either a license or a build plan, because a successful demo says little about the cost of the next change.
A pilot without an exit drill makes the cheapest option look safer than it is
Teams often ask whether a framework can serve the first release, because that is the question a short pilot can answer. Can a 20-Person Team Trust This Architecture Framework? makes trust the question; a product manager should also price the work of leaving, because dependencies can remain long after the pilot team moves on. A framework that generates an ASP.NET Core endpoint quickly may still make a routine schema change, authentication change, or package upgrade expensive.
Scope the pilot around one reversible product workflow: accept a request, authorize it, write to PostgreSQL, emit a trace, and return an error the client can act on. Then replace the framework-dependent portion with ordinary ASP.NET Core code. The replacement need not be production-ready; it must reveal which contracts, data mappings, and tests would have to move. Include the time spent finding framework-specific conventions, because that discovery is part of a future exit.
For a planning example, assume two engineers spend two weeks at 40 hours per week and an internal loaded rate of $100 per hour. That is a $16,000 pilot assumption, not a vendor quote or a measured outcome. If the team allocates all that time to the happy path, the product manager has bought a demonstration but no evidence about switching cost. Reserve the final three days for removing one dependency or upgrading one major package version; the amount of code that must change becomes an input to the delivery estimate.
I would not approve a framework on the strength of a sample application, because samples rarely include the product’s identity provider, migrations, or existing API clients. Require the team to record which parts of the workflow depend on vendor types and which speak stable interfaces such as HTTP and OpenAPI 3.1. This is not a demand for zero dependency; it is a way to put a price on the dependency the team is choosing.
A vendor quote does not pay for the boundary your product still owns
The common scoping error is to treat a licensed framework or delivery partner as a substitute for product-side integration work. Build .NET In-House or Buy It How Much Can You Cut Corners? frames a choice worth examining, but neither route removes the need to define data ownership, authorization rules, and release acceptance. A supplier can implement those rules only after someone on the product team decides what they mean.
Compare two options for a bounded workflow. A licensed framework extension wins when its supported extension points match the workflow and the supplier will fix defects within an agreed response window; its costs are the license, integration, contract tests, and a possible exit. A custom ASP.NET Core module wins when the workflow changes frequently or needs behavior the extension points cannot express; its costs are engineering time, maintenance, and operational ownership. The first option is not automatically faster, because adapting a mismatched authorization model can consume the time saved on scaffolding. The second is not automatically cheaper, because the team must maintain the code after launch.
Turn those costs into named deliverables. For Microsoft Entra ID sign-in through OpenID Connect, specify who maps claims to product roles and who tests expired tokens. For an EF Core migration against PostgreSQL 16, specify who checks a rollback on a copy of representative data. For an API described with OpenAPI 3.1, specify who approves a breaking change and updates clients. Each unanswered owner question is work, not an implementation detail that will resolve itself.
Suppose a supplier estimates four weeks for an extension. As a separate budget allowance to validate, assign one product engineer half-time during those four weeks: at 20 hours per week and an assumed loaded rate of $120 per hour, that adds $9,600 before procurement or testing. The figure is a worksheet input, not a claim about typical vendor projects. Leaving it out makes the external option appear cheaper by charging necessary decisions to another team’s capacity.
Counting endpoints conceals the changes that consume engineering time
An estimate of “six endpoints” sounds concrete but says little about effort, because one endpoint may cross authorization, data, client compatibility, and observability boundaries. Count change paths instead: the distinct places a likely product change must be specified, implemented, tested, deployed, and supported. A new customer field, for example, may touch an EF Core model, a migration, an OpenAPI contract, a serializer, a client, and a backfill. If the framework duplicates that field in configuration or generated code, include those edits too.
Ask the team to walk through three plausible changes before committing the release scope: add a field, tighten a permission, and change an external response. For each, request a list of repositories, owners, environments, and approval points. Use an initial planning limit of five touched components per change path, then tune it after the pilot; the threshold is a prompt to investigate coupling, not an architectural law. If a supposedly small change crosses eight components, estimate it from that path rather than from the endpoint count.
Dependency discovery belongs in this estimate because a restore or upgrade can expose work that is invisible in a feature demo. With the .NET 8 SDK installed and NuGet reachable, this small drill creates a project, locks its dependencies, and shows the resolved package graph:
dotnet new web -n ExitDrill --framework net8.0 cd ExitDrill dotnet add package Npgsql --version 8.0.5 dotnet restore --use-lock-file dotnet restore --locked-mode dotnet list package --include-transitive dotnet build --no-restore grep -n '"Npgsql"' packages.lock.json
The commands do not certify a framework, because a clean build cannot prove that product behavior survives an upgrade. They establish a repeatable baseline: commit packages.lock.json, substitute the candidate’s NuGet package where appropriate, and repeat the locked restore in GitHub Actions. If the candidate cannot be upgraded without regenerating code or changing application contracts, put that work in the roadmap rather than treating it as routine maintenance.
Version choice also belongs in scope. Microsoft’s published support schedule places .NET 8 at the end of support in November 2026, so a new long-lived project starting near that date needs an explicit upgrade plan rather than an implicit promise to handle it later. Record the target runtime and the date of its next review in the product plan, because the migration will otherwise compete with features after the initial team has dispersed.
An acceptance gate is cheaper than discovering an owner during an incident
Teams sometimes postpone operational acceptance until after implementation, because monitoring and failure handling look like release tasks. That postponement distorts the estimate: the framework, supplier, and product team may each assume another party owns a timeout or bad deployment. Define the failure boundary while the workflow is still small. For every external call, name the timeout, retry policy, and owner of the final user-visible error; retries without a boundary can multiply load during an outage.
Make acceptance observable rather than adjectival. Use OpenTelemetry traces to follow a request across the application and its dependencies, and use Prometheus metrics to distinguish latency from error rate. A starting service-level objective to tune might be 99.5% successful requests over a rolling 28-day window, excluding only failures the team defines in advance. That number is a proposed product threshold, not a measured level of reliability. Pair it with a latency target drawn from the workflow’s actual user expectation; a fast health check is no evidence that the write path is fast.
Run one failure exercise before sign-off: stop PostgreSQL, send requests with k6, and check whether callers receive a bounded failure rather than hanging connections. Test the same behavior with xUnit at the application boundary, because a load-test result alone is hard to reproduce during a later code change. Record whether HTTP 503, HTTP 429, or another response is appropriate for each failure mode; those status codes carry different retry implications for clients.
Price the gate as planned work. In an illustrative release budget, two engineers spending three days at eight hours per day and $100 per hour cost $4,800. That is a budget estimate to replace with the team’s rate, not a measured saving from incidents. The product manager can now compare that line item with the exposure it controls: without an agreed failure test and owner, a production incident may require the team to diagnose both the defect and its responsibility before making a fix.
The first scope decision should expose the cost of changing course
At the next planning meeting, choose one real workflow and ask for two estimates: delivery with the proposed framework and removal of its framework-dependent portion. Give both estimates the same authentication, data, client, and failure requirements. If the team cannot name the owners or run the exit drill within the pilot, keep the purchase and launch dates provisional; the missing work has not disappeared simply because it lacks a ticket.


