Migration Assessment
Key Takeaways
  • Assessment is its own stage, not a side task you do during migration
  • Score five dimensions on a Red, Yellow, Green rubric
  • The UI layer is usually the longest part of a port, so weight it accordingly
  • Combine GitHub Copilot app modernization, Visual Studio code metrics, and dependency scanners
  • Use audit output to choose port, rewrite, or retire on evidence, not opinion

Who this is for: Engineering leaders, architects, and product owners scoping the modernization of a WPF, WinForms, Silverlight, UWP, or Xamarin application before committing budget.

Why Assess

Why Assess Before You Port

A port that skips assessment usually fails one of three ways. The team discovers a blocker on day 60 that should have surfaced on day 1. The budget overruns by two or three times because the original estimate was a guess. Or leadership cancels the project mid-flight because no one can defend the spend. None of these failures are about engineering skill. They are failures of scope.

Microsoft's own modernization guidance reflects this. The workflow is split into three explicit stages (assessment, planning, and execution), and the assessment stage produces a written report that lists breaking changes, API compatibility problems, and the upgrade scope before any code is touched. Treat this as the floor, not the ceiling. A defensible assessment also covers the UI layer, the third-party surface, and the business-critical paths that no automated tool measures.

The output of a good assessment is three things: a scoring sheet, a ranged effort estimate, and a one-page recommendation. That is what gets you funded.

Five Dimensions

The Five Dimensions of a Legacy .NET Audit

A complete audit covers five dimensions. Each one maps to a question your team can answer in a one-day workshop with the source code open.

DimensionQuestionWhy It Matters
Dependency healthHow many packages are unmaintained, end-of-life, or pinned to .NET Framework?Dead packages are the most common porting blocker
UI framework ageIs the UI on WPF, WinForms, Silverlight, UWP, or Xamarin.Forms?UI layer effort dominates total port cost
Third-party controlsHow many DevExpress, Telerik, Infragistics, or in-house controls are in use?Each one needs a replacement or wrapper
Test coverageWhat percentage of business logic is covered by automated tests?Tests are the only safety net during a port
OS/runtime constraintsDoes the app depend on Windows-only APIs, COM, P/Invoke, or specific .NET Framework versions?Constraints decide which targets are even possible

The dimensions are deliberately weighted toward the UI layer, because the UI is where most ports run long. Microsoft's standard tooling output focuses on dependencies and APIs and does not measure custom controls, so you need to count those by hand. A grep across .xaml files for <local: and <custom: tags is enough to start.

Rubric

A Red, Yellow, Green Scoring Rubric

DimensionGreen (low risk)Yellow (manageable)Red (blocker)
Dependency health90%+ packages have a current .NET 9 build60-89% currentBelow 60% or any critical dead package
UI framework ageWPF or UWP on a recent SDKWinForms with mostly stock controlsSilverlight, Xamarin.Forms, or heavily customized WinForms
Third-party controlsUnder 10 controls, all with current replacements10-30 controls, partial replacementsOver 30 controls, or any with no replacement path
Test coverage60%+ on business logic30-59%Under 30%
OS/runtime constraintsPure managed code, .NET 6+Some Windows-only APIs, isolatableCOM, P/Invoke, or .NET Framework 3.5 dependencies

Score each row, count the colors, and write the result on a single page. Three or more Reds means port is probably the wrong answer. Two Reds means scope carefully. One Red is a normal port that needs a clear mitigation plan.

Worked Example

Worked Example: A 180k LOC WPF LOB App

Consider a hypothetical inventory management app: 180,000 lines of code, six years old, WPF on .NET Framework 4.8, 22 third-party Telerik controls, 14 in-house custom controls, 24% unit test coverage, three Windows-only COM dependencies for a label printer SDK.

DimensionSample ValueBand
Dependency health71% of NuGet packages have .NET 9 buildsYellow
UI framework ageWPF on a current SDKGreen
Third-party controls36 controls total, 5 with no replacementRed
Test coverage24%Red
OS/runtime constraints3 COM bindings, isolatable behind an interfaceYellow

This app earns two Reds and two Yellows. That is a port that needs scope discipline, not a rewrite. The UI is the long pole, so the team should plan for a gradual screen-by-screen migration and budget for replacing the five blocker controls.

A useful first measurement is the ratio of UI code to business logic:

C#
// Quick LOC ratio for an audit workshop
var uiLoc = Directory
    .EnumerateFiles("src", "*.xaml.cs", SearchOption.AllDirectories)
    .Sum(f => File.ReadAllLines(f).Length);

