Mein erster eigener Streaming-Server in F# – Teil 1

Heute beginnen wir mit einer kleinen Serie an Artikeln, in der wir einen Streaming-Server in F# implementieren werden. Die Serie umfasst geplant drei Teile. Im heutigen ersten Teil werden wir unsere Entwicklungsumgebung aufsetzen. Im zweiten Teil implementieren wir den Endpunkt zum HTTP-Streaming einer lokalen Video-Datei. Und im letzten Teil ergänzen wir einen weiteren Endpunkt zum Streamen einer Video-Datei aus dem Azure-Blob-Storage.

Geplantes Ziel für diesen Teil

Heute möchten wir unsere Entwicklungsumgebung soweit herrichten, dass wir im nächsten Teil problemlos loslegen können.
Normalerweise wäre keine zusätzliche Arbeit notwendig, wenn wir mit F# und dem .net Framework als Zielumgebung arbeiten würden. Das integrierte Tooling von Visual Studio 2017 für F# mit dem vollen Framework ermöglicht inzwischen ein effizientes Arbeiten. Man könnte erwarten, dass einem der gleiche Umfang für die Arbeit mit .net core als Zielumgebung zur Verfügung steht. Leider ist das aktuell nicht so. Selbst Microsoft empfiehlt momentan daher die Verwendung von Visual Studio Code mit der Ionide-Erweiterung.
Ionide ist eine Sammlung von Editor-Erweiterungen für VS Code und Atom, dass die Arbeit mit F# effizienter gestaltet. Da inzwischen VS Code mein bevorzugter Editor ist, werde ich VS Code im Folgenden verwenden. Wer lieber mit Atom arbeiten möchte, kann das natürlich auch tun. Die Schritte sollten im Prinzip ähnlich sein.
Am Ende möchten wir also eine vergleichbare Entwicklungserfahrung mit F# haben wie unter Visual Studio und dennoch .net core verwenden. Das ist unser Ziel heute.

Grundvoraussetzungen

Folgende Programme/Downloads sollten vorab getätigt werden:
Visual Studio Code
.net core 2 SDK
Anschließend dann den Editor und das SDK installieren.

Streaming-Server - VS Code Terminal, generic.de AG

Abbildung 1: VS Code Terminal

Wenn ihr anschließend den Editor startet und dort die Konsole öffnet (View -> Integrated Terminal oder Strg+ö) und dort die Version des installierten .net core SDK abfragt mit dotnet – Version solltet ihr als Ausgabe 2.0.0 erhalten, so wie ich oben in der Abbildung.

Ionide installieren

Über View -> Extensions (Strg+Shift+X) öffnet ihr den Paketmanager von Code. Dort im Suchfeld „Ionide“ eingeben. Und ihr solltet drei Ergebnisse sehen. Eins davon sollte Ionide-fsharp heißen. Zum Zeitpunkt des Schreibens in der Version 3.1.0. Über einen Klick auf Install könnt ihr Paket das nun installieren.

Streaming-Server - VSCode mit installiertem Ionide Paket, generic.de AG

Abbildung 2: VSCode mit installiertem Ionide Paket

Zwischenstand ausprobieren

Machen wir nun einen kleinen Test, ob alles installierte auch funktioniert. Dafür legen wir ein neues Konsolenprojekt an mit der .net core CLI und anschließend öffnen wir das Projekt in VS Code und bauen und führen es aus.
Dazu öffnen wir zuerst das Terminal wieder. Anschließend legen wir ein Konsolenprojekt am Ort unserer Wahl an. Bevor ihr den Befehl ausführt, sollte euer aktuelles Verzeichnis dort sein, wo ihr eure Projektdatei haben wollt. Der gezeigte Befehl legt kein weiteres Unterverzeichnis an.

Wenn alles geklappt hat, solltet ihr eine ähnliche Ausgabe wie in Abbildung 3 sehen.

Streaming-Server - VS Code Terminal nach Anlegen eines neuen Projekts, generic.de AG

Abbildung 3: VS Code Terminal nach Anlegen eines neuen Projekts

Nun können wir das Projekt in VS Code öffnen. Dazu geht ihr File -> Open Folder (Strg + K, Strg + O) und wählt das Verzeichnis aus, in dem ihr euer neues Projekt angelegt habt. Anschließend sollte der Code in etwa so aussehen, wie in Abbildung 4.

Streaming-Server - VS Code mit geöffnetem Projektverzeichnis, generic.de AG

Abbildung 4: VS Code mit geöffnetem Projektverzeichnis

Falls ihr den F# Project Explorer nicht seht, dann ist er vermutlich ganz unten zusammengeklappt. Ihr könnt ihn dann einfach aufklappen und über den Splitter größer machen.
Als nächstes schauen wir in die erzeugte Program.fs und sehen das einfache Hello World Programm.

Streaming-Server - Hello world from F#, generic.de AG

Abbildung 5: Hello world from F#

