Hacker News new | ask | show | jobs
by dundarious 1483 days ago
I worked on a (failed, explanation follows) project to trial port a large system from .NET Framework 4.6 or 4.8 to I think .NET Core 2.1 or 3.0. I was most annoyed at having to recreate project files, but it was quite straightforward and easy, even for us, where we had complications like numerous sub-projects, some generated code (luckily, I quickly found the correct arcane incantation embedded in some GitHub issue), etc. We also had to rewrite a C# API wrapper for a C library we used for reliable multicast, because our vendor had disappeared, and their wrapper was shipped as a Windows-only Framework-only DLL (and honestly, the code quality was relatively poor, with a lot of needless complexity in their wrapper). But we had already consciously chosen to only use sensible slices of that library’s functionality, so writing our own wrapper was quite trivial, even though I hadn’t used C#’s DllImport stuff before. It was easy to port the slice needed for most publishers first, before having to port the slice for receivers, etc.

All in all, I’d say the port for our large suite of server apps, with lots of different CPU/memory bound and network I/O bound apps, it was quite straightforward and easy.

What killed it in the end for us, was that our testing showed our CPU/memory bound apps ran 0.9x as fast on Linux .NET Core 3.0 vs. Windows .NET Framework 4.6/4.8 OR .NET Core 3.0, using near-identical hardware. The Linux port just wasn’t there yet, so we decided not to go through with any port to .NET Core for any part of our system, since Linux would have been the main benefit (we were using fancy network cards and stacks, and the Linux support for those was far more advanced and reliable compared to Windows, where multicast groups would spontaneously fail to be joined, etc.).

Another elephant in the room, is that GUI support on .NET Core was limited at the time, so we may not have been able to do a Big Bang for that reason also. We had a few WPF apps, and some Forms stuff, but I have no clue about what .NET Core support was/is for that stuff, as I rarely worked on GUI things (I would create a GUI as a necessary part of an experiment and hand it off to more experience people, or modify/simplify GUI logic as part of my evolution of our server stack, but that’s all).

So obviously YMMV and it seemingly does vary, but my experience on server apps that weren’t using lots of Windows/MS specific technologies (I’m not a fan of them generally), our porting was really quite easy. Still a failure though :-)

2 comments

The performance improvements between .NET Core (any version) and (just) .NET 5+ have been pretty astounding. I've seen some incredible micro-benchmarks where the same code running in .NET 5+ hugely outperforms anything running in a version <= 4 (both .NET Core and the old .NET Framework). Factor in what you can do in memory-bound code by rewriting it to use .NET 5+ things like Span<T> and stackalloc there's no question that at this point you should be able to get much better performance out of .NET 5+. If performance was your bottleneck in .NET Core, the latest .NET versions (6 [LTS] or 7 [Preview]) may be worth checking out.

GUI stuff is also what happened in .NET 5+. WinForms and WPF were both added to .NET 5. There's some porting that needs to happen and not all old WinForms/WPF code will be happy on .NET 5+. The biggest remaining "missing piece" from a GUI perspective is that a lot of old WinForms/WPF code used WCF for service code. I think porting WCF to use simpler REST services is easy enough and there's lots of people doing that with gRPC services in .NET 5+ too. There's also the Open Source CoreWCF project that is trying to hit compatibility with the most used bindings in WCF on top of .NET 5+.

The relevant part were our model calculations and it was already heavily optimized (no allocations, etc.), so none of the new library stuff would help at all. We just found that Linux .NET Core underperformed compared to Windows .NET anything (Framework or Core). Maybe our methodology was wrong, but we had a few people look at it, made the comparison in several ways, and generally tried to be quite thorough. We always found Linux (only .NET Core) had ~0.9x the performance of Windows (any .NET) — and we were a mostly Linux shop, running C/C++ apps, so our Linux build was appropriately tuned. Given .NET Core was relatively new at the time, and Framework still had some legs, we didn’t dig down as far as looking at IR or JIT output, because we could afford to wait. After all, one of the draws was to reduce problems due to using our fancy network cards+stack in Windows, so there was no point in adding complexity from a new Linux .NET runtime, including complexity from having to troubleshoot performance.

I’ve been saying “we”, but I left that job a couple years ago so I won’t be trying any new .NET versions myself :-)

One of the issues I ran into when I looked at porting to .net core 3 was the crypto library. They didn't implement all .net framework classes, the ones related to public/private keys in particular. Perhaps they do now. I don't know how many edge cases I will find like that.

On the recreating project files, I don't think you can copy-paste winform code like that, you need to recreate it using the UI, which is a pain. Also they had this weird concept that an assembly had to be set to be a "winform" or "wpf" assembly, you couldn't simply reference system.windows.forms, which basically prevented you from creating a helper winform assembly, and you certainly couldn't create an assembly that referenced both winforms and wpf DLLs. They perhaps also fixed that since.

In any case, it's not a complete rewrite to migrate to .net 6, but it is far far from a simple lift and shift.