var coreLoc = Directory
    .EnumerateFiles("src", "*.cs", SearchOption.AllDirectories)
    .Where(f => !f.EndsWith(".xaml.cs"))
    .Sum(f => File.ReadAllLines(f).Length);

Console.WriteLine($"UI to core ratio: {(double)uiLoc / coreLoc:F2}");

For this hypothetical app the ratio comes back at 1.4, meaning the UI surface is bigger than the business logic. That is the single most important number to bring to the budget meeting.

Effort Range Estimate
9 to 14 engineer-months for a phased port to .NET 9 with a cross-platform UI target
2026 Tooling

2026 Tooling Map for Legacy .NET Assessment

ToolWhat It MeasuresNotes
GitHub Copilot app modernizationBreaking changes, API compatibility, upgrade scopeDefault in Visual Studio 2026; replaces the standalone Upgrade Assistant
.NET Upgrade Assistant analyzeProject-level incompatibility reportDeprecated, but still callable from CLI for batch runs
Visual Studio code metricsMaintainability index, cyclomatic complexity, class coupling, LOCRuns from the IDE or the command line
Roslyn analyzersSource-level diagnostics for risky patternsUseful as a CI gate after the audit
Dependency scannersNuGet target framework support, version driftNuGet Package Explorer, dotnet-outdated

A typical batch invocation of the legacy Upgrade Assistant:

Terminal
# Assess a solution and write an HTML report you can share
upgrade-assistant analyze ./LegacyApp.sln --format html --report ./out

For new work in 2026, lead with the GitHub Copilot app modernization agent inside Visual Studio, paired with the productivity tooling in Uno Platform Studio once you choose a cross-platform target. The agent generates an assessment.md file during its first stage, which you can paste straight into the audit deliverable.

Decision Tree

Port, Rewrite, or Retire: A Decision Tree

Once the rubric is filled in, walk these five questions in order.

  1. Does the app still serve a clear business purpose for the next three years? If no, retire.
  2. Do you have three or more Reds in the rubric? If yes, rewrite is the safer bet.
  3. Is the UI-to-business-logic ratio above 2.0 with a Red on third-party controls? If yes, rewrite the UI but keep the core.
  4. Are there one or two Reds with a clear mitigation? If yes, port with a phased plan.
  5. Are all dimensions Yellow or Green? If yes, port with confidence and a normal contingency.

When Porting Is Not the Right Fit

Port-first sounds prudent, but three patterns turn it into a money pit:

  • Less than 20% UI reuse. If the visual design is being redone anyway, a port adds cost without value.
  • Business rules trapped in code-behind. When XAML code-behind contains logic with no isolation layer, untangling it costs more than rewriting against a clean architecture.
  • Sunset within 18 months. If the application is on a known retirement path, even a successful port loses money.

If the audit recommends a phased port, the Uno Islands feature lets your team host new cross-platform UI inside the existing WPF shell, so you can ship value before the full port lands.

FAQ

FAQ

What is a legacy .NET codebase assessment?

A pre-migration audit that scores dependency health, UI framework age, third-party control usage, test coverage, and OS/runtime constraints. The output is a Red/Yellow/Green scoring sheet, a ranged effort estimate, and a written port, rewrite, or retire recommendation.

How long does a legacy .NET assessment take?

A focused assessment for a single application usually takes between one and two weeks of elapsed time, with three to five days of active engineering effort. Larger portfolios with twenty or more applications can take four to six weeks because each app needs its own scoring sheet.

Is the .NET Upgrade Assistant still supported in 2026?

The standalone .NET Upgrade Assistant is deprecated and has been replaced by the GitHub Copilot app modernization agent inside Visual Studio 2026 and recent Visual Studio 2022 builds. The legacy CLI is still available behind a settings flag for batch runs, and its analyze mode is useful for producing shareable HTML reports during assessment workshops.

How do I decide between port, rewrite, and retire?

Use the rubric output. Three or more Reds means rewrite. Two Reds means port with strict scope discipline. One or zero Reds means a normal port. Retire wins if the application has no clear three-year business purpose, regardless of the technical score.

Conclusion

Conclusion

A legacy .NET codebase assessment is the cheapest insurance you can buy on a modernization project. Five dimensions, three colors per dimension, one worked example, and a five-question decision tree are enough to turn a guess into a defensible plan. Run the rubric before you negotiate the budget, not after.

When the audit points to a phased port, Uno Platform is one of several modernization targets worth a look, especially when web reach matters alongside Windows. A single .NET codebase can run on Windows, macOS, Linux, iOS, Android, and the browser.