A .NET consultancy can leave a small engineering team with more ownership risk than it removes, especially when its preferred library becomes a dependency the team cannot confidently upgrade or replace. For a 15–30-person organisation, I would evaluate the vendor and its proposed stack together. A convincing demo is insufficient; the deciding evidence is whether your engineers can operate, change and remove the solution after the vendor leaves.
The vendor should prove its framework choice in your repository
Do not let a consultant select a framework during a sales workshop and validate it after the contract is signed. The recommendation affects your team’s future work, so the evaluation should produce code your team can inspect before procurement is settled. In-House .NET Developers vs .NET Consultants: Key Decision Guide usefully separates staffing models, but that distinction cannot establish who will understand an unfamiliar dependency six months after handoff.
Give each shortlisted vendor the same narrow task: add one production-shaped feature to a disposable branch of an existing ASP.NET Core service. Choose a feature with an HTTP endpoint, a PostgreSQL write, a read path and a failed-request case, because that combination exposes more integration decisions than a standalone benchmark. Require a pull request rather than a presentation. Its description should name the proposed packages, the alternatives rejected and the files your team would edit to replace the choice.
Make the boundary explicit. A candidate proposing EF Core 10 should show where query expressions, migrations and database-specific behavior live. A candidate proposing Dapper should show where SQL, mapping and schema changes live. Both should implement the same behavior against the same PostgreSQL 17 fixture, or the comparison will reward differences in the test setup rather than differences in approach. Keep authentication, hosting and surrounding application code unchanged unless the candidate can explain why a change is necessary.
The trial needs a reproducible starting point. The following CLI sequence runs with the .NET 10 SDK and creates a small dependency baseline; replace the SQLite package with the proposed package when preparing the actual vendor branch. It proves restoration and compilation, not that the library is suitable:
dotnet new web -n VendorProbe -f net10.0 cd VendorProbe dotnet add package Microsoft.EntityFrameworkCore.Sqlite --version 10.0.0 dotnet restore --use-lock-file dotnet restore --locked-mode dotnet build -c Release --no-restore dotnet list package --include-transitive --vulnerable dotnet publish -c Release --no-restore -o out
Ask the vendor to commit packages.lock.json and run locked-mode restore in CI, because a reproducible dependency graph makes later changes visible to reviewers. The vulnerability command is a useful screening step, not a security verdict, because its result depends on the advisories available when it runs. Microsoft’s published support policy gives .NET 10 LTS a three-year support period; ask the vendor to show that its chosen packages and upgrade plan fit within that window rather than assuming “current” means maintainable.
A library wins only when your engineers can explain its failure modes
The second test belongs to your engineers, not the vendor. Have a developer who did not attend the sales calls review the pull request and make one change without coaching: add a field, alter a query or handle a transient database failure. An adjustable allowance of two engineer-days is enough for a focused trial; if the task cannot be scoped that tightly, reduce the feature rather than accepting a vague assessment. Record where the developer needed vendor help, because those requests are early evidence of a continuing support dependency.
Inspect the operational path as closely as the happy path. Ask how the code handles a PostgreSQL timeout, cancellation through CancellationToken, a retry after an uncertain write and a failed migration. Polly v8 may help express retry policy, but a retry around a non-idempotent operation can duplicate effects, so the vendor must identify which operations are safe to retry and why. OpenTelemetry traces should carry a request across the ASP.NET Core endpoint and database call, while Prometheus metrics should let your team distinguish response-time changes from error-rate changes. Names on a diagram do not count; request a trace and a dashboard query from the running trial.
Agree on measurements before seeing results. For example, use an adjustable workload of 10,000 representative rows and a concurrency setting of 20, then record p95 latency, error rate and database CPU for the baseline and candidate. Those are trial settings to tune to your service, not universal targets. If a pilot reports a measured p95 of 18 ms against a measured 16 ms baseline, the useful question is whether the additional 2 ms buys simpler changes or safer operations; the figures alone cannot answer it because the workload may not resemble production. k6 can drive the same HTTP script for both versions, while PostgreSQL EXPLAIN (ANALYZE, BUFFERS) can reveal whether an apparent library difference is actually a different query plan.
I would not award the contract to the lowest-latency microbenchmark, because it omits the migration, diagnosis and modification work that a small team must perform repeatedly. BenchmarkDotNet is useful for an isolated hot path, but it should support, not replace, a service-level trial. Require the vendor to explain any benchmark result that disagrees with the HTTP test; that discrepancy often points to connection handling, serialization or SQL rather than the library itself.
EF Core 10 and Dapper impose different ownership costs
An explicit comparison prevents “our consultants prefer it” from becoming the architecture decision. EF Core 10 wins when the feature contains changing relationships and ordinary application writes, because its model and migration tooling can keep those changes together. Its cost is maintaining mappings, reviewing generated SQL and knowing when tracking or query translation works against a particular access pattern. Dapper 2.x wins when a small set of stable, query-heavy endpoints benefits from SQL that your team already reviews and tunes directly. Its cost is owning the SQL, mapping conventions and schema-change discipline that EF Core otherwise helps organise. Neither option removes the need to inspect PostgreSQL plans or test failure behavior.
Make the vendor price those costs in engineering terms rather than adjectives. Request the pull request, a proposed schema-change procedure and a written account of how the next developer would add a filter to the endpoint. Ask your reviewer to perform that filter change in both candidate implementations. Time spent locating the right files and tests is useful evidence, provided both candidates start from equally familiar code; it is not a universal productivity benchmark. Keep the actual observations with the procurement decision so that a later team can see why the choice was made.
Apply the same comparison to a vendor’s other proposed dependencies. If it wants Serilog instead of the logging facilities already in your service, ask what concrete failure or investigation the change fixes. If it introduces a PostgreSQL client configuration through Npgsql, ask which settings differ from your existing deployment and how they will be tested. A new abstraction has a real cost because your team must debug both the application and the abstraction when behavior diverges. The vendor can justify that cost with a demonstrated need; a framework’s popularity is not evidence that your service has that need.
Exit evidence matters more than a polished handoff meeting
A vendor may complete the trial and still be a poor fit if only its employees can maintain the result. Make exit conditions part of the evaluation: your organisation owns the repository and CI configuration, can restore dependencies without private vendor infrastructure and can deploy from documented credentials it controls. Ask for an SPDX 2.3 or CycloneDX 1.6 software bill of materials, because it gives your team a concrete package inventory to review when an advisory appears. Ask who updates that inventory and how upgrades are proposed; an artifact that immediately goes stale offers little protection.
Hire NET Developers or NET Consultant Key Decision Guide frames the hiring choice, but I would make the contract contingent on a maintainer exercise because either staffing route can conceal dependence on one specialist. Have the vendor step away while two of your engineers perform a fresh setup, run the tests and investigate an intentionally failing request. Set a trial-specific ceiling of four hours to reach a credible diagnosis, then note exactly where documentation or access blocked them. That ceiling is a value to tune for the complexity of your service, not a promise that every incident can be resolved in an afternoon.
Put acceptance criteria in the statement of work: a merged pull request, passing CI, a dependency inventory, an upgrade path, an operational runbook and a recorded maintainer exercise. Specify how unresolved findings affect acceptance, because “knowledge transfer completed” says nothing about whether knowledge was retained. If the vendor cannot explain how to remove its chosen framework without rewriting unrelated endpoints, ask for a narrower integration boundary before signing. That request is reasonable for a small team because replacing one dependency should not require rediscovering the whole application.
The first procurement step is a branch, not a meeting
Pick one service and prepare a disposable branch with a representative endpoint, a PostgreSQL fixture and a failing-case test. Send that same branch and acceptance criteria to each shortlisted vendor. Assign one engineer to review the resulting pull requests and another to attempt an unassisted change. Their recorded obstacles will tell you more about the proposed relationship than a confident architecture presentation.



