.NET-Softwareentwicklung auf MacOS mit Mono Framework

Neue Softwareentwicklungsprojekte machen immer Spaß und sind gleichzeitig eine Herausforderung. Aber bei einem bestimmten Projekt vor drei Jahren habe ich die Herausforderung auf meiner eigenen Haut gespürt:

  • Der Tech-Stack des konkreten Projekts basierte auf Microsofts ausgereiftem und leistungsfähigem .NET Framework v4 …
  • … während mein eigener Tech-Pack ein Mac war (und immer noch ist) – was ihn in Bezug auf die Grundlagen des Projekts inkompatibel erscheinen ließ.

Es war entscheidend, weiterhin auf meinem Mac zu arbeiten, da ich mich an seine Einfachheit, Leistung, sein geringes Gewicht, seinen guten Geschmack usw. gewöhnt hatte (sprich: von ihm „abhängig“ war – Apple-Fan ganz eindeutig).

Da die beiden Systeme so gut wie inkompatibel sind, war dies zunächst eine Entweder-Oder-Frage. Die anfängliche Recherche ließ mich zunächst zwischen hitzigen Debatten und lustigen Werbespots von beiden Seiten verzetteln, die klar zu machen schienen, dass ich in einer Windows-Welt ein Bürger zweiter Klasse sein würde.

Die hitzigen Debatten und die lustigen Werbespotts brachten mich also auch nicht weiter. Was mich aber weiterbrachte, war eine unabhängige Lösung eines Drittanbieters. Hier kommt die ganze Geschichte:

Die Bühne einrichten

.NET ist ein gut etabliertes Software-Entwicklungs-Framework, da es seit Ende der 90er/Anfang der 2000er Jahre auf dem Markt ist. Es hat zwei Hauptversionen:

  • Das .NET-Framework (oft als ASP.NET bezeichnet) ist ein Open-Source-Framework, das ursprünglich im Jahr 2002 veröffentlicht wurde und zunächst nur auf die Windows-Plattform beschränkt war.
  • Das .NET (ursprünglich .NET Core genannt) wurde 2016 als modulare, leichtere, plattformübergreifende Alternative veröffentlicht. Es funktioniert daher auf Windows, Linux und MacOS.

Beide laufen auf der gleichen Laufzeitumgebung (CLR/Common Language Runtime), die das Äquivalent zur Java Virtual Machine (JRE) ist. Allerdings sind .NET und .NET Framework nicht kompatibel.

In diesem speziellen Fall musste das Projekt aus Gründen, die außerhalb meines Einflusses lagen, auf dem (nicht direkt MacOS-kompatiblen) .NET Framework aufgebaut werden, also hatte ich berechtigte Zweifel (und Sorgen).

Da das .NET Framework so populär ist, gibt es Software-Entwickler, die es (lange vor mir) außerhalb des Windows-Ökosystems verwenden wollten. Da sie nicht auf eine offizielle MS-Antwort auf ihre Bedürfnisse warten wollten, starteten sie 2014 Mono – d.h. die dritte .NET-Version (auch genannt: „the one that saved my day“/„meine Retterin in der Not“).

Was genau ist Mono also? Von ihren Entwicklern wird sie folgendermaßen beschrieben: „Mono ist eine Open-Source-Implementierung von Microsofts .NET Framework, basierend auf den ECMA-Standards für C# und die Common Language Runtime.“

Wenn Sie „Open-Source“ lesen und die Alarmglocken schrillen hören, kann ich Sie beruhigen: Die Mono-Community ist sehr engagiert und professionell, und das Projekt wird sehr gut gepflegt (die letzte Version 6.12. wurde im November 2020 veröffentlicht). Im Laufe der Zeit hat sogar Microsoft begonnen, das Projekt zu sponsern, wobei Teile davon in die aktuellen Iterationen von .NET (v5 und v6) aufgenommen wurden.

In der Praxis stellt sich die Installation von Mono als sehr einfach heraus: Man muss nur hier den richtigen Installer herunterladen (Linux/MacOS/Windows/Docker).

