.NET software development on MacOS, with Mono Framework
New software development projects are always fun and challenging. But for a particular project three years ago, the challenge became personal:
- The specific project’s tech stack was based on Microsoft’s mature and powerful .NET Framework v4.
- …While my own tech pack was (and still is) a Mac – which made it look incompatible with the project’s basics.
Continuing to work on my Mac was crucial, as I got used to (read: “dependent on”) its simplicity, performance, light weight, good taste etc. (Yup, Apple fanboi here).
As the two systems are pretty much incompatible, this started as an either/or issue. The initial research got me into a rabbit hole of heated debates and funny commercials from both sides, that seemed to make it clear that I would be a second-grade citizen in a Windows world.
But heat and laughs didn’t cut it. What did, was an independent, third-party solution. Here’s the whole story:
Setting up the stage
The .NET is a well-established software development framework, as it’s been on the market since the late-‘90s/early-2000s. It has two main versions:
- The .NET Framework (often referred to as ASP.NET) is an open-source framework, initially released in 2002, originally confined to Windows platform only.
- The .NET (initially called .NET Core) was released in 2016 as the modular, lighter, cross-platform alternative. It therefore works on Windows, Linux, MacOS.
They both run on the same runtime environment (CLR / Common Language Runtime), which is the equivalent of Java’s Virtual Machine (JRE). However, .NET and .NET Framework are not compatible.
In this specific case, for reasons beyond my choice, the project had to be built on the .NET Framework (the one not directly MacOS-compatible), so I had legit questions (and concerns).
But because the .NET Framework is so popular, there are software developers who (way before me) wanted to use it outside the Windows ecosystem. Not waiting for any official MS answer to their needs, in 2014 they started Mono – i.e., the third .NET version (also called: “the one that saved my day”).
So, what precisely is Mono? Here’s their own description: “Mono is an open-source implementation of Microsoft’s .NET Framework based on the ECMA standards for C# and the Common Language Runtime”.
If you read “open-source” and hear alarm bells, here’s a soother: Mono’s community is highly dedicated and professional, and the project is very well maintained (with the latest version 6.12. released in November 2020). Along the way, even Microsoft started sponsoring the project, with parts of it included in the current iterations of .NET (v5 and v6).
On the practical side, Mono’s installation is straightforward: just download the right installer here (Linux/MacOS/Windows/Docker).
I was surprised to discover that Mono was already installed (this happens to you too, right?). Apparently, I had it used for a different/minor reason: run a Windows .exe on Mac. Yes, Mono can do that, with a simple command line:
> mono myprogram.exe
(A note of caution: only C# desktop applications with the .exe extensions can work this way on MacOS.)
This time, however, I needed Mono for much more: develop a .NET project, using C#, together with colleagues using Windows machines, using the same code base. So, I just updated Mono to its latest version, then took care of the most important part: the IDE.
Regardless of whether you’re on Windows or Mac, there are two main choices, both of them good:
- Free: VisualStudio Community edition (the little brother of the classical Visual Studio Enterprise)
- Commercial: The JetBrains Rider (a little brother of IntelliJ, the most complete Java IDE on the market).
Once I’ve opened the project, my Mono version was instantly recognised:
Behind the scenes, for running the project locally, Mono offers the XPS (its own lightweight webserver). For Windows machines, that part is covered by the IIS Express, the lightweight version of IIS (Internet Information Server).
Limitations and workarounds
If it sounds smooth, it is because it was smooth. Still, I did have a plan B just in case things went south.
I installed a virtual Windows 10, running on the Mac under hardware virtualization. I knew that because virtualized, the performance of that system would be suboptimal. But if used for a short time and a limited set of actions, it should have been fine.
If you develop with .NET on a regular basis, I strongly recommend a Windows system for backup. Some of the most popular ways to do it are:
- Parallels Desktop, commercial
- VM Ware, commercial
- Virtual Box, free
- Azure, Amazon S3, commercial and on the Cloud
These options mean that I can always reach out to Windows, for the tasks that can’t be done on the Mac.
However, there are few drawbacks that I ran into:
1. I could not publish the project for development. It just doesn’t work on a Mac, so you will still need a “real” Windows system. But then, publishing directly from the local station is usually done during the project’s early stages. Later on, this task should be automated and delegated to a build server, on-premise, or on the cloud.
This is definitely not a critical issue – at least for me, as I had to publish the project from the virtual Windows I mentioned earlier.
2. Another operation that absolutely needed Windows was to run Entity Framework commands, such as adding migrations or updating the database. The “Code First” approach requires NuGet Package Manager Console, which isn’t available in Mono. But again, this is not something you would do on a daily basis, therefore not a deal-breaker.
3. A more serious drawback came from some third-party NuGet libraries not working on Mono. For me, this was the case with commercial HTML-to-PDF converters (used by our report generation service). I tried three libraries, none of which worked properly with Mono, so I eventually gave up tinkering. The project’s architecture (similar to microservice architecture) allowed me to isolate the respective service on the Windows machine, meaning I wasn’t actually blocked.
Bottom line: although I landed on some problems, workaround solutions were possible with minimal effort, so none of them ended blocking me from working on the project.
As of November 2020, Apple started transitioning its MacOS hardware from Intel CPUs to M1 – Apple’s own silicon, a version of ARM CPU. Although a “revolutionary” move, Apple reassured its customers that it will be a smooth one due to Rosetta 2 – a translation process that allows users to run apps that contain Intel’s x86_64 instructions on Apple silicon. However, when it comes to .NET, things will be different – at least for the next months (few years?).
I haven’t yet personally tried the M1, but I had a look at people who did:
- JetBrains (Khalid Abuhakmeh): .NET Development on Apple Silicon
- Alexander Ziskind: Apple M1 vs Intel Core i9 and .NET Performance – First Look
Right now, the only virtual Windows you can have on a M1 is an ARM Windows that Microsoft offers as Insider Preview. You can’t buy a licence yet, which indicates that it’s not (yet) an established OS.
With M1, Mono works as expected under Rosetta, although with a (not significant) drop in performance.
.NET Core however, works under Rosetta but without the debugging feature – but I expect this glitch to be addressed soon.
Before upgrading your machine to M1 or beyond, it is a good idea to rent one online (e.g., here) for at least a month, and test whether it can be a development environment that fits your own needs.
As for the .NET future on Macs, the v6 (to be released Fall 2021) is planned to bring native support for M1. Should this really happen, it will be The .NET version “to rule them all”. Let’s check base again then!