I’ve just come off the back of migrating to NET5. Yup, attempting, you did read that right. So why am I writing this then?
Well there is practically nothing out there on this topic yet. At least I couldn’t find much. Every example that is online, is also hopelessly over-simplified and frankly about as much use as a chocolate teapot. They just aren’t real examples of a real out-in-the-wilds application with all the awkward bits and knarly solutions to hard problems included that can and often seep in.
Anything that complicates an application on it’s historical path to where it is now is a potential source of a problem when migrating.
In my particular situation I have a large complex loosely coupled WPF application. Based around Prism and using directory assembly enumeration at runtime. So certainly that is already more complex than any example you’ll find online. Honestly speaking, we can’t really hope for much more either as there are just too many variables involved in the process for them to create real world expamples. By definition they take years to arrive at.
My application also does a large amount of P/Invoke and integrates and distributes 3rd party unmanaged C++ DLLs for low level work. There are a few others for other features and generally “closer to the metal” than .NET to provide features or hardware compatibility. All of this adds to the deployment stories complexity.
Also, these projects and solutions files have been evolving since Visual Studio 2008. There is dross. Actually, before I say anything else, this is a key take-away. Do all you can to simplify what you have to migrate before you attempt to migrate. Address that technical debt or it’s just going to bring problems along for the ride. In my instance, I’ve decided to remodel the app structure away from directory enumeration. I’m not making use of it’s increased flexibility so really is just technical debt with zero net benefit.
So anyway, that paints a rough picture of the app. It’s not simple, or small.
Migrating to NET5
So I started the migration and to be fair, all things considered the migration tooling did a remarkably good job considering all the curve balls I was throwing at it.
I had to work through a few thousand errors and warning. I was having to go through each project file to fix settings and bits of configuration. Any files that you may have excluded from projects are automatically just added to the converted projects. That caused a good few hundred issues simple by having sucked every *.cs file back into the projects.
I know, I know. We shouldn’t be keeping things like this around in source control but people do and have done and it’s hardly a terrible practice to keep relevant things in repos. It’s potentially a huge issue for really large enterprise solutions being migrated. Not one migration doc I’ve read mentions things like this.
Some namespace changes and classes having moved around in NET5 was a source of some issues but to be honest dotnet restore was a godsend. Along with clearing down all the \bin \obj directories regularly through the process.
The Main Exe Project
This was the source of a lot of issues when migrating to NET5. No amount of config testing on my part ever got this project to build and run. There was quite a tussle between my app code and the framework generated code. Initially oscillating between having no static main method to having too many. It was an interesting dance that ultimately led to a point on the third day of my migration where I threw in the towel and rebuilt the entire project from the ground up. The common error was:
The target process exited without raising a CoreCLR started event. Ensure that the target process is configured to use .NET Core. This may be expected if the target process did not run on .NET Core. The program '[xxxxx] xxxxx.xxx' has exited with code -2147450726 (0x8000809a).
I tried an unknowable number of fixes to get this working. Even spooling up empty version of apps from templates to compare and contrast. Nothing got it working, hence the rebuild. Fortunately my exe is tiny so this wasn’t too much of an issue but for larger projects this could be a daunting task in itself if you run into a similar situation.
The libraries within the solution all migrated over pretty easily. Since there are a lot of differences in the way the projects are handled there was a lot of trimming in these projects to do. Many Compile and XAML page compile directives need to be removed. Once the targeting is right the various dotnet commands can help a lot to process the proejct files and dependencies.
The Real Trouble Started
The real trouble migrating to NET5 started around deployment. Like I explained above my app has a lot of 3rd party libs and some of them didn’t play nice, at all.
It seems that in Microsofts infinite wisdom them seem to expect an extraordinarily flat deployment structure on disk. Basically, NET5 Desktop apps don’t support directory probing. BOOM. On reflection, the game was over for me at that point but I persisted.
There is discussion on GitHub about various workaround involving the xxx.deps.json files and the directory properties in the runtime.json files. It’s a config dance to kid the runtime into thinking your directories are NuGet repositories. There is another hack which involves MANUALLY HANDLING ASSEMBLY RESOLUTION.
It was at that point when I was looking at how best to integrate manually handling assembly resolution that I ran out of steam with it all. Day 4.
I’m moving towards a v1.0.0 release of this app and I’m now writing code to manually handle assembly loading to get around a missing deployment framework features. I just stopped and started debating the whole thing with myself. I came to the conclusion that I’m not comfortable with that. Yes the code is easy to write and it’s not even complex. I just see it as a bit of a regression.
I decided to commit what I had to a branch and get back to being productive on real code bringing new features to my users. At least for now …
Migrating to NET5 Take Aways
So the conclusions and tips for migrating to NET5 at the moment looks like;
- Simplify your app code as much as possible before migrating
- If your app is as loosely coupled as mine is, consider backtracking on that if you can before running any migration tools
- .NET Core 3 compatibility analyzers are less of an issue for .NET5. I even have all my Management Instrumentation stuff working with minimal changes
- Accept some projects may need rebuilding from the ground up
- Tidy up your source files to remove any loose files not linked to active projects
- WPF projects using OS Dialogs need <UseWindowsForms>true</UseWindowsForms> in their project files
- Check for issues like net5.0-windows7.0 being used
- Add in SupportedOS attributes to a root shared AssemblyInfo.cs can get rid of piles of error reports with one line of code
- Switch any PostBuild Events to use relative paths
- If post/pre build events are failing, copy the commands test out, save the project, paste it back in … yes it works.
All in all I think the main conclusion I’ve come to is that I need to wait a version or two. It’s not like NET 4.8 is going away any time soon.
My code and application seem fine in terms of compilation, I didn’t get it running but that is partly my inexperience with NET Core for Desktop coming into play at this stage. All I’ve used NET Core for so far is web based solutions for clients. So there is definitely a gap there in my experience and knowledge to be addressed.
I think us developers also have to accept that it is a drastically different deployment model. So expecting to coast through to NET5 could be a little optimistic, depending on your solution complexity. Despite what Microsoft and various control library authoring companies may like to convince us of the simplicity of this task. The real world, where most of us write code, is rarely that simple.
I also think I’m going to wait until Visual Studio itself hits NET5. With the issues I’ve had, I can’t help but think a product as complex as VS would also have issues. Issues they’re going to have to solve to get Visual Studio migrating to NET5. That’s when it’s going to hit maturity I think and when I’m going to revisit this.
I’ve accepted that when I do, I’m also going to rebuild each and every project from the ground up. Seeing as they are now 13 year old vintage it’s time to bite that bullet.
Thanks for reading and I hope your experience is a lot less bumpy.