Ich war überrascht zu entdecken, dass Mono bei mir bereits installiert war (Das ist Ihnen doch auch passiert, nicht?). Offensichtlich hatte ich es aus einem anderen/unwichtigen Grund benutzt: eine Windows-.exe auf dem Mac ausführen. Ja, Mono kann das, mit einer einfachen Kommandozeile:

> mono meinprogramm.exe

(Ein Warnhinweis: Nur C#-Desktop-Programme mit den .exe-Erweiterungen können auf diese Weise auf MacOS laufen).

Diesmal brauchte ich Mono aber für viel mehr: ein .NET-Projekt in C# zu entwickeln, zusammen mit Kollegen, die Windows-Rechner benutzten und dieselbe Code-Basis verwendeten. Also aktualisierte ich Mono einfach auf die neueste Version und kümmerte mich dann um den wichtigsten Teil: die integrierte Entwicklungsumgebung (IDE).

Unabhängig davon, ob Sie mit Windows oder Mac arbeiten, gibt es zwei Hauptoptionen, die beide gut sind:

  • kostenlos: VisualStudio Community Edition (der kleine Bruder des klassischen Visual Studio Enterprise)
  • kommerziell: Der JetBrains Rider (der kleine Bruder von IntelliJ, der vollständigsten auf dem Markt erhältlichen Java-IDE).

Sobald ich das Projekt öffnete, wurde meine Mono-Version sofort erkannt:

Berg Software - NET on MacOS - Mono recognised on MacOS
Danach funktionierte alles wie erwartet: Ich war in der Lage, ein .NET-Projekt zu erstellen, zu entwickeln, auszuführen und zu debuggen sowie Tests zu erstellen und die Testabdeckung zu analysieren, und das alles mit großartiger Performance.

Hinter den Kulissen, für die lokale Ausführung des Projekts, bietet Mono den XPS (seinen eigenen leichtgewichtigen Webserver). Für Windows-Maschinen wird dieser Teil durch den IIS Express abgedeckt, die leichtgewichtige Version des IIS (Internet Information Server).

Berg Software - NET on MacOS - Mono webserver on MacOS
Eine Einschränkung gibt es allerdings: Unser .NET-Projekt war eine Reihe von REST-APIs, die von Unity-verwalteten Diensten unterstützt wurden und das Entity Framework für den Datenbankzugriff verwendeten. Wir haben kein klassisches .NET-Frontend/keine Windows Forms entwickelt – für die Frontend-Entwicklung haben wir das modernere Angular-Framework verwendet. Allerdings könnte Mono auch mit Windows Forms umgehen – ich bin nur nicht dazu gekommen, mich damit zu beschäftigen.

Einschränkungen und Umgehungsmöglichkeiten

Sollte es sich reibungslos anhören, so liegt das daran, dass es reibungslos war. Ich hatte allerdings einen Plan B für den Fall, dass etwas schief ging.
Ich installierte ein virtuelles Windows 10, das auf dem Mac unter Hardware-Virtualisierung lief. Ich wusste, dass die Leistung dieses Systems aufgrund der Virtualisierung suboptimal sein würde. Wenn man es aber nur für eine kurze Zeit und eine begrenzte Anzahl von Aktionen verwendete, sollte es in Ordnung sein.

Wenn Sie regelmäßig mit .NET entwickeln, empfehle ich dringend ein Windows-System für die Datensicherung. Einige der beliebtesten Möglichkeiten dafür sind:

  • Parallels Desktop, kommerziell
  • VM Ware, kommerziell
  • Virtual Box, kostenlos
  • Azure, Amazon S3, kommerziell und in der Cloud

Diese Optionen bedeuten, dass ich immer zu Windows greifen kann, für die Aufgaben, die nicht auf dem Mac erledigt werden können.

Allerdings gibt es ein paar Nachteile, auf die ich gestoßen bin:

1. Ich konnte das Projekt nicht für die Entwicklung veröffentlichen. Es funktioniert einfach nicht auf einem Mac, Sie brauchen also immer noch ein „echtes“ Windows-System. Allerdings wird das Publizieren direkt von der lokalen Plattform in der Regel in den frühen Phasen des Projekts durchgeführt. Später sollte diese Aufgabe automatisiert und an einen Build-Server, vor Ort oder in der Cloud, ausgelagert werden.

Dies ist definitiv kein entscheidendes Problem – für mich zumindest, da ich das Projekt von dem bereits erwähnten virtuellen Windows aus veröffentlichen konnte.

2. Eine weitere Operation, die unbedingt Windows benötigte, war das Ausführen von Entity-Framework-Befehlen, wie das Hinzufügen von Migrationen oder das Aktualisieren der Datenbank. Der „Code First“-Ansatz erfordert eine NuGet Package Manager Console, die in Mono nicht verfügbar ist. Aber auch das ist nichts, was man täglich machen würde, also kein Dealbreaker.

3. Ein schwerwiegenderer Nachteil war, dass einige NuGet-Bibliotheken von Drittanbietern unter Mono nicht funktionierten. Bei mir war dies der Fall bei kommerziellen HTML-zu-PDF-Konvertern (die von unserem Berichtserstellungsdienst verwendet werden). Ich habe drei Bibliotheken ausprobiert, von denen keine richtig mit Mono funktionierte, so dass ich schließlich aufgegeben habe, daran herumzubasteln. Die Architektur des Projekts (ähnlich der Microservice-Architektur) erlaubte es mir, den jeweiligen Dienst auf der Windows-Maschine zu isolieren, sodass ich nicht wirklich blockiert war.

Fazit: Obwohl ich auf einige Probleme gestoßen bin, waren Umgehungslösungen mit minimalem Aufwand möglich, so dass mich keines davon von der Arbeit an dem Projekt abgehalten hat.

Die Zukunft

Im November 2020 begann Apple mit der Umstellung seiner MacOS-Hardware von Intel-CPUs auf M1 – Apple Silicon, eine Version der ARM-CPU. Obwohl es sich um einen „revolutionären“ Schritt handelte, versicherte Apple seinen Kunden, dass es dank Rosetta 2 – einem Übersetzungsprozess, der es Benutzern ermöglicht, Apps, die Intels x86_64-Anweisungen enthalten, auf Apple Silicon auszuführen – reibungslos verlaufen wird. Bei .NET wird es jedoch anders sein – zumindest in den nächsten Monaten (oder in den nächsten paar Jahren?).

Ich habe den M1 noch nicht selbst ausprobiert, aber ich habe mir die Berichte von Leuten angesehen, die das getan haben:

Im Moment ist das einzige virtuelle Windows, das Sie auf einem M1 haben können, ein ARM-Windows, das Microsoft als Insider Preview anbietet. Sie können noch keine Lizenz kaufen, was darauf hindeutet, dass es sich (noch) nicht um ein etabliertes OS handelt.

Mit dem M1 funktioniert Mono wie erwartet unter Rosetta, allerdings mit einem (nicht signifikanten) Leistungsabfall.

.NET Core hingegen funktioniert unter Rosetta, aber ohne die Debugging-Funktion – ich erwarte aber, dass diese Panne bald behoben wird.

Bevor Sie Ihren Rechner auf M1 oder darüber hinaus aufrüsten, ist es eine gute Idee, einen solchen Rechner online (z. B. hier) für mindestens einen Monat zu mieten und zu testen, ob er eine Entwicklungsumgebung sein kann, die den eigenen Bedürfnissen entspricht.

Was die .NET-Zukunft auf Macs angeht, so ist geplant, dass die v6 (die im Herbst 2021 erscheinen soll) native Unterstützung für M1 bringt. Sollte dies wirklich passieren, wird es die „ultimative“ .NET-Version sein. Warten wir also ab!

_

29 Jahre im Geschäft | 2700 Software-Projekte | 760 Kunden | 24 Länder

Wir verwandeln Ideen in Software. Wie lautet Ihre Idee?

Kontakt aufnehmen

3 + 11 =