Zeit zu überprüfen, ob wir das Programm auch starten können. Dazu haben wir nun mindestens zwei Möglichkeiten. Die erste Möglichkeit besteht darin, den Build Prozess anzustoßen und anschließend das Programm über das .net core CLI zu starten.
Dazu öffnet ihr das integrierte Terminal wieder. Ihr solltet bereits in eurem Projektverzeichnis starten, andernfalls müsst ihr noch schnell dahin navigieren. Dann könnt ihr mit dotnet run euer Projekt bauen und ausführen. Dafür werdet ihr mit einem freundlichen „Hello World from F#“ belohnt. Im Kontextmenü des F# Project Explorer könnt ihr ebenfalls das Starten veranlassen, allerdings bleibt das Konsolenfenster dort nicht offen.
Prinzipiell könnt ihr Code auch um euer eigenes Tastenkürzel erweitern, sodass ihr den Befehl nicht von Hand im Terminal eingeben müsst. Herauszufinden wie das geht, überlasse ich dem motivierten Leser.
Stattdessen schauen wir uns die zweite Möglichkeit an. Dazu müssen wir aber erst ein weiteres Paket installieren. Und zwar das C# Paket. In diesem Paket ist unter anderem auch der Debugger enthalten, den wir auch für F# Programme nutzen können. Also installieren wir ihn erstmal.

Streaming-Server - C# Paket mit unserem Debugger, generic.de AG

Abbildung 6: C# Paket mit unserem Debugger

Anschließend Code neustarten und auf Debug -> Start without Debugging klicken (Strg + F5). Das wird erstmal mit einer Fehlermeldung quittiert. Wir müssen den .net core Debugger installieren. Dazu müssen wir die Kommandopalette öffnen (Strg + P) und dort nach „Debug: Download .NET Core Debugger“ suchen und ausführen. Wenn alles geklappt hat, solltet ihr im Ausgabefenster etwas vergleichbares zu Abbildung 7 sehen.

Wenn wir erneut versuchen das Programm zu starten, werden wir darauf aufmerksam gemacht, dass uns eine launch.json fehlt. Das Bestätigen wir und wir bekommen automatisch eine angelegt. Die automatisch erzeugte launch.json müssen wir noch parametrieren. Wir ersetzen in der Konfiguration für die Konsole, das Targetframework mit netcoreapp2.0 und den Projektnamen mit eurem Projektnamen, in meinem Fall streaming1.
Wir haben es fast geschafft. Beim nächsten Versuch zu starten, wird noch die fehlende tasks.json bemängelt. Auch das Bestätigen wir und bekommen automatisch eine tasks.json erzeugt. Hier müssen wir diesmal nichts anpassen und können alles so übernehmen.
Noch einmal starten wir das Programm mit Debug -> Start without Debugging (Strg + F5) und diesmal dauert es etwas länger und wir erhalten keine Fehlermeldung. Code wechselt zudem vielleicht in die Debug-Perspektive. Das ist mir beim ersten Mal passiert, bei den darauffolgenden Malen nicht mehr.
Aber wo ist nun unsere Ausgabe zu sehen. Dazu müsst ihr zu guter Letzt die Debug Console öffnen über View -> Debug Console (Strg + Shift + Y). Et voilà.

Streaming-Server - VS Code mit launch.json und Debug Console, generic.de AG

Abbildung 8: VS Code mit launch.json und Debug Console

Endspurt

Das einzige was noch fehlt, damit beim wir beim nächsten Mal gleich richtig durchstarten können, ist die Integration unseres Paketmanagers. Im F# Umfeld wird hier statt dem nuget Client in der Regel Paket eingesetzt. Paket macht ein paar Sachen anders als der nuget Client und meiner Ansicht nach sind diese Veränderungen besser, wie z.B. die Trennung zwischen direkten und indirekten Abhängigkeiten.
Integrieren wir also Paket in unser Projekt.
Legen wir dazu ein .paket Verzeichnis an. In dieses Verzeichnis laden wir die paket.bootstrapper.exe runter. Den Download zur aktuellen Version gibt es hier. Anschließend ändern wir den Dateinamen in paket.exe. Nun können wir paket initialisieren.

Dadurch werden drei neue Dateien angelegt:

In der paket.dependencies pflegen wir die Abhängigkeiten, die wir in unserem Projekt verfügbar machen möchten. Um Pakete in einem Projekt zu verwenden müssen eine weitere Datei anlegen namens paket.references. Während es nur eine paket.dependencies gibt, kann es mehrere paket.references geben, eine pro Projekt. Die paket.dependencies gilt also für die Solution und die paket.references je für ein Projekt in der Solution. In unserem Fall haben wir nur ein Projekt, so dass wir nur eine paket.references benötigen, die alle Pakete benutzt, die wir in der paket.dependencies verfügbar machen.
Hier noch ein wichtiger Hinweis: Beim Arbeiten mit Code, Ionide und Paket ist mir leider aufgefallen, dass es scheinbar ein Problem in der aktuellen Version gibt, bzgl. der Aktualisierung der Textvervollständigung, wenn sich die Referenzen des Projekts verändern. Soweit ich es nachvollziehen konnte, aktualisiert sich der im Hintergrund verwendete FsAutocomplete Service nicht, wenn sich die project.assets.json aktualisiert. Der einzige mir bekannte Workaround ist Code jedes Mal neu zu starten und damit den FsAutocomplete Service, wenn man neue Pakete hinzugefügt und über dotnet restore die project.assets.json erneuert wurde. Das ist momentan der einzige Wermutstropfen. Man kann im F# Project Explorer kontrollieren, ob nach dem Neustart von Code die Referenzen aktuell sind.
Das reicht uns auch für heute. Wir haben alles vorbereitet und beim nächsten Mal legen wir dann los mit unserem Streaming-Server. Den Quellcode zur Serie gibt es hier. Man liest sich in Teil 2.

Danke fürs Lesen.