Moving from .NET Framework to .NET 8 Without Burning the Place Down
For many engineering teams across Sydney, Melbourne and Brisbane, the .NET Framework applications that quietly run the back office of a large Australian bank, a logistics provider or a state government agency are still ticking over on the same code that was written when Windows Server 2008 felt modern. They work, the depreciation schedule is forgiving, and nobody wants to be the person who breaks payroll. The trouble is that "still works" is a shrinking asset. .NET Framework is in maintenance mode, security fixes are slowing to a trickle, and every quarter that passes widens the gap between the skills graduates bring out of university and the stack your team actually maintains. Migrating to .NET 8 is less about chasing the new and more about buying back optionality.
This guide walks through a practical migration path that keeps the lights on while you move. It is built around the .NET Upgrade Assistant, the package compatibility tooling, and a few habits picked up from teams who have already done the jump — including some who learnt the hard way so you do not have to. The aim is to reach .NET 8 with confidence, ship it behind a feature flag, and roll forward rather than rebuild from the foundations up.
Why Australian Teams Are Making the Jump Now
Three forces are converging on Australian engineering leaders in 2025. The first is regulatory. The Privacy Act 1988 and its Notifiable Data Breaches scheme mean a missed security patch on an internet-facing legacy service is a board-level conversation. APRA's CPS 234 obligations for banks and insurers add another layer, and several large institutions including NAB and Westpac have publicly committed to modernising legacy estates as part of their cyber uplift programmes. Staying current on a supported runtime is no longer a nice-to-have when your incident response plan has to account for it. The second force is cost. .NET 8 brings dynamic PGO, an improved generational GC and native ahead-of-time compilation for specific workloads. For applications hosted in Azure Australia East or AWS ap-southeast-2, the performance delta often shows up as a smaller bill at the end of the month, which makes the business case far easier to write than a vague "modernisation" memo.
The third force is people. New graduates from UNSW, Monash, RMIT and UQ learn the unified .NET platform; they do not learn Web Forms. If your hiring pipeline runs through Seek or LinkedIn Sydney, you have probably already noticed the drop-off in candidates willing to work on .NET Framework 4.x in preference to something more current. .NET 8 is an LTS release with three years of support, which lines up neatly with how Australian CIOs plan their budgets — annual, with a three-year horizon.
Audit Before You Touch a Single Line of Code
The single biggest mistake teams make is firing up the Upgrade Assistant before they have a clear picture of what they actually own. Start with an honest inventory. Open every solution in Visual Studio, list the target frameworks, and produce a spreadsheet of project, target framework and key dependencies. The .NET Upgrade Assistant can do this for you with its analyse command, but a quick pass with grep across your repositories for TargetFramework, AssemblyLoadContext and System.Web will tell you most of what you need to know.
Catalogue your NuGet packages. Most of the popular ones — Newtonsoft.Json, Serilog, AutoMapper, Dapper, NUnit, xUnit, Moq — have .NET 8 equivalents that drop in cleanly. The trouble usually sits with the long tail: an internal logging library last touched in 2017, a charting component that depends on System.Drawing, or a third-party SDK that still targets .NET Standard 1.6. For each of these you have three options: upgrade to a maintained version, find a .NET 8 alternative, or isolate the offending code behind an interface and live with it for now. Decide which strategy applies before you start the migration, not halfway through.
A practical tip for distributed teams: if your engineering is split between AEST and IST or PHT — a common pattern for Australian teams partnering with consultancies in Hyderabad or Manila — write the upgrade plan down in the repo's wiki. The handover between timezones is where intent gets lost, and you do not want the offshore team picking up a half-migrated solution with no context.
Run the Upgrade Assistant and Tidy Up the Fallout
The .NET Upgrade Assistant is a useful but blunt tool. Install it with dotnet tool install -g upgrade-assistant, point it at your solution file, and step through the wizard. It will rewrite your csproj files into the SDK style, update TargetFramework to net8.0, and bump most of your package references. Expect it to leave a mess behind, particularly around packages.config projects, binding redirects, and anything that references System.Web.
Once the assistant has finished, do not panic at the red wave in your IDE. Compile errors come in clusters. Knock them over in passes: target framework mismatches first, then missing APIs, then configuration. WCF services are a special case — migrate them to CoreWCF or replace them with gRPC or a REST shim, because WCF hosting is not supported on .NET 8 and the workarounds are worse than the rewrite. System.Drawing is another trap: replace it with ImageSharp or SkiaSharp rather than trying to coax GDI+ across the boundary. Entity Framework 6 still runs on .NET 8 but it is effectively unmaintained, so treat it as a migration project of its own. App.config transformations still apply, but the syntax inside SDK-style projects is different enough that you should read the docs before trusting your release pipeline.
Resist the temptation to refactor architecture during the migration. Keep the changes mechanical. You can rewrite the data access layer once you are on .NET 8 and the rest of the team has muscle memory for the new shape.
Modernise Configuration, Hosting and Platform Touchpoints
This is where the migration stops being a find-and-replace exercise and starts being a real piece of engineering. web.config does not disappear on .NET 8 — it is still read at runtime — but the modern approach is appsettings.json, environment variables and the IOptions pattern. Migrate deliberately: pull each section across, decide whether it belongs in appsettings, Key Vault or environment variables, and write down where it lives. Australian teams that integrate with the ATO's Standard Business Reporting APIs, MyGovID, or the Australian Digital Identity framework should pay particular attention to TLS version, certificate handling and signed payload libraries — these have moved around between runtimes and a quiet break here will fail integration testing in production in the most embarrassing way.
On the hosting side, IIS still works for Windows deployments and is a sensible default if your operations team has deep IIS knowledge. But .NET 8 runs brilliantly on Linux under Kestrel, which is worth considering if you are moving workloads to AKS in Sydney or to an EKS cluster in ap-southeast-2. Container support is first-class, images are smaller than they used to be, and the cold-start story on Azure Container Apps is competitive. Logging should move to Microsoft.Extensions.Logging with a structured sink such as Serilog or OpenTelemetry — anything that still calls Trace.WriteLine is a code smell worth chasing down during the migration.
Validate, Ship and Watch
Your existing test suite is your safety net. xUnit, NUnit and MSTest all run on .NET 8 with minimal fuss. Update the target frameworks on the test projects, fix any reflection-based assertions that broke under trimming, and run the full suite locally before you touch CI. Pipeline-wise, GitHub Actions and Azure DevOps both have first-class .NET 8 templates — use them rather than copying your old YAML across and hoping for the best.
For the actual rollout, do not flip the switch. Run the migrated service side-by-side with the legacy one and route a small percentage of traffic through it using a feature flag or path-based routing in Azure Application Gateway. Smoke test against real Australian integrations before you commit: Tyro or BPoint for payments, Australia Post for shipping, the ATO's STS for identity. These systems are unforgiving and a half-broken integration is exactly the kind of thing that ends up on the evening news.
Once it is live, watch it. Application Insights, Seq or your existing observability stack should give you startup time, request duration and memory usage comparisons against the legacy service. If you see a regression in cold-start on Azure, you almost certainly have an unoptimised DI container or a blocking call in your startup pipeline. Both are fixable, and now you have a modern runtime to fix them with.
If you are still on the fence, start with a single small service. Pick something internal, low-risk and owned by a team that enjoys a challenge. Get it across, write up what you learnt, and share it with the rest of the engineering organisation. The .NET community in Australia is small enough that you will probably bump into someone from a Sydney or Melbourne .NET meetup at your next conference who has already done the same migration — ask them what bit them, and you will save yourself a week. The official .NET migration docs, the dotnet/upgrade-assistant GitHub repository, and the .NET 8 release notes are the best starting points. .NET 8 is a steady, well-supported target, and the migration is far less dramatic than the stories you have heard.