<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>schnittstelle Archive - Robert Skibbe</title>
	<atom:link href="https://robbelroot.de/blog/tag/schnittstelle/feed/" rel="self" type="application/rss+xml" />
	<link></link>
	<description>alias RobbelRoot – Freelance Full Stack Developer .NET</description>
	<lastBuildDate>Mon, 13 Jun 2022 14:11:37 +0000</lastBuildDate>
	<language>de</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>

<image>
	<url>https://robbelroot.de/wp-content/uploads/2020/12/cropped-favicon-32x32.png</url>
	<title>schnittstelle Archive - Robert Skibbe</title>
	<link></link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>&#x1f511; VB.NET RFID Scanner &#8211; Chips mit dem Arduino Mikrocontroller auslesen</title>
		<link>https://robbelroot.de/blog/vbnet-rfid-scanner-chips-mit-arduinomikrocontroller-auslesen/</link>
					<comments>https://robbelroot.de/blog/vbnet-rfid-scanner-chips-mit-arduinomikrocontroller-auslesen/#comments</comments>
		
		<dc:creator><![CDATA[Robert Skibbe]]></dc:creator>
		<pubDate>Fri, 20 May 2022 23:31:10 +0000</pubDate>
				<category><![CDATA[Allgemein]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[Visual Basic .NET]]></category>
		<category><![CDATA[Visual Basic .NET Problemlösungen]]></category>
		<category><![CDATA[arduino]]></category>
		<category><![CDATA[basic]]></category>
		<category><![CDATA[beispiel]]></category>
		<category><![CDATA[chipkarte]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[einfach]]></category>
		<category><![CDATA[hardware]]></category>
		<category><![CDATA[input]]></category>
		<category><![CDATA[io]]></category>
		<category><![CDATA[nano]]></category>
		<category><![CDATA[output]]></category>
		<category><![CDATA[reader]]></category>
		<category><![CDATA[rfid]]></category>
		<category><![CDATA[scannen]]></category>
		<category><![CDATA[scanner]]></category>
		<category><![CDATA[schnittstelle]]></category>
		<category><![CDATA[serial]]></category>
		<category><![CDATA[serialport]]></category>
		<category><![CDATA[seriell]]></category>
		<category><![CDATA[vb]]></category>
		<category><![CDATA[vbnet]]></category>
		<category><![CDATA[visual]]></category>
		<category><![CDATA[zugang]]></category>
		<category><![CDATA[zugangskontrolle]]></category>
		<guid isPermaLink="false">https://robbelroot.de/?p=9930</guid>

					<description><![CDATA[<p>RFID Chips mit Visual Basic .NET und dem Arduino Mikrocontroller auslesen Wer in VB.NET Daten aus einem RFID-Chip auslesen möchte, trifft unter normalen Umständen vermutlich auf die handelsüblichen Geräte. Ruckzuck an den PC angeschlossen sind Sie auch schon startklar, uns die ausgelesenen Daten als Tastatur-Input bereitzustellen. Gleichzeitig liegt genau hier &#8230;</p>
<p>Der Beitrag <a href="https://robbelroot.de/blog/vbnet-rfid-scanner-chips-mit-arduinomikrocontroller-auslesen/">&#x1f511; VB.NET RFID Scanner &#8211; Chips mit dem Arduino Mikrocontroller auslesen</a> erschien zuerst auf <a href="https://robbelroot.de">Robert Skibbe</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2022/05/VB.NET-RFID-Scanner-Chips-mit-dem-Arduino-Mikrocontroller-auslesen.png"><img fetchpriority="high" decoding="async" width="640" height="360" src="https://robbelroot.de/wp-content/uploads/2022/05/VB.NET-RFID-Scanner-Chips-mit-dem-Arduino-Mikrocontroller-auslesen.png" alt="VB.NET RFID Scanner - Chips mit dem Arduino Mikrocontroller auslesen" class="wp-image-9934" title="VB.NET RFID Scanner - Chips mit dem Arduino Mikrocontroller auslesen"/></a><figcaption>VB.NET RFID Scanner &#8211; Chips mit dem Arduino Mikrocontroller auslesen</figcaption></figure>






<h2 class="wp-block-heading">RFID Chips mit Visual Basic .NET und dem Arduino Mikrocontroller auslesen</h2>



<p>Wer in VB.NET Daten aus einem RFID-Chip auslesen möchte, trifft unter normalen Umständen vermutlich auf die handelsüblichen Geräte. Ruckzuck an den PC angeschlossen sind Sie auch schon startklar, uns die ausgelesenen Daten als Tastatur-Input bereitzustellen. Gleichzeitig liegt genau hier das Problem, jedoch gleich mehr dazu. Im heutigen Beitrag beschäftigen wir uns also mit einem RFID-Scanner der Marke Eigenbau und schauen uns die Verarbeitung mit VB.NET an.</p>



<p>Zu den bekannten Einsatzgebieten der kleinen RFID-Sensoren zählen unter anderem: Zugangs- und Zugriffskontrollen wie z. B. Ticketsysteme und Türen, aber ebenso bei unseren tierischen Freunden und sogar im Ausweis finden Sie Ihre Anwendung. Selbst beim Einkauf können wir mit der RFID-Technologie kontaktlose Bezahlvorgänge durchführen und somit unseren Alltag erleichtern.</p>



<p class="info-banner">&#x1f4a1; Achtung: In diesem Beitrag geht es in erster Linie um die Verarbeitung der RFID-Daten seitens VB.NET. Ich werde in einem zukünftigen Beitrag noch die Seite des Mikrocontrollers (Arduino Nano, Mega, whatever) erläutern. Hier beschäftigen wir uns ein wenig mit den Aspekten wie Handhabung und Sicherheit. Ich verwende in diesem Beitrag Affiliate-Links, womit Du mich vollkommen kostenlos bei einem Kauf über die Links unterstützen kannst.</p>



<style>
.info-banner {
  background: #03a9f4;
  padding: 2em;
  border-radius: 0.5em;
  color: whitesmoke;
}
</style>



<h2 class="wp-block-heading">VB.NET RFID Reader aus dem Handel = meist &#8222;Tastatur-a-like only&#8220;</h2>



<p>Kommen wir nochmal genauer auf das Problem mit der angesprochenen Tastatur-Emulation (wenn das der exakt korrekte Ausdruck ist..) zurück. Wenn wir mit solchen Geräten, bzw. Sensoren wie einem RFID-Scanner arbeiten möchten, dann natürlich so flexibel wie möglich. Man stellt sich also vor, man startet seine Anwendung, lässt Sie in Ruhe laufen und wenn man loslegen will, kommt ein Kollege und möchte sich &#8222;eben&#8220; im System anmelden.</p>



<p>Dies funktioniert mit den gängigen Geräten im Discount-Bereich häufig nicht, da Diese zwangsweise eine fokussierte Oberfläche (TextBox, etc.) benötigen. Das ist freilich nicht gerade cool, wenn wir eine Bestellung bearbeiten und zig Daten neu eingeben müssten, nachdem unser Kollege fertig ist. Schöner wäre es hingegen, wenn unser Kollege seinen Chip einscannt, eine kleine Maske kommt und er seine 2–3 Eingaben so erledigen könnte. Anschließend könnten wir dann mit unserer Arbeit fortfahren und wir wären durch.</p>



<p>Sicherlich gibt es vermutlich auch andere Varianten, Welche dann zig andere Funktionen unterstützen, aber hier bewegen wir uns dann auch zumeist im vergleichsweise teureren Preis-Segment. Leider bieten die handelsüblichen Geräte also häufig nur eine Art &#8222;nix Halbes und nix Ganzes&#8220;-Lösung. Das Gerät emuliert häufig einfach nur eine Art Tastatur, Welche dann die einzelnen Daten-Bestandteile runterschreibt und häufig mit einem &#8222;Enter&#8220; bestätigt.</p>


<div class="async-youtube" data-embed="yPgT8BAmEAo" data-alt="">
    <div class="play-button"></div>      
  </div>



<h2 class="wp-block-heading">Was benötigen wir für den VB.NET RFID Reader</h2>



<p>Bedenke den blauen Hinweis oben, dass wir in diesem Beitrag vorerst nur die VB.NET Seite der Medaille betrachten. Trotzdem möchte ich hier eben noch einmal die verwendeten Dinge auflisten, alles Weitere wird dann in einem zukünftigen Beitrag ergänzend erscheinen.</p>



<p>Wir benötigen also:</p>



<ul class="wp-block-list"><li>Einen Mikrocontroller wie z. B. den <strong><a href="https://amzn.to/3yQisn0" target="_blank" rel="noreferrer noopener">Arduino Nano</a></strong> in meinem Fall</li><li>Die <strong><a href="https://www.arduino.cc/en/software" target="_blank" rel="noreferrer noopener">Arduino IDE</a></strong> (am häufigsten verwendet)</li><li>Ein <strong><a href="https://amzn.to/3wGgz9x" target="_blank" rel="noreferrer noopener">RFID Kit</a></strong> (häufig bestehend aus Sensor, Pins und Chipkarten/Anhänger)</li><li>Ausreichend <strong><a href="https://amzn.to/3NtBPX2" target="_blank" rel="noreferrer noopener">Jumper-Kabel</a></strong> (je nach Setup &#8211; hier 7 male to female)</li><li>1 <strong><a href="https://amzn.to/3Nwt8ex" target="_blank" rel="noreferrer noopener">Mini-USB Kabel</a></strong> zur Verbindung des Arduinos zum PC (eigentlich immer beim Arduino dabei..)</li></ul>



<p>Nachdem wir nun von den Hardware-Komponenten erstmal startklar sind, widmen wir uns nach der Verbindung endlich dem Visual Basic NET Code.</p>



<h2 class="wp-block-heading">Den RFID Scanner mit unserem PC verbinden</h2>



<p>Ebenso einfach wie der oben beschriebene Weg mit den handelsüblichen RFID Scanner-Geräten, verfahren wir auch mit unserem Eigenbau. Verbinde den Arduino mithilfe eines Mini-USB Kabel mit einem USB-Port Deiner Wahl. Es sollte dann ein normales &#8222;Pling-Plong&#8220;-Geräusch kommen, Welches wie üblich das Anschließen eines neuen Gerätes signalisiert.</p>



<h3 class="wp-block-heading">Verbindungsprobleme</h3>



<p>Natürlich kann auch hier das ein oder andere Problem auf Dich zukommen, so traf es auch mich – Thema Treiber.. Um den typischen CH340 Chip erkennbar und zum Laufen zu bringen, installierst Du den für Dein System passenden Treiber. Danach wirst Du vermutlich zu einem Neustart Deines PCs aufgefordert, Welchen Du auch – um weitere Fehlerquellen zu vermeiden – durchführen solltest.</p>



<p class="info-banner">&#x1f4a1; Achtung: Bei der <strong><a href="http://www.wch.cn/download/CH341SER_ZIP.html" target="_blank" rel="noreferrer noopener">Treiber-Seite</a></strong> handelt es sich um einen chinesischen Anbieter. Achte auf das für dich passende Paket und verwende ggf. die z. B. in Chrome vorhandene Übersetzungs-Funktion. Grundsätzlich ist das dicke blaue Download-Icon aber nicht zu übersehen. Der &#8222;341SER.zip&#8220;-Treiber sollte auch für die 340er Variante funktionieren. Gerne würde ich Dir den Treiber ebenfalls zum Download anbieten, aber ich möchte vermeiden, dass Du nachher mit einem veralteten Treiber arbeitest.</p>



<p>Öffne dann einfach die &#8222;SETUP.exe&#8220; im &#8222;CH341SER&#8220;-Ordner und klicke auf &#8222;install&#8220;:</p>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2022/05/Arduino-USB-Treiber-Installation-CH341SER.png"><img decoding="async" width="536" height="292" src="https://robbelroot.de/wp-content/uploads/2022/05/Arduino-USB-Treiber-Installation-CH341SER.png" alt="" class="wp-image-9965"/></a><figcaption>Arduino USB Treiber Installation CH341SER – VB.NET RFID Scanner</figcaption></figure>



<p>Starte anschließend Deinen PC wie gesagt am besten neu, damit Du keine eventuellen Installations-, bzw. Erkennungsprobleme hast. Danach sollte der CH340 Chip ganz normal als COM-Port im Gerätemanager auftauchen (natürlich nur wenn tatsächlich physisch verbunden &#8211; Captain Obvious..):</p>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2022/05/USB-Verbindung-vom-Arduino-CH340-Chip-erkannt.png"><img decoding="async" width="785" height="208" src="https://robbelroot.de/wp-content/uploads/2022/05/USB-Verbindung-vom-Arduino-CH340-Chip-erkannt.png" alt="" class="wp-image-9969"/></a><figcaption>USB Verbindung vom Arduino CH340 Chip erkannt – VB.NET RFID Scanner</figcaption></figure>



<h2 class="wp-block-heading">Code – RFID-Daten über VB.NET auslesen</h2>



<p>Kommen wir nun zum vermutlich heißt ersehnten VB.NET Code zum Auslesen der jeweiligen RFID-Daten. Im Mittelpunkt aller Dinge steht hier die <strong><a href="https://docs.microsoft.com/de-de/dotnet/api/system.io.ports.serialport?view=dotnet-plat-ext-6.0" target="_blank" rel="noreferrer noopener">SerialPort-Klasse</a></strong>, Welche Du ggf. noch via NuGet-Paket installieren musst. Suche dazu am besten im NuGet-Paketmanager nach &#8222;System.IO.Ports&#8220;, oder verwende <strong><a href="https://www.nuget.org/packages/System.IO.Ports/" target="_blank" rel="noreferrer noopener">diesen Link</a>, </strong>dort drin befindet sich die Klasse. Nachdem wir jetzt über die erforderlichen Mittel für die Kommunikation via COM-Ports besitzen, können wir starten.</p>



<p>Lege z. B. eine .NET 6 Windows Forms App an und gehe wie gewohnt mit F7 in den Code hinter der Form. Zuerst legen wir (je nach Belieben/gewünschten Einschränkungen) eine Eigenschaft namens &#8222;Connection&#8220; an, Welche unsere SerialPort-Verbindung widerspiegeln wird.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Public Property Connection As SerialPort</pre>



<p>Als nächstes fügen wir noch ein &#8222;<strong><a href="https://docs.microsoft.com/de-de/dotnet/api/system.collections.generic.dictionary-2?view=net-6.0" target="_blank" rel="noreferrer noopener">Dictionary</a></strong>&#8220; für eine Zuweisung von Uids (Strings &#8211; die Ids der gescannten Chips) zu Nutzern (User-Klasse) hinzu. Beachte hierbei, dass ich mit einer generischen Variante, also einem Interface arbeite, alternativ kannst Du das große &#8222;i&#8220; auch weglassen. Die User-Klasse erstellen wir gleich und dient nur zur Veranschaulichung.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Public Property UidsToUser As IDictionary(Of String, User)</pre>



<h3 class="wp-block-heading">Vorbereiten der Verbindung</h3>



<p>Erstelle als Nächstes einen Konstruktor für die Form, indem Du &#8222;Sub New&#8220; innerhalb der &#8222;Form1&#8220;-Klasse tippst und mit &#8222;Enter&#8220; bestätigst. Dann sollte Visual Studio Dir ein grobes Skelett für den Konstruktor generieren, diesen passen wir wie folgt an:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">    Sub New()
        InitializeComponent()
        Connection = New SerialPort("COM3", 9600, Parity.None, 8, StopBits.One)
        AddHandler Connection.DataReceived, AddressOf Connection_DataReceived
    End Sub</pre>



<p>Zuerst lassen wir die von Haus aus kommende &#8222;InitializeComponent&#8220;-Methode unangetastet, da unsere eventuellen Form-Steuerelemente sonst nicht funktionieren würden. Danach instanziieren wir eine neue Instanz der Klasse &#8222;SerialPort&#8220; mit einigen Werten.</p>



<ul class="wp-block-list"><li>COM3 &#8211; steht für den für die Kommunikation zu wählenden COM-Port. In meinem Fall steckt mein Arduino am COM-Port Nr. 3.</li><li>9600 &#8211; ist die sogenannte Baudrate und regelt die &#8222;Kommunikationsgeschwindigkeit&#8220; zwischen Arduino und PC. Achte hier darauf, dass Du den gleichen Wert wie in Deinem Arduino Sketch unter &#8222;Serial.Begin(&lt;der Wert&gt;)&#8220; wählst.</li></ul>



<p>Dann stellen wir noch gewisse andere Dinge wie die Parität, die Daten-Bits und die Stop-Bits ein. (Ich erspare Dir jede einzelne Erklärung hier..).</p>



<p>Im letzten Konstruktor-Schritt bezüglich der SerialPort-Verbindung fügen wir auch noch einen Ereignishandler für das <strong><a href="https://docs.microsoft.com/de-de/dotnet/api/system.io.ports.serialport.datareceived?view=dotnet-plat-ext-6.0" target="_blank" rel="noreferrer noopener">&#8222;DataReceived&#8220;-Ereignis</a></strong> hinzu.</p>



<h3 class="wp-block-heading">Verbindung starten</h3>



<p>Danach können wir einen weiteren Handler generieren, hierbei handelt es sich um den Ereignishandler für das &#8222;Form Load&#8220;-Ereignis. Darin werden wir dann die Verbindung zum Arduino (über den SerialPort) öffnen, ansonsten können wir natürlich nicht kommunizieren &#x1f609;.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Connection.Open()
    End Sub</pre>



<h3 class="wp-block-heading">Auf Daten reagieren/lauschen</h3>



<p>Nun müssen wir den oben zugewiesenen (aber bisher nicht existenten) Ereignishandler für das &#8222;DataReceived&#8220;-Ereignis erstellen. Das geht erstmal ganz einfach wie folgt:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">    Private Sub Connection_DataReceived(sender As Object, e As SerialDataReceivedEventArgs)
        Dim text = Connection.ReadLine().TrimStart().TrimEnd()
        If text.StartsWith("RFID:") Then
            Dim uid = text.Split(":")(1)
            Invoke(Sub() OnUidScanned(uid))
        End If
    End Sub</pre>



<p class="info-banner">&#x1f4a1; Achtung: Ich habe seitens des Arduino-Codes sichergestellt, dass wir mit einem Zeilenumbruch arbeiten/kommunizieren. Daher kann ich hier mit dem <strong><a href="https://docs.microsoft.com/de-de/dotnet/api/system.io.ports.serialport.readline?view=dotnet-plat-ext-6.0" target="_blank" rel="noreferrer noopener">&#8222;ReadLine&#8220;-Befehl</a></strong> arbeiten. Beachte allerdings bei Deinen geplanten Projekten, dass das &#8222;DataReceived&#8220;-Ereignis (wie der Name schon sagt) lediglich sagt: &#8222;Ey, hier sind Daten&#8220; &#8211; das heißt aber nicht, dass ALLE Daten da sind, die Du Dir vorstellst. Da wir hier aber mit einer kleinen Datenmenge a la &#8222;RFID:DieUid&#8220; arbeiten, werden wir hier aller Voraussicht nach kein Problem bekommen. Wenn Du allerdings ellenlange Texte hin und her schiebst, könnte es zu einem Problem werden &#8211; aber auch dazu in einem anderen Beitrag mehr..</p>



<p>Nun lesen wir mit &#8222;ReadLine&#8220; die Daten ein und &#8222;säubern&#8220; Diese anschließend durch Verkettung von &#8222;TrimStart&#8220; und &#8222;TrimEnd&#8220;. Das verhindert unnötige und unerwartete Leerzeichen, kann aber natürlich auch durch saubere Programmierung am Arduino verhindert werden..</p>



<h3 class="wp-block-heading">Nun vor-verarbeiten</h3>



<p>Grundsätzlich haben wir den Text, Welcher vom Arduino kommt endlich vorliegen und können Ihn verarbeiten. Beachte, dass ich hier ein kleines &#8222;Protokoll&#8220; einhalte, auch wenn es nur praktisch gesehen aus einem Teil besteht. Ich halte mich an meine Regel, dass ich beim erfolgreichen Einlesen eines RFID-Chips den String &#8222;RFID:&#8220; gefolgt von der Uid-Zeichenfolge und einem Zeilenumbruch durch den SerialPort jage.</p>



<p>Ergo muss ich mich natürlich an der Gegenstelle (VB.NET) daran halten und die Daten dementsprechend auslesen und verarbeiten. Das mache ich dann im nächsten Schritt, indem ich prüfe, ob die eingelesenen Daten mit einem &#8222;RFID:&#8220; beginnen. Ich splitte also den String anhand des Doppelpunktes und nehme mir den zweiten Teil des Strings als Uid.</p>



<h3 class="wp-block-heading">Daten an die UI delegieren</h3>



<p>Anders als gedacht sollte man hier normalerweise nun nicht mit einer Art &#8222;ich update mal jetzt direkt die UI a la Label1.Text = &#8230;&#8220; arbeiten. Das liegt daran, dass das Ereignis vom SerialPort (und somit unser Handler) meines Wissens nach auf einem anderen Thread als die UI ausgeführt wird. Von dort aus also nun auf die grafische Oberfläche zuzugreifen sollte aller Wahrscheinlichkeit nach einen &#8222;Cross Thread bla blupp&#8220;-Fehler auslösen.</p>



<p>Um dies zu vermeiden, verwende ich die &#8222;Invoke&#8220;-Methode der Form in Kombination mit einem inline definierten Delegaten (&#8222;Sub() &lt;etc&gt;..&#8220;). Dieser Delegat hat einen zugrunde liegenden Aufruf namens &#8222;OnUidScanned&#8220; &#8211; mit dem passenden String-Parameter. Alternativ könntest Du hier auch mit einem &#8222;BeginInvoke&#8220;-Aufruf arbeiten, dies lässt den Aufrufer nicht auf den Abschluss des Codes warten.</p>



<h3 class="wp-block-heading">Reine Erkennung von Uids fertig &#8211; und nun?</h3>



<p>An dieser Stelle haben wir unser Grundgerüst, was das Auslesen und &#8222;parsen&#8220; der Uids der Chips betrifft fertig. Nun wirst Du Dich hoffentlich fragen – ja cool, und was nun? Nur Geduld junger Padawan, es geht direkt weiter. Als Nächstes definieren wir (in .NET-Manier) eine typische Ereignis-Methode namens &#8222;On&#8230;&#8220;. Diese kann bei Bedarf in Sub-Klassen überschrieben werden und dient als Basis für unser eigenes Ereignis.</p>



<p>Erstelle nun am Ende der Datei (da lege ich die Ereignisse eigentlich immer ab) ein Ereignis wie das Folgende. Beachte dabei, dass man normalerweise eine eigene von EventArgs abgeleitete Klasse für die Ereignisinformationen verwenden sollte, darauf habe ich hier verzichtet. Unser Ereignis beinhaltet nur die Uid-Information, also einen simplen String.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Public Event UidScanned As EventHandler(Of String)</pre>



<p>Die passende &#8222;On&#8220;-Methode würde also so aussehen:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">    Protected Overridable Sub OnUidScanned(uid As String)
        RaiseEvent UidScanned(Me, uid)
    End Sub</pre>



<p>Zu guter Letzt verknüpfen wir nun unser eigens erstelltes Ereignis via Handles-Klausel mit einer passenden Methode als Handler:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">    Private Sub Me_UidScanned(sender As Object, uid As String) Handles Me.UidScanned
        Dim user As User = Nothing
        UidsToUser.TryGetValue(uid, user)
        If user Is Nothing Then
            MessageBox.Show("Login failed!")
            Return
        End If
        MessageBox.Show($"Hey {user.Name}!")
    End Sub</pre>



<p>Hier initialisieren wir zuerst eine leere Variable namens &#8222;User&#8220;, Welche anschließend durch die <strong><a href="https://docs.microsoft.com/de-de/dotnet/api/system.collections.generic.dictionary-2.trygetvalue?view=net-6.0" target="_blank" rel="noreferrer noopener">&#8222;TryGetValue&#8220;-Funktion</a></strong> der generischen Dictionary Klasseninstanz befüllt werden sollte. Wenn kein zur Uid passender Nutzer ermittelt werden konnte, wird hier eine kleine &#8222;Login failed!&#8220;-Meldung ausgegeben. Ansonsten zeigen wir testweise den Namen des jeweils ermittelten Nutzers an.</p>



<p class="info-banner">&#x1f4a1; Achtung: Hier noch der Hinweis, dass es sich hierbei keinesfalls um einen &#8222;production ready&#8220; Code handelt. Das Beispiel dient lediglich zur Veranschaulichung des Empfangs von seriellen Sensordaten via SerialPort. Jeder mit einigermaßen vorhandenen <strong>Disassembler</strong>-Kenntnissen würde in wenigen Sekunden an die jeweiligen Chip-Uids kommen. Normalerweise sollte das Programm nur als Schnittstelle dienen, also die Daten einlesen und an eine passende (Web-) Schnittstelle zur Verarbeitung weiterleiten. Wenn sicher über Https übertragen, könnte die Schnittstelle also anhand der Uid einen passenden Nutzer aus der Datenbank laden und einen Zugriff ermöglichen. Auch wenn ich diesen Satz hasse: &#8222;..aber das würde den Rahmen sprengen&#8220; / &#8222;The princess is in another castle&#8220; &#8211; wenn Du mich verstehst &#x1f61b;..</p>



<h3 class="wp-block-heading">Die User-Klasse</h3>



<p>Bevor ich es vergesse, hier noch die verwendete, simple User-Klasse:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Public Class User

    Public Property Name As String

    Sub New(name As String)
        Me.Name = name
    End Sub

    Public Overrides Function ToString() As String
        Return Name
    End Function

End Class</pre>



<h2 class="wp-block-heading">Weitere Links</h2>



<ul class="wp-block-list"><li><strong><a href="https://robbelroot.de/blog/chipkarten-tags-mit-arduino-rfid-scanner-auslesen" target="_blank" rel="noreferrer noopener">Arduino RFID Scanner</a></strong></li><li><a href="https://robbelroot.de/blog/virtuelle-com-ports-mit-com0com-erstellen-emulieren/" target="_blank" rel="noreferrer noopener"><strong>Virtuelle COM Ports emulieren mit com0com</strong></a></li></ul>



<h2 class="wp-block-heading">Downloads</h2>



<p>Wie immer findest Du hier am Schluss den vollständigen Download des (VB.NET) Codes. Ggf. ergänze ich der Vollständigkeit halber trotzdem noch den Arduino-Code, ansonsten wird Dieser später in dem getrennten Arduino-Teil kommen.</p>



<div class="wp-block-buttons is-layout-flex wp-block-buttons-is-layout-flex">
<div class="wp-block-button"><a class="wp-block-button__link" href="https://bit.ly/vbnet-rfid-scanner-download-hp" target="_blank" rel="noreferrer noopener">RfidReaderExample.zip</a></div>



<div class="wp-block-button"><a class="wp-block-button__link" href="https://www.nuget.org/packages/System.IO.Ports/" target="_blank" rel="noreferrer noopener">System.IO.Ports NuGet Package</a></div>



<div class="wp-block-button"><a class="wp-block-button__link" href="http://www.wch.cn/download/CH341SER_ZIP.html" target="_blank" rel="noreferrer noopener">CH340 Driver Site</a></div>


</div>
<p>Der Beitrag <a href="https://robbelroot.de/blog/vbnet-rfid-scanner-chips-mit-arduinomikrocontroller-auslesen/">&#x1f511; VB.NET RFID Scanner &#8211; Chips mit dem Arduino Mikrocontroller auslesen</a> erschien zuerst auf <a href="https://robbelroot.de">Robert Skibbe</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://robbelroot.de/blog/vbnet-rfid-scanner-chips-mit-arduinomikrocontroller-auslesen/feed/</wfw:commentRss>
			<slash:comments>3</slash:comments>
		
		
			</item>
		<item>
		<title>Wie man einen NodeJS Http Server erstellt</title>
		<link>https://robbelroot.de/blog/wie-man-einen-nodejs-http-server-erstellt/</link>
					<comments>https://robbelroot.de/blog/wie-man-einen-nodejs-http-server-erstellt/#comments</comments>
		
		<dc:creator><![CDATA[Robert Skibbe]]></dc:creator>
		<pubDate>Thu, 16 Dec 2021 19:28:54 +0000</pubDate>
				<category><![CDATA[Allgemein]]></category>
		<category><![CDATA[NodeJS]]></category>
		<category><![CDATA[NodeJS Problemlösungen]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[anfragen]]></category>
		<category><![CDATA[antwort]]></category>
		<category><![CDATA[antworten]]></category>
		<category><![CDATA[api]]></category>
		<category><![CDATA[async]]></category>
		<category><![CDATA[asynchron]]></category>
		<category><![CDATA[beantworten]]></category>
		<category><![CDATA[dienst]]></category>
		<category><![CDATA[erstellen]]></category>
		<category><![CDATA[http]]></category>
		<category><![CDATA[https]]></category>
		<category><![CDATA[hypertext transfer protocol]]></category>
		<category><![CDATA[io]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[js]]></category>
		<category><![CDATA[microservice]]></category>
		<category><![CDATA[node]]></category>
		<category><![CDATA[nodejs]]></category>
		<category><![CDATA[request]]></category>
		<category><![CDATA[respond]]></category>
		<category><![CDATA[response]]></category>
		<category><![CDATA[schnittstelle]]></category>
		<category><![CDATA[secure]]></category>
		<category><![CDATA[server]]></category>
		<category><![CDATA[service]]></category>
		<category><![CDATA[sicher]]></category>
		<category><![CDATA[ssl]]></category>
		<category><![CDATA[web]]></category>
		<category><![CDATA[webdienst]]></category>
		<category><![CDATA[webschnittstelle]]></category>
		<category><![CDATA[webserver]]></category>
		<guid isPermaLink="false">https://robbelroot.de/?p=6901</guid>

					<description><![CDATA[<p>Wie Du einen NodeJS Http Server erstellen kannst, erfährst Du im heutigen Beitrag. Ich verzichte der Einfachheit halber und aufgrund der meiner Meinung nach sinnvollen Trennung auf weitere Frameworks. Für den Bau eines NodeJS Http Servers werden wir also nur die bereits vorhandenen Bordmittel von Node verwenden. Grundprinzipien eines (NodeJS) &#8230;</p>
<p>Der Beitrag <a href="https://robbelroot.de/blog/wie-man-einen-nodejs-http-server-erstellt/">Wie man einen NodeJS Http Server erstellt</a> erschien zuerst auf <a href="https://robbelroot.de">Robert Skibbe</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2021/12/NodeJS-Http-Server-erstellen.png"><img loading="lazy" decoding="async" width="1200" height="628" src="https://robbelroot.de/wp-content/uploads/2021/12/NodeJS-Http-Server-erstellen.png" alt="NodeJS Http Server erstellen" class="wp-image-6903" title="NodeJS Http Server erstellen"/></a><figcaption>NodeJS Http Server erstellen</figcaption></figure>






<p>Wie Du einen <strong>NodeJS Http Server</strong> erstellen kannst, erfährst Du im <strong>heutigen Beitrag</strong>.</p>



<p>Ich <strong>verzichte </strong>der Einfachheit halber und aufgrund der meiner Meinung nach sinnvollen Trennung <strong>auf</strong> <strong>weitere Frameworks</strong>.</p>



<p><strong>Für den Bau </strong>eines NodeJS Http Servers <strong>werden </strong>wir also <strong>nur </strong>die bereits <strong>vorhandenen Bordmittel </strong>von Node <strong>verwenden</strong>.</p>



<h2 class="wp-block-heading">Grundprinzipien eines (NodeJS) Http Servers</h2>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2021/12/NodeJS-Http-Server-Basics.png"><img loading="lazy" decoding="async" width="1200" height="628" src="https://robbelroot.de/wp-content/uploads/2021/12/NodeJS-Http-Server-Basics.png" alt="NodeJS Http Server Basics" class="wp-image-6920" title="NodeJS Http Server Basics"/></a><figcaption>NodeJS Http Server Basics</figcaption></figure>



<p><strong>Bevor </strong>wir <strong>in </strong>den <strong>Code </strong>und Weiteres <strong>starten </strong>würde ich sagen, dass wir uns <strong>erstmal </strong>den <strong>Basics </strong>des Webs widmen.</p>



<p><strong>Vielleicht </strong>ist Dir das <strong>Grundprinzip </strong>von Webservern bereits <strong>bekannt</strong>, <strong>dann </strong>bist Du natürlich herzlich <strong>eingeladen </strong>diesen Abschnitt zu <strong>überspringen</strong>.</p>



<p><strong>Für </strong>alle <strong>Anderen </strong>und die somit eventuellen Neulinge unter den Besuchern, <strong>schauen </strong>wir uns aber <strong>den Ablauf </strong>eines Webservers <strong>nochmal an</strong>.</p>



<p>Das <strong>Grundprinzip </strong>lässt sich auf <strong>viele Bereich </strong>übertragen, also <strong>nicht nur auf</strong> das simple &#8222;Serven&#8220; (Bereitstellen) <strong>einer Datei </strong>auf Anfrage.</p>



<p>Wenn Du Dir das <strong>Bild</strong> anschaust, siehst Du eine (oder mehrere) <strong>typische Situatione</strong>(n).</p>



<h3 class="wp-block-heading">Ablauf einer Anfrage</h3>



<p><strong>Links </strong>befinden sich die <strong>verwendeten Geräte</strong>, wie z. B. Laptops &amp; Desktop PCs, Smartphones und Tablets.</p>



<p>Diese <strong>rufen </strong>z. B. <strong>in </strong>Ihrem <strong>Browser </strong>eine bestimmte <strong>Website/Adresse </strong>auf, Sie senden also eine <strong>Anfrage an den Server</strong>.</p>



<p><strong>Danach schaut </strong>der <strong>Server </strong>nach seiner <strong>entsprechenden Logik</strong>, <strong>um </strong>die jeweilige Anfrage <strong>zu beantworten</strong>.</p>



<p><strong>Dabei sendet </strong>&#8222;er&#8220; <strong>verschiedene </strong>Daten <strong>in </strong>seiner <strong>Antwort </strong>wie z. B. den <strong>Kopf</strong>, oder den <strong>Body</strong>.</p>



<p>Der <strong>Inhalt </strong>der <strong>Antwort </strong>hängt natürlich <strong>unter Anderem </strong>stark von der <strong>Gestaltung </strong>des jeweiligen &#8222;Endpunktes&#8220; und der allgemeinen Server-Infrastruktur ab.</p>



<p><strong>Handelt </strong>es sich dabei um eine <strong>Datei </strong>sieht die <strong>Antwort anders </strong>aus, <strong>als </strong>wenn man nur über <strong>eine Schnittstelle </strong>diverse <strong>Kunden </strong>abrufen möchte.</p>



<h2 class="wp-block-heading">Das simpelste Beispiel</h2>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2021/12/NodeJS-Http-Server-Simples-Beispiel.jpg"><img loading="lazy" decoding="async" width="1280" height="853" src="https://robbelroot.de/wp-content/uploads/2021/12/NodeJS-Http-Server-Simples-Beispiel.jpg" alt="NodeJS Http Server - Simples Beispiel" class="wp-image-6938" title="NodeJS Http Server - Simples Beispiel"/></a><figcaption>NodeJS Http Server &#8211; Simples Beispiel</figcaption></figure>



<p>Ich <strong>denke </strong>es ist <strong>an der Zeit</strong>, für ein wirklich (wirklich) <strong>simples Beispiel </strong>eines <strong>Node Http Servers</strong>.</p>



<p>Schauen wir uns <strong>erstmal </strong>an, <strong>was </strong>wir aus der Standard-Bibliothek von Node (Module) <strong>verwenden </strong>können.</p>



<p>Wer sucht wird <strong>relativ schnell </strong>fündig und stößt auf das gute alte <strong>&#8222;Http&#8220;-Modul</strong> – wer hätte es gedacht.</p>



<h3 class="wp-block-heading">Das Http-Modul</h3>



<p><strong>Um </strong>das &#8222;Http&#8220;-<strong>Modul </strong>zu &#8222;<strong>importieren</strong>&#8220; und verwenden zu können, legen wir <strong>wie üblich </strong>eine <strong>Konstante </strong>mit jeweiligem Namen <strong>an</strong>.</p>



<p><strong>Des Weiteren </strong>brauchen wir <strong>noch </strong>die für Node Programme <strong>typische </strong>&#8222;<strong>require</strong>&#8222;-Funktion, welche das Modul letztendlich <strong>importiert und </strong>als <strong>Rückgabewert </strong>zurückgibt.</p>



<p>Solche <strong>Module können </strong>wir natürlich auch <strong>selbst schreiben</strong>, allerdings ist das ein <strong>Thema für </strong>einen <strong>späteren </strong>Beitrag!</p>



<p><strong>Legen </strong>wir also <strong>nun </strong>die <strong>Konstante an </strong>und verwenden Diese anschließend:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="js" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">const http = require('http')</pre>



<p><strong>Natürlich </strong>verwende ich <strong>hier </strong>eine <strong>Konstante</strong>, <strong>statt </strong>einer <strong>normalen Variable (var)</strong> oder &#8222;scoped&#8220; Variable <strong>(let)</strong>, da sich der dort drin stehende <strong>Wert nicht verändern </strong>wird/soll!</p>



<h3 class="wp-block-heading">Der Request-Handler</h3>



<p><strong>Danach </strong>erstellen wir einen <strong>Request-Handler</strong>, Welcher <strong>jeweils </strong>einen Request (eine Anfrage an den Server) <strong>verarbeiten </strong>wird.</p>



<p><strong>Dieser Handler </strong>ist letztendlich <strong>nichts anderes als </strong>eine kleine <strong>Funktion</strong>, Welche <strong>2 Parameter</strong> mitgeliefert bekommt – der Request und die Response.</p>



<p><strong>Damit </strong>bekommen wir die <strong>Möglichkeit Daten vom Request</strong> zu <strong>lesen</strong>, bzw. Daten <strong>in </strong>die <strong>Response zu schreiben</strong>.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="js" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">const requestHandler = function (req, res) {
  res.writeHead(200, { 'Content-Type': 'application/json' })
  res.write("NodeJS Http Server")
  res.end()
}</pre>



<h3 class="wp-block-heading">Server erstellen und ausführen</h3>



<p><strong>Im letzten Schritt </strong>des einfachen Beispiels müssen wir <strong>nur noch </strong>einen &#8222;<strong>Server</strong>&#8220; mit Hilfe der &#8222;<strong>createServer</strong>&#8222;-Funktion des <strong>&#8222;Http&#8220;-Moduls</strong> erstellen.</p>



<p><strong>Danach </strong>können wir dem <strong>Server </strong>einfach nur noch <strong>sagen</strong>: &#8222;Hör&#8216; zu!&#8220; und schon <strong>läuft </strong>das Ding!</p>



<p>Wir legen <strong>zuerst zwei Konstanten</strong> fest, Welche eine kleine <strong>Art Konfiguration</strong> widerspiegeln.</p>



<p><strong>Dabei </strong>sagen wir dem Programm, auf <strong>welchen Port </strong>bzw. auf welchen <strong>Host</strong>&#8211;<strong>Namen </strong>es lauschen soll:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="js" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">const port = 8000
const host = 'localhost'</pre>



<p><strong>Nun erstellen </strong>wir den <strong>Server indem </strong>wir einfach wie angekündigt die &#8222;createServer&#8220;-<strong>Funktion </strong>des &#8222;Http&#8220;-Moduls <strong>aufrufen</strong>.</p>



<p><strong>Dann rufen </strong>wir nur noch die &#8222;<strong>listen</strong>&#8222;-<strong>Funktion auf </strong>und <strong>schön </strong>&#8222;hört&#8220; unser <strong>Server </strong>auf ankommende <strong>Anfragen</strong>.</p>



<p><strong>Um </strong>eine <strong>Art Status auszugeben</strong>, geben wir der &#8222;listen&#8220;-Funktion <strong>noch </strong>ein anonymes <strong>Callback </strong>mit, Welches <strong>bei Start </strong>des Servers <strong>aufgerufen </strong>wird.</p>



<p><strong>Hier könnten </strong>wir natürlich <strong>auch </strong>ähnlich <strong>wie </strong>mit dem &#8222;Request-Handler&#8220; verfahren <strong>und </strong>eine <strong>benannte Funktion</strong>, statt einer Anonymen verwenden..</p>



<pre class="EnlighterJSRAW" data-enlighter-language="js" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">const server = http.createServer(requestHandler)
server.listen(port, host, function () {
  console.log(`Listening for requests on https://${host}:${port}`)
})</pre>



<p><strong>Nun </strong>kannst Du die <strong>Anwendung </strong>z. B. <strong>in Visual Studio Code</strong> <strong>über </strong>die <strong>Konsole ausführen </strong>(oder Du verwendest die normale Windows/Mac Konsole/Terminal).</p>



<p><strong>Öffne </strong>in Visual Studio Code ein <strong>Terminal mit </strong>dem <strong>Hotkey </strong>&#8222;Strg+Shift+ö&#8220;, <strong>oder </strong>gehe oben <strong>über&#8217;s Menü</strong>.</p>



<p><strong>Dann </strong>musst Du den <strong>obigen Code</strong> nur noch <strong>in </strong>eine <strong>JavaScript-Datei</strong>, z. B. &#8222;index.js&#8220; stecken <strong>und </strong>mit &#8222;node index.js&#8220; (geht auch ohne &#8222;.js&#8220;) <strong>ausführen</strong>.</p>



<figure class="wp-block-image size-full is-resized"><a href="https://robbelroot.de/wp-content/uploads/2021/12/NodeJS-Http-Server-Ausgabe.png"><img loading="lazy" decoding="async" src="https://robbelroot.de/wp-content/uploads/2021/12/NodeJS-Http-Server-Ausgabe.png" alt="NodeJS Http Server - Ausgabe" class="wp-image-6953" width="418" height="192" title="NodeJS Http Server - Ausgabe"/></a><figcaption>NodeJS Http Server &#8211; Ausgabe</figcaption></figure>



<p>Wenn Du <strong>dann </strong>die <strong>konfigurierte Adresse </strong>&#8222;<strong><a href="https://localhost:8000" target="_blank" rel="noreferrer noopener">https://localhost:8000</a></strong>&#8220; <strong>besuchst</strong>, dürfest Du <strong>folgende Ausgabe </strong>sehen:</p>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2021/12/NodeJS-Http-Server-Web-Ausgabe.png"><img loading="lazy" decoding="async" width="261" height="83" src="https://robbelroot.de/wp-content/uploads/2021/12/NodeJS-Http-Server-Web-Ausgabe.png" alt="NodeJS Http Server - Web Ausgabe" class="wp-image-6960" title="NodeJS Http Server - Web Ausgabe"/></a></figure>



<h3 class="wp-block-heading">Fazit</h3>



<p><strong>Nun </strong>haben wir das simple <strong>Beispiel abgeschlossen</strong>, jedoch <strong>kommen </strong>in <strong>Zukunft </strong>noch weitere <strong>Problematiken </strong>auf uns zu.</p>



<p><strong>Diese kommen </strong>unter Anderem <strong>dann</strong>, <strong>wenn </strong>man mit <strong>einzelnen </strong>Routen/<strong>Endpunkten und auch </strong>z. B. einer <strong>Authentifizierung </strong>arbeiten möchte.</p>



<p>Mit dem <strong>aktuellen Stand </strong>könnten wir also <strong>keine wirklich </strong>sinnvolle, bzw. eher <strong>vielfältige Applikation </strong>bauen – zumindest nicht so easy..</p>



<p>Das <strong>aktuelle Skript </strong>arbeitet praktisch als &#8222;<strong>Catch-All-Route</strong>&#8222;, es <strong>arbeitet </strong>also <strong>jeden GET-Request</strong> bisher gleich ab.</p>



<p><strong>Egal ob </strong>wir &#8222;&lt;adresse&gt;/kunden&#8220;, <strong>oder </strong>&#8222;&lt;adresse&gt;/dashboard&#8220; aufrufen, es kommt <strong>immer </strong>das <strong>Gleiche </strong>als <strong>Antwort</strong>.</p>



<p>Das <strong>liegt </strong>natürlich <strong>daran</strong>, <strong>dass </strong>wir in dem obigen Skript <strong>in keiner Weise zwischen </strong>verschiedenen <strong>Endpunkten zu unterscheiden</strong>.</p>



<h3 class="wp-block-heading">Simpler NodeJS Http Server Code</h3>



<pre class="EnlighterJSRAW" data-enlighter-language="js" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">const http = require('http')
const requestHandler = function (req, res) {
  res.writeHead(200, { 'Content-Type': 'application/json' })
  res.write('NodeJS Http Server')
  res.end()
}
const port = 8000
const host = 'localhost'
const server = http.createServer(requestHandler)
server.listen(port, host, function () {
  console.log(`Listening for requests on https://${host}:${port}`)
})</pre>



<h2 class="wp-block-heading">Erweitertes NodeJS Http Server Beispiel im Selbstversuch</h2>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2021/12/NodeJS-Http-Server-Erweitertes-Beispiel.png"><img loading="lazy" decoding="async" width="698" height="465" src="https://robbelroot.de/wp-content/uploads/2021/12/NodeJS-Http-Server-Erweitertes-Beispiel.png" alt="NodeJS Http Server - Erweitertes Beispiel" class="wp-image-6983" title="NodeJS Http Server - Erweitertes Beispiel"/></a><figcaption>NodeJS Http Server &#8211; Erweitertes Beispiel</figcaption></figure>



<p><strong>Nachdem </strong>wir nun oben schon <strong>einige Fallstricke </strong>feststellen konnten, schauen wir uns <strong>im nächsten Abschnitt </strong>mal einen kleinen <strong>Selbstversuch </strong>an.</p>



<p>Wir <strong>schreiben </strong>uns eine eigene <strong>kleine Server</strong>&#8211;<strong>Klasse</strong>, mit dessen Hilfe wir <strong>verschiedene Request-Arten und Routen</strong> registrieren können.</p>



<p><strong>Wie </strong>Dir <strong>vielleicht bekannt </strong>ist, gibt es <strong>nicht nur </strong>die <strong>oben verwendete </strong>Http &#8222;GET&#8220;-<strong>Methode</strong>, <strong>sondern </strong>z. B. <strong>noch </strong>&#8222;POST&#8220;, &#8222;PUT&#8220;, &#8222;DELETE&#8220; und mehr.</p>



<p><strong>Ein Beispiel wäre ein </strong>&#8222;<strong>GET</strong>&#8222;-<strong>Request </strong>an den &#8222;/kunden&#8220;-Endpunkt, Welcher z. B. eine Suche signalisiert und eventuell noch Query-Parameter zur Filterung a la &#8222;?name=Max&#8220; entgegennehmen kann.</p>



<p><strong>Wenn man </strong>nun allerdings ein <strong>&#8222;POST&#8220;-Request</strong> an den &#8222;/kunden&#8220;-Endpunkt <strong>schickt</strong>, <strong>könnte man </strong>durch die Angabe passender Daten z. B. <strong>einen Kunden erstellen</strong>.</p>



<h3 class="wp-block-heading">Los geht&#8217;s – die jetzt benötigten Module</h3>



<p><strong>Bei </strong>dem <strong>erweiterten Beispiel</strong>-Server benötigen wir im Vergleich zu vorhin einige <strong>zusätzliche Module</strong>.</p>



<p>Wir <strong>möchten </strong>natürlich <strong>so viel </strong>Arbeit <strong>wie </strong>nur <strong>möglich an </strong>die <strong>Core</strong>-Module von NodeJS <strong>abgeben</strong>.</p>



<p><strong>Darunter fällt </strong>zum Beispiel das <strong>Verarbeiten</strong>, also das <strong>Parsen des Url</strong>-Strings, bestehend aus <strong>Endpunkt </strong>und <strong>Query</strong>&#8211;<strong>Parameter</strong>.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="js" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">const http = require('http'),
  url = require('url'),
  querystring = require('querystring')</pre>



<h3 class="wp-block-heading">Die Server-Klasse</h3>



<p><strong>Im Optimalfall </strong>stellt man sich die <strong>Konfiguration </strong>des Servers meiner Meinung nach <strong>so</strong> aktuell am besten vor:</p>



<pre class="wp-block-code"><code>- Server instanziieren
- Routen definieren
- Server lauschen lassen und Handler die Arbeit machen lassen</code></pre>



<p><strong>Daher </strong>werde ich den <strong>Server </strong>nach Möglichkeit genau <strong>so </strong>versuchen in kurzer Zeit zu <strong>bauen </strong>– damit es <strong>nicht den Rahmen sprengt</strong>.</p>



<p><strong>Selbstverständlich </strong>ist Deine eigene <strong>Kreativität gerne gesehen </strong>und <strong>keine Grenzen </strong>in Sicht, &#8222;do your thing&#8220; sag ich mal!</p>



<p><strong>Definieren </strong>wir also im <strong>ersten Schritt </strong>eine simple JavaScript-Klasse <strong>mit </strong>unserem <strong>gewünschten </strong>&#8222;Skelett&#8220;-Aufbau:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="js" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">class Server {
  constructor () {
    // doin' some constructional things
  }
  get () {
    // registering a GET route..
  }
  post () {
    // registering a POST route..
  }
  start () {
    // starting the server making it listening to requests
  }
}</pre>



<h4 class="wp-block-heading">Der Konstruktor</h4>



<p>Im <strong>Konstruktor </strong>des Servers <strong>übergeben </strong>wir die Haupt-<strong>Konfiguration</strong>, wie den <strong>Hostname und</strong> den <strong>Port</strong>.</p>



<p>Ggf. <strong>könnte </strong>man es <strong>auch </strong>hier <strong>mit </strong>einem <strong>&#8222;options&#8220;-Objekt</strong> gestalten, <strong>allerdings </strong>ist das für&#8217;s Erste nicht notwendig.</p>



<p><strong>Meistens bietet </strong>es sich aber tatsächlich <strong>an</strong>, <strong>da </strong>die <strong>Konfigurationsmöglichkeiten </strong>häufig von Zeit zu Zeit <strong>wachsen und</strong> man natürlich sowas wie <strong>7 Konstruktor-Parameter vermeiden</strong> sollte.</p>



<p><strong>Zuerst </strong>kümmern wir uns um <strong>Auflistung</strong>, Welche <strong>später </strong>die <strong>einzelnen </strong>registrierten <strong>Routen </strong>enthalten wird.</p>



<h5 class="wp-block-heading">Ein Workaround</h5>



<p>Ich <strong>habe </strong>hier <strong>bewusst </strong>eine <strong>anonyme Funktion mit &#8222;Arrow-Function&#8220;-Deklaration</strong> gewählt, um den &#8222;This-<strong>Scope</strong>&#8220; des <strong>Konstruktors </strong>zu behalten.</p>



<p>So <strong>komme </strong>ich <strong>kinderleicht an </strong>das &#8222;_routes&#8220; <strong>Feld</strong>/Eigenschaft – bau&#8216; dies gern nach Belieben um..</p>



<p><strong>Würde </strong>ich hingegen eine <strong>weitere Methode in </strong>der <strong>Klasse </strong>hinzufügen, würde ich <strong>innerhalb der Methode</strong> den <strong>Scope </strong>des &#8222;http&#8220;-Moduls haben (und somit nicht an die Routes kommen..).</p>



<p><strong>Nachdem </strong>die &#8222;<strong>createServer</strong>&#8222;-Funktion ihr Ding macht, <strong>nehmen </strong>wir noch <strong>Standardwerte für </strong>die <strong>Konfiguration </strong>(host, port) auf und setzen Sie <strong>ansonsten </strong>wie <strong>übergeben</strong>.</p>



<h5 class="wp-block-heading">Vorgehensweise</h5>



<p>Das <strong>Callback </strong>der &#8222;createServer&#8220;-Funktion <strong>loggt </strong>im ersten Schritt die <strong>besuchte Url inkl. Route</strong>, damit wir verfolgen können was passiert.</p>



<p><strong>Danach verarbeiten </strong>wir mit einer der oben angesprochenen Utility-Module die <strong>Request</strong>&#8211;<strong>Url</strong>.</p>



<p><strong>Somit </strong>können wir dann <strong>kinderleicht </strong>an den <strong>Pfad </strong>kommen (z. B. &#8222;/customers&#8220;) und <strong>müssen </strong>hier <strong>nicht nach </strong>dem <strong>Query-String schauen</strong>.</p>



<p><strong>Dieser </strong>kommt zu einem <strong>späteren Zeitpunkt </strong>noch bei z. B. der Filterung <strong>zum Einsatz</strong>.</p>



<p><strong>Ansonsten </strong>machen wir das, was viele Server machen, wenn Sie eine <strong>Url nicht finden </strong>können.</p>



<p>Sie <strong>melden </strong>einen <strong>404-Fehler</strong> und wir verlassen dann den Durchlauf mit einem &#8222;<strong>Early Return</strong>&#8222;!</p>



<p><strong>Falls </strong>die <strong>Route </strong>jedoch <strong>gefunden </strong>wird, sich also eine <strong>zum Pfad und zur Request-Methode passende Route</strong> in unserer Auflistung befindet, ziehen wir Diese.</p>



<p>Zum Schluss rufen wir dann den dafür registrierten Handler der Route auf und übergeben das <strong>Request- &amp; Response-Objekt</strong> als Parameter.</p>



<p>So <strong>können </strong>die <strong>Handler entscheiden</strong>, <strong>was </strong>Sie mit den dem jeweiligen Objekt <strong>machen </strong>und der <strong>zentralen Stelle </strong>oben <strong>obliegt </strong>einzig und allein die <strong>Delegation </strong>– schön!</p>



<pre class="EnlighterJSRAW" data-enlighter-language="js" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">// ..
constructor(host, port) {
    const routes = []
    this._routes = routes
    this._server = http.createServer((req, res) => {
      console.log(`[${req.method}] ${req.url}`)
      const requestUrl = url.parse(req.url)
      const route = routes.find(x => x.path === requestUrl.pathname &amp;&amp; x.method === req.method)
      if (!route) {
        res.writeHead(404, { 'Content-Type': 'application/json' })
        res.write('Route not found')
        res.end()
        return
      }
      route.handler(req, res)
    })
    this._host = host || 'localhost'
    this._port = port || 8000
  }
// ..</pre>



<h3 class="wp-block-heading">Ein paar Hilfsmethoden</h3>



<p><strong>Normalerweise </strong>bin ich <strong>kein Fan von </strong>komplexen <strong>Abfang-Szenarien</strong> in Beispiel-Codes, <strong>allerdings </strong>dürfte das hier relativ <strong>überschaubar </strong>sein, daher..</p>



<p>Wir <strong>definieren 3 Methoden</strong>, Welche die <strong>Überprüfung </strong>der notwendigen <strong>Argumente/Parameter</strong> bei einer Routen-Registrierung übernehmen.</p>



<p>Man hat ja <strong>schließlich keine Lust </strong>(und es ist schlechter Coding-Stil), alles <strong>5 mal zu schreiben</strong> – <strong>duplicated Code</strong>, bah!</p>



<h4 class="wp-block-heading"> <strong>_checkPath</strong>-Methode</h4>



<p><strong>Nun </strong>gibt es also die &#8222;<strong>_checkPath</strong>&#8222;-Methode, <strong>Welche </strong>einfach nur <strong>prüft</strong>, <strong>ob </strong>das übergebene <strong>Argument &#8222;ok&#8220;</strong> ist, also nicht &#8222;leer&#8220; und vom Typ String.</p>



<p><strong>Zusätzlich prüft </strong>die Methode noch, <strong>ob </strong>schonmal eine <strong>gleiche Route </strong>registriert wurde (unabhängig vom Handler..).</p>



<h4 class="wp-block-heading">_checkHandler-Methode</h4>



<p>Die &#8222;_checkHandler&#8220;-Methode <strong>prüft </strong>auch <strong>ob überhaupt </strong>etwas <strong>übergeben </strong>wurde <strong>und </strong>zusätzlich, <strong>ob </strong>es sich dabei auch um eine gewünschte <strong>Funktion </strong>handelt.</p>



<h4 class="wp-block-heading">_registerRoute-Methode</h4>



<p><strong>Als nächstes </strong>kommt das <strong>Routen-Helferlein</strong> zum Einsatz, Welches uns – wer hätte es gedacht.. – <strong>bei </strong>der <strong>Registrierung </strong>einer <strong>Route </strong>unterstützt.</p>



<p><strong>Auch hier </strong>gilt wieder die <strong>Vermeidung von duplicated Code</strong>, etc..</p>



<p>Es wird ein <strong>neues Route-Objekt</strong> mit Hilfe der angegebenen Parameter erstellt <strong>und </strong>der <strong>Auflistung hinzugefügt</strong>.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="js" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">  _checkPath(path, method) {
    if (!path || typeof path !== 'string') {
      throw new Error('No or invalid path specified')
    }
    const existentRoute = this._routes.find(x => x.path === path &amp;&amp; x.method === method)
    if (existentRoute) {
      throw new Error(`Route already registered [${method}] ${path}`)
    }
  }
  _checkHandler(handler) {
    if (!handler || typeof handler !== 'function') {
      throw new Error('No or invalid handler specified')
    }
  }
  _registerRoute(path, method, handler) {
    const route = {
      path,
      method,
      handler,
    }
    this._routes.push(route)
  }</pre>



<h3 class="wp-block-heading">Routen registrieren</h3>



<p>Im <strong>Folgenden Code </strong>werden <strong>zwei Möglichkeiten </strong>einer Routen-<strong>Registrierung </strong>definiert:</p>



<ul class="wp-block-list"><li>GET-Routen</li><li>POST-Routen</li></ul>



<pre class="EnlighterJSRAW" data-enlighter-language="js" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">  get(path, handler) {
    this._checkPath(path, 'GET')
    this._checkHandler(handler)
    this._registerRoute(path, 'GET', handler)
  }
  post(path, handler) {
    this._checkPath(path, 'POST')
    this._checkHandler(handler)
    this._registerRoute(path, 'POST', handler)
  }</pre>



<p><strong>Dabei </strong>wird bis auf die <strong>Request-Methode</strong> <strong>nicht </strong>wirklich etwas <strong>anderes </strong>gemacht, könnte man ggf. auch anders gestalten, aber cmon..</p>



<h3 class="wp-block-heading">Den Server starten</h3>



<p><strong>Um </strong>den Server zu <strong>starten</strong>, müssen wir auf das <strong>klasseninterne Feld</strong> namens &#8222;_server&#8220; zugreifen und dessen &#8222;<strong>listen</strong>&#8222;-Methode <strong>aufrufen</strong>.</p>



<p><strong>Ggf</strong>. <strong>könnte </strong>man hier noch mit irgendwelchen <strong>Zustands-Flags</strong> für einen noch zu <strong>implementierenden Stop </strong>realisieren.</p>



<p>Kommen wir <strong>nun </strong>zu einer <strong>Beispiel-Konfiguration</strong> <strong>und </strong>einer Art Kunden-<strong>API</strong>.</p>



<p><strong>Dazu erstelle </strong>ich eine (nicht persistente, nur im Server-Memory existierende) <strong>Kunden-Auflistung</strong>.</p>



<p><strong>Als nächstes </strong>instanziiere ich wie oben geplant eine neue <strong>Server</strong>&#8211;<strong>Instanz</strong>.</p>



<p>Im <strong>Anschluss </strong>werden die <strong>Routen registriert und </strong>der Server durch die &#8222;start&#8220;-Methode <strong>gestartet</strong>.</p>



<h4 class="wp-block-heading">Die Such-Route für die Kunden</h4>



<p>Die <strong>erste </strong>zu registrierende <strong>Route </strong>wäre die <strong>Such-Route für die Kunden</strong> (bzw. die Schnittstelle..).</p>



<p><strong>Pro Anfrage </strong>entsteht im ersten Schritt ein <strong>neues Array mit </strong>dem <strong>Inhalt </strong>der <strong>ursprünglichen </strong>&#8222;customers&#8220;-Auflistung.</p>



<p>Dann <strong>führen </strong>wir ein paar <strong>Prüfungen </strong>durch, <strong>ob </strong>es <strong>wirklich</strong> eine <strong>Suche </strong>ist, also <strong>ob </strong>wirklich <strong>Suchparameter übergeben </strong>wurden.</p>



<p><strong>Falls ja filtern </strong>wie die &#8222;responseCustomers&#8220; und weisen der gleichen Variable das neue Ergebnis zu.</p>



<p><strong>So </strong>könnte man Schritt für Schritt natürlich <strong>weitere Such-Möglichkeiten hinzufügen</strong>.</p>



<p><strong>Zum Schluss </strong>geben wir die <strong>Daten </strong>JSON-konform <strong>an </strong>den aufrufenden <strong>Client aus </strong>– fertig!</p>



<p><strong>Gerne </strong>darfst Du Dich daran versuchen, die <strong>fehlende POST-Route zu bauen</strong> *zwinker*.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="js" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">const customers = [
  {
    company: 'Nice Company ltd.'
  },
  {
    company: 'Another Company'
  },
]
const server = new Server()
server.get('/customers', (req, res) => {
  let responseCustomers = [...customers]
  const shouldFilter = req.url.includes('?') &amp;&amp; req.url.includes('=')
  if (shouldFilter) {
    const requestUrl = url.parse(req.url)
    const query = querystring.parse(requestUrl.query)
    const hasNameFilter = 'name' in query
    if (hasNameFilter) {
      const nameToFilter = (query['name'] || '').toLowerCase()
      if (nameToFilter) {
        responseCustomers = responseCustomers.filter(x => x.company.toLowerCase().includes(nameToFilter))
      }
    }
  }
  res.writeHead(200, { 'Content-Type': 'application/json' })
  res.write(JSON.stringify(responseCustomers))
  res.end()
})
server.post('/customers', (req, res) => {
  // to be done..
})
server.start()</pre>



<h3 class="wp-block-heading">Erweiterter NodeJS Http Server Code </h3>



<pre class="EnlighterJSRAW" data-enlighter-language="js" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">const http = require('http'),
  url = require('url'),
  querystring = require('querystring')

class Server {
  constructor(host, port) {
    this._routes = []
    this._server = http.createServer((req, res) => {
      console.log(`[${req.method}] ${req.url}`)
      const requestUrl = url.parse(req.url)
      const route = this._routes.find(x => x.path === requestUrl.pathname &amp;&amp; x.method === req.method)
      if (!route) {
        res.writeHead(404, { 'Content-Type': 'application/json' })
        res.write('Route not found')
        res.end()
        return
      }
      route.handler(req, res)
    })
    this._host = host || 'localhost'
    this._port = port || 8000
  }
  _checkPath(path, method) {
    if (!path || typeof path !== 'string') {
      throw new Error('No or invalid path specified')
    }
    const existentRoute = this._routes.find(x => x.path === path &amp;&amp; x.method === method)
    if (existentRoute) {
      throw new Error(`Route already registered [${method}] ${path}`)
    }
  }
  _checkHandler(handler) {
    if (!handler || typeof handler !== 'function') {
      throw new Error('No or invalid handler specified')
    }
  }
  _registerRoute(path, method, handler) {
    const route = {
      path,
      method,
      handler,
    }
    this._routes.push(route)
  }
  get(path, handler) {
    this._checkPath(path, 'GET')
    this._checkHandler(handler)
    this._registerRoute(path, 'GET', handler)
  }
  post(path, handler) {
    this._checkPath(path, 'POST')
    this._checkHandler(handler)
    this._registerRoute(path, 'POST', handler)
  }
  start() {
    this._server.listen(this._port, this._host, () => {
      console.log(`Listening for requests on https://${this._host}:${this._port}`)
    })
  }
}

const customers = [
  {
    company: 'Nice Company ltd.'
  },
  {
    company: 'Another Company'
  },
]
const server = new Server()
server.get('/customers', (req, res) => {
  let responseCustomers = [...customers]
  const shouldFilter = req.url.includes('?') &amp;&amp; req.url.includes('=')
  if (shouldFilter) {
    const requestUrl = url.parse(req.url)
    const query = querystring.parse(requestUrl.query)
    const hasNameFilter = 'name' in query
    if (hasNameFilter) {
      const nameToFilter = (query['name'] || '').toLowerCase()
      if (nameToFilter) {
        responseCustomers = responseCustomers.filter(x => x.company.toLowerCase().includes(nameToFilter))
      }
    }
  }
  res.writeHead(200, { 'Content-Type': 'application/json' })
  res.write(JSON.stringify(responseCustomers))
  res.end()
})
server.post('/customers', (req, res) => {

})
server.start()
</pre>



<h2 class="wp-block-heading">Du willst mehr!?</h2>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2021/12/NodeJS-Http-Server-Express-JS.jpg"><img loading="lazy" decoding="async" width="1280" height="853" src="https://robbelroot.de/wp-content/uploads/2021/12/NodeJS-Http-Server-Express-JS.jpg" alt="NodeJS Http Server - Komplexere Anwendungen mit Express JS" class="wp-image-6972" title="NodeJS Http Server - Komplexere Anwendungen mit Express JS"/></a><figcaption>NodeJS Http Server &#8211; Komplexere Anwendungen mit Express JS (Bild nicht offiziell)</figcaption></figure>



<p><strong>Wenn Du mehr willst</strong>, sprich Deine Anwendung wirklich <strong>komplex gestalten </strong>möchtest, kommst Du nicht um das <strong>non plus ultra Framework</strong> herum.</p>



<p><strong>Dabei </strong>handelt es sich <strong>um </strong>das in Node-Kreisen sehr <strong>bekannte ExpressJS Framework</strong>.</p>



<p><strong>Neben </strong>gewisse <strong>Basis-Funktionen</strong> <strong>wie </strong>die einfache <strong>Definition von Routen </strong>unterstützt ExpressJS <strong>auch </strong>noch ein Konzept namens &#8222;<strong>Middlewares</strong>&#8222;.</p>



<p><strong>Hierüber </strong>werde ich allerdings noch <strong>in </strong>einem <strong>getrennten Beitrag </strong>schreiben, da es sonst zu viel wird!</p>



<h2 class="wp-block-heading">Downloads</h2>



<div class="wp-block-buttons is-layout-flex wp-block-buttons-is-layout-flex">
<div class="wp-block-button"><a class="wp-block-button__link" href="/downloads/nodejs/HttpServerExample.zip" target="_blank" rel="noreferrer noopener">HttpServerExample.zip</a></div>



<div class="wp-block-button"><a class="wp-block-button__link" href="/downloads/nodejs/AdvancedHttpServerExample.zip" target="_blank" rel="noreferrer noopener">AdvancedHttpServerExample.zip</a></div>
</div>



<h2 class="wp-block-heading">Weiterführende Links</h2>



<ul class="wp-block-list"><li><strong><a href="https://robbelroot.de/blog/nodejs-verzeichnisse-mit-readdirsync-synchron-einlesen/" target="_blank" rel="noreferrer noopener">NodeJS Verzeichnisse mit readdirSync auslesen</a></strong></li><li><strong><a href="https://robbelroot.de/blog/wie-man-einen-nodejs-qrcode-scanner-erstellt/" target="_blank" rel="noreferrer noopener">NodeJS QRCode Scanner erstellen</a></strong></li></ul>
<p>Der Beitrag <a href="https://robbelroot.de/blog/wie-man-einen-nodejs-http-server-erstellt/">Wie man einen NodeJS Http Server erstellt</a> erschien zuerst auf <a href="https://robbelroot.de">Robert Skibbe</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://robbelroot.de/blog/wie-man-einen-nodejs-http-server-erstellt/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
		<item>
		<title>VB NET Web API &#8211; Währungskurs Service Konsum von Grund auf erklärt</title>
		<link>https://robbelroot.de/blog/vb-net-web-api-waehrungskurs-service-konsum-von-grund-auf-erklaert/</link>
					<comments>https://robbelroot.de/blog/vb-net-web-api-waehrungskurs-service-konsum-von-grund-auf-erklaert/#comments</comments>
		
		<dc:creator><![CDATA[Robert Skibbe]]></dc:creator>
		<pubDate>Wed, 29 Sep 2021 16:34:25 +0000</pubDate>
				<category><![CDATA[Allgemein]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[Visual Basic .NET]]></category>
		<category><![CDATA[Visual Basic .NET Problemlösungen]]></category>
		<category><![CDATA[anfrage]]></category>
		<category><![CDATA[api]]></category>
		<category><![CDATA[async]]></category>
		<category><![CDATA[consume]]></category>
		<category><![CDATA[convert]]></category>
		<category><![CDATA[deserialize]]></category>
		<category><![CDATA[get]]></category>
		<category><![CDATA[http]]></category>
		<category><![CDATA[https]]></category>
		<category><![CDATA[json]]></category>
		<category><![CDATA[jsonconvert]]></category>
		<category><![CDATA[konsum]]></category>
		<category><![CDATA[load]]></category>
		<category><![CDATA[method]]></category>
		<category><![CDATA[net]]></category>
		<category><![CDATA[newtonsoft]]></category>
		<category><![CDATA[nuget]]></category>
		<category><![CDATA[object]]></category>
		<category><![CDATA[request]]></category>
		<category><![CDATA[schnittstelle]]></category>
		<category><![CDATA[serialize]]></category>
		<category><![CDATA[service]]></category>
		<category><![CDATA[task]]></category>
		<category><![CDATA[vb.net]]></category>
		<category><![CDATA[vbnet]]></category>
		<category><![CDATA[visual basic]]></category>
		<category><![CDATA[visual basic net]]></category>
		<category><![CDATA[web]]></category>
		<guid isPermaLink="false">https://robbelroot.de/?p=6176</guid>

					<description><![CDATA[<p>VB NET Web API – Web API Konsum von Grund auf erklärt Heute erwartet Dich ein ganz besonderer und von vielen Abonnenten gewünschter Beitrag – die Implementierung einer VB NET Web API. Es handelt sich genauer genommen um die Erstellung eines Clients, Welcher gewünschte Daten aus einer Web-Schnittstelle abrufen kann. &#8230;</p>
<p>Der Beitrag <a href="https://robbelroot.de/blog/vb-net-web-api-waehrungskurs-service-konsum-von-grund-auf-erklaert/">VB NET Web API &#8211; Währungskurs Service Konsum von Grund auf erklärt</a> erschien zuerst auf <a href="https://robbelroot.de">Robert Skibbe</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2021/09/thumbnail-1.jpg"><img loading="lazy" decoding="async" width="1920" height="1080" src="https://robbelroot.de/wp-content/uploads/2021/09/thumbnail-1.jpg" alt="" class="wp-image-6178"/></a><figcaption>VB NET Web API Konsum – Währungskurse umrechnen</figcaption></figure>






<h2 class="wp-block-heading">VB NET Web API – Web API Konsum von Grund auf erklärt</h2>



<p><strong>Heute </strong>erwartet Dich ein <strong>ganz besonderer </strong>und von vielen Abonnenten gewünschter <strong>Beitrag</strong> – die Implementierung einer VB NET Web API.</p>



<p>Es handelt sich genauer genommen um die <strong>Erstellung </strong>eines <strong>Clients</strong>, Welcher <strong>gewünschte Daten aus </strong>einer <strong>Web</strong>-Schnittstelle <strong>abrufen </strong>kann.</p>



<p>Die <strong>Web-API</strong> <strong>arbeitet</strong> dabei <strong>nach </strong>dem üblichen <strong>Standard</strong>, Sie gibt <strong>JSON</strong>-Daten zurück, <strong>Welche </strong>wir dann <strong>noch </strong>clientseitig <strong>verarbeiten </strong>müssen.</p>



<p><strong>Letztendlich </strong>ist der <strong>Client </strong>natürlich nichts anderes als eine <strong>VB NET Klasse</strong>, bzw. eher gesagt eine <strong>Instanz </strong>davon.</p>



<h2 class="wp-block-heading">Auf YouTube ansehen –  VB NET Web API</h2>



<p><strong>Falls </strong>Du die <strong>visuelle Darstellung</strong>, bzw. Erklärung des Beitrages <strong>bevorzugst</strong>, <strong>kannst </strong>Du natürlich auch das dementsprechende <strong>Video anschauen</strong>.</p>



<iframe loading="lazy" width="560" height="315" src="https://www.youtube-nocookie.com/embed/JAbcvXduGJ4" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe>



<style>
.margin-after-video-block {
  margin-top: 1em;
}
</style>



<h2 class="margin-after-video-block wp-block-heading">Ursprung und Idee zum Beitrag &#8211; VB NET Web API</h2>



<p>Den <strong>ursprünglichen Anreiz </strong>zum Video habe ich – wie fast immer – durch den <strong>eigenen Bedarf </strong>dazu gehabt.</p>



<p>Ich <strong>baue </strong>mir aktuell ein <strong>kleines Tool</strong>, Welches mir bei meiner Arbeit mit dem <strong>Staking von Kryptowährungen </strong>helfen soll.</p>



<p><strong>Hier </strong>zeige ich Dir mal einen <strong>kleinen Ausschnitt</strong>, beachte jedoch, dass das Tool hier <strong>nicht weiter aufgegriffen </strong>wird:</p>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2021/09/VB.NET-Web-API-CakeStats-Staking-Tool.gif"><img loading="lazy" decoding="async" width="273" height="274" src="https://robbelroot.de/wp-content/uploads/2021/09/VB.NET-Web-API-CakeStats-Staking-Tool.gif" alt="VB.NET Web-API - CakeStats Staking Tool" class="wp-image-6200" title="VB.NET Web-API - CakeStats Staking Tool"/></a><figcaption>VB.NET Web-API &#8211; CakeStats Staking Tool</figcaption></figure>



<p><strong>Bisher </strong>musst ich <strong>bei Bedarf </strong>immer die einzelnen <strong>Werte und Positionen selbst errechnen</strong>, <strong>nun </strong>habe ich dafür letztendlich <strong>ein </strong>Mini-<strong>Tool </strong>gebaut.</p>



<p><strong>Bewusst </strong>in der <strong>unteren</strong>, <strong>rechten </strong>Ecke <strong>positioniert</strong>, sollte es als <strong>eine Art Widget </strong>im Hintergrund funktionieren.</p>



<p><strong>Bei Bedarf </strong>sollte es mir dann die gesammelten/verarbeiteten <strong>Informationen </strong>aufbereitet <strong>darstellen</strong>.</p>



<h2 class="wp-block-heading">Gedanken zum Start</h2>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2021/09/BackgroundWorker-starten.jpg"><img loading="lazy" decoding="async" width="640" height="360" src="https://robbelroot.de/wp-content/uploads/2021/09/BackgroundWorker-starten.jpg" alt="VB.NET Web API - Start" class="wp-image-5991" title="VB.NET Web API - Start"/></a><figcaption> VB NET Web API &#8211; Start</figcaption></figure>



<p>Bei den <strong>initialen Gedanken </strong>bezüglich des Projektstarts, kann man natürlich <strong>einiges </strong>einbeziehen.</p>



<p>Ich spreche hier unter anderem von Konzepten wie z. B. die <strong>Dependency-Injection</strong>, bzw. auch kurz <strong>DI</strong> genannt.</p>



<p><strong>Als nächstes </strong>sollte man sich vermutlich über die <strong>restliche Infrastruktur</strong> der App Gedanken machen.</p>



<p>Hast Du<strong> eventuell das MVVM-Entwurfsmuster</strong> für Deine Anwendung <strong>eingeplant</strong>, <strong>oder </strong>möchtest Du &#8222;<strong>quick </strong>and <strong>dirty</strong>&#8220; durchstarten?</p>



<p>In meinem <strong>Beitrag über </strong>das <strong><a href="https://robbelroot.de/blog/mvvm-csharp/" target="_blank" rel="noreferrer noopener">MVVM-Entwurfsmuster</a></strong> kannst Du mehr darüber erfahren und detailliert <strong>nachlesen</strong>.</p>



<p>Möchtest Du eventuell <strong>grafisch ansprechender </strong>arbeiten und ein GUI-Framework wie Mahapps-Metro verwenden?</p>



<p><strong>Dann </strong>schaue Dir ggf. <strong>folgende Beiträge </strong>über Mahapps Metro an: <strong><a href="https://robbelroot.de/blog/mahapps-metro-projekt-aufsetzen/" target="_blank" rel="noreferrer noopener">Mahapps Metro Projekt aufsetzen</a></strong>.</p>



<h2 class="wp-block-heading">Wegfallendes &amp; Veränderungen</h2>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2021/09/Aenderungen-und-Updates-in-der-Softwarebranche-1.jpg"><img loading="lazy" decoding="async" width="640" height="360" src="https://robbelroot.de/wp-content/uploads/2021/09/Aenderungen-und-Updates-in-der-Softwarebranche-1.jpg" alt="Änderungen und Updates in der Softwarebranche" class="wp-image-6218" title="Änderungen und Updates in der Softwarebranche"/></a><figcaption>Änderungen und Updates in der Softwarebranche</figcaption></figure>



<p>Viele <strong>Entwickler </strong>arbeiten bei einem <strong>Projekt </strong>zuerst einmal an einem &#8222;<strong><a href="https://de.wikipedia.org/wiki/Minimum_Viable_Product" target="_blank" rel="noreferrer noopener">Minimum Viable Product&#8220;, kurz MVP.</a></strong></p>



<p>Die <strong>Welt der Programmierung</strong> befindet sich in einem <strong>permanenten Wandel </strong>und nicht anders geht es Deinem Projekt.</p>



<p>Man <strong>möchte Kunden</strong>, <strong>Investoren</strong>, oder auch <strong>einfach Vorgesetzten </strong>ein <strong>schnelles </strong>und praxisnahes <strong>Beispiel </strong>des Projektes vorzeigen können.</p>



<p><strong>Oftmals resultiert </strong>dies <strong>aus </strong>bestehendem <strong>Projektdruck</strong>, anderen <strong>wartenden Projekten</strong>, <strong>ungeduldigen Kunden</strong>, usw.</p>



<p>Da es sich hierbei allerdings um ein <strong>privates Projekt </strong>handelt, habe ich mich für eine <strong>hybride, bzw. einfache Lösung </strong>entschieden.</p>



<p>Ich habe daher <strong>als Basis </strong>ein kleines <strong>Interface </strong>erstellt, wovon sich dann <strong>Implementierungen ergeben</strong> können.</p>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2021/09/Offline-APIs-und-Preisgestaltung-1.jpg"><img loading="lazy" decoding="async" width="640" height="360" src="https://robbelroot.de/wp-content/uploads/2021/09/Offline-APIs-und-Preisgestaltung-1.jpg" alt="Offline APIs und Preisgestaltung" class="wp-image-6225" title="Offline APIs und Preisgestaltung"/></a><figcaption>Offline APIs und Preisgestaltung</figcaption></figure>



<p><strong>Man weiß</strong> <strong>nie</strong>, <strong>welche </strong>Webseiten, bzw. <strong>Schnittstellen </strong>irgendwann ihren <strong>Dienst quittieren</strong>.</p>



<p><strong>Ebenso </strong>weiß man <strong>häufig nicht</strong>, inwiefern sich <strong>Preismodelle verändern</strong>, da sich auch <strong>kostenlose </strong>Modelle der Wirtschaftlichkeit <strong>anpassen </strong>müssen.</p>



<p><strong>Besonders ehemals kostenlose </strong>&#8222;Subsciption-Plans&#8220; werden <strong>irgendwann kostenpflichtig </strong>und <strong>bestehende </strong>Pläne werden <strong>teurer</strong>.</p>



<p><strong>Wenn </strong>solche <strong>Veränderungen eintreten </strong>muss bestehende <strong>Software </strong>im Optimalfall natürlich <strong>gut gebaut </strong>sein.</p>



<p>Sie <strong>muss </strong>über eine <strong>gute Infrastruktur </strong>und Planung verfolgen, um auf eventuelle Änderungen reagieren zu können.</p>



<p><strong>Dabei </strong>sollte Sie <strong>effizient und einfach </strong>umgestellt werden können und <strong>erfolgte Änderungen </strong>sollten <strong>einfach getestet </strong>werden können.</p>



<h2 class="wp-block-heading">Vorbereitungen für die VB NET Web API</h2>



<p><strong>Um </strong>dieses Tutorial <strong>erfolgreich abschließen </strong>zu können, musst Du vorher noch einige Vorbereitungen treffen.</p>



<p>Du brauchst <strong>im ersten Schritt</strong> einen <strong>Account </strong>für den verwenden <strong>Web-Service</strong> namens &#8222;<strong>exchangeratesapi</strong>&#8222;.</p>



<p><strong>Besuche </strong>dafür einfach die <strong>Website </strong>namens <strong><a href="https://exchangeratesapi.io" target="_blank" rel="noreferrer noopener">exchangeratesapi.io</a></strong> und erstelle Dir einen kostenlosen Account im &#8222;Free Subscription Plan&#8220;.</p>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2021/09/exchangeratesapi.io-Registrierung.png"><img loading="lazy" decoding="async" width="1181" height="737" src="https://robbelroot.de/wp-content/uploads/2021/09/exchangeratesapi.io-Registrierung.png" alt="exchangeratesapi.io Registrierung – Free Subscription Plan" class="wp-image-6227" title="exchangeratesapi.io Registrierung – Free Subscription Plan"/></a><figcaption>exchangeratesapi.io Registrierung – Free Subscription Plan</figcaption></figure>



<p>Der <strong>kostenlose Plan</strong> von exchangeratesapi.io bietet Dir die Möglichkeit <strong>250 Anfragen im Monat kostenlos</strong> zu nutzen.</p>



<p><strong>Wenn </strong>Du die <strong>Registrierung abgeschlossen </strong>und Deinen <strong>API-Key erhalten</strong> hast, können wir <strong>fortfahren</strong>.</p>



<h2 class="wp-block-heading">Los geht&#8217;s</h2>



<p><strong>Hier </strong>starten wir mit der <strong>Basis </strong>des <strong>Codes </strong>und setzen die <strong>ersten Überlegungen </strong>um.</p>



<p><strong>Wie </strong>oben schon <strong>erwähnt </strong>wird es ein <strong>Interface als </strong>kleine <strong>Basis </strong>geben:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Public Interface IExchangeRateService

    Function GetExchangeRateAsync(baseCurrency As String, targetCurrency As String) As Task(Of Double)

End Interface</pre>



<p><strong>Dieses stellt </strong>in der absoluten &#8222;easy-to-go&#8220;-Version nur <strong>eine einzige Funktion bereit </strong>– &#8222;GetExchangeRateAsync&#8220;.</p>



<p><strong>Die Funktion </strong>soll uns den <strong>Wechselkurs der </strong>jeweiligen <strong>Basis</strong>-Währung <strong>in </strong>die angegebene <strong>Ziel</strong>&#8211;<strong>Währung liefern</strong>.</p>



<p>Wie Du <strong>in </strong>der <strong>Deklaration </strong>erkennen kannst, <strong>übergeben </strong>wir die <strong>beiden </strong>Währungen <strong>als Parameter vom Typ String</strong>.</p>



<p>Des Weiteren <strong>gibt </strong>die <strong>Funktion </strong>keinen simplen Double-Wert, <strong>sondern </strong>eine <strong><a href="https://docs.microsoft.com/de-de/dotnet/api/system.threading.tasks.task?view=net-5.0" target="_blank" rel="noreferrer noopener">Task</a> mit </strong>einem <strong>generischen Parameter </strong>vom Typ <strong><a href="https://docs.microsoft.com/de-de/dotnet/api/system.double?view=net-5.0" target="_blank" rel="noreferrer noopener">Double</a></strong> zurück.</p>



<p>Ich <strong>bevorzuge </strong>die <strong>asynchrone Arbeitsweise</strong>, daher wird die Funktion <strong>beispielhaft wie folgt </strong>aufgerufen:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Private Async Task LoadExampleDataAsync()
    Dim exchangeRate As Double = Await theService.GetExchangeRateAsync("EUR", "USD")
End Sub</pre>



<p><strong>Auch bei </strong>der <strong>Bezeichnung </strong>der Variante sollte man <strong>natürlich </strong>auf die &#8222;<strong>Asynchronität</strong>&#8220; eingehen.</p>



<p><strong>In </strong>der VB <strong>NET Welt </strong>hat es sich eingebürgert, <strong>asynchrone Funktionalitäten mit </strong>einem &#8222;<strong>Async</strong>&#8222;-<strong>Postfix </strong>zu <strong>kennzeichnen</strong>.</p>



<p><strong>Möchte </strong>man <strong>stattdessen </strong>die <strong>synchrone </strong>Variante verwenden, kann man <strong>dafür </strong>natürlich auch einfach <strong>folgenden Code </strong>verwenden:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Private LoadExampleDataSync()
    Dim exchangeRate As Double = theService.GetExchangeRateAsync("EUR", "USD").Wait()
End Sub</pre>



<p>Die oben genannte Schnittstelle <strong>wird </strong>dann <strong>von </strong>jeweiligen <strong>ExchangeRateServices </strong>implementiert – <strong>vorerst </strong>jedoch nur <strong>von Einem</strong>.</p>



<h2 class="wp-block-heading">Konkrete Implementierung des Services</h2>



<p><strong>Mit </strong>dem <strong>Status quo </strong>gibt es<strong> </strong>nur <strong>eine </strong>&#8222;Service-<strong>Möglichkeit</strong>&#8222;, also eine <strong>konkrete Implementierung </strong>des Interfaces.</p>



<p>Dabei handelt es sich um die <strong>Web-Dienstleistung</strong> der <strong>oben </strong>genannten <strong>Seite</strong>, Welche uns als Daten-Lieferant dient.</p>



<p><strong>Selbstverständlich könnten </strong>wir auch <strong>genauso </strong>gut <strong>mehrere Anbieter heraussuchen </strong>und Diese dann <strong>in </strong>eigenen <strong>Services implementieren</strong>.</p>



<p>Im <strong>folgenden Bild </strong>versuche ich diese <strong>Gegebenheit </strong>ein wenig besser <strong>darzustellen</strong>:</p>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2021/09/VB.NET-Web-API-ExchangeRateServiceDiagram.jpg"><img loading="lazy" decoding="async" width="841" height="471" src="https://robbelroot.de/wp-content/uploads/2021/09/VB.NET-Web-API-ExchangeRateServiceDiagram.jpg" alt="VB.NET Web-API - ExchangeRateServiceDiagram" class="wp-image-6259" title="VB.NET Web-API - ExchangeRateServiceDiagram"/></a><figcaption>VB.NET Web-API &#8211; ExchangeRateServiceDiagram</figcaption></figure>



<h3 class="wp-block-heading">Klasse erstellen – Für ExchangeRatesApi.io</h3>



<p>Erstelle also <strong>im nächsten Schritt </strong>eine eigene <strong>Klasse</strong>, in der wir dann beginnen, den <strong>Web-Dienst und</strong> unser <strong>Interface </strong>zu <strong>implementieren</strong>.</p>



<p>Die <strong>Bezeichnung bleibt </strong>hier natürlich <strong>Dir überlassen</strong>, man <strong>könnte </strong>hier den <strong>Hersteller </strong>des Web-Dienstes in irgendeiner Form <strong>einbringen</strong>.</p>



<p><strong>Damit </strong>würde man ggf. <strong>klarer darstellen</strong>, <strong>dass </strong>es sich um die konkrete Implementierung <strong>für diese </strong>eine <strong>Website </strong>handelt.</p>



<p>Der <strong>Einfachheit halber </strong>und <strong>mangels </strong>anderer <strong>Implementierungen </strong>belasse ich es <strong>bei </strong>einem <strong>simplen Namen</strong>.</p>



<p><strong>Implementiere </strong>anschließend das <strong>oben </strong>gezeigte <strong>Interface </strong>und Du solltest den gleich <strong>folgenden Stand </strong>haben.</p>



<p><strong>Tippe </strong>dazu einfach &#8222;<strong>Implements</strong>&#8220; in die nächstfolgende <strong>Zeile nach </strong>dem <strong>Klassennamen </strong>und <strong>gebe </strong>den <strong>Namen </strong>des Interfaces ein.</p>



<p><strong>Danach </strong>kannst Du das gewünschte Interface ggf. schon <strong>durch Autokorrektur bestätigen</strong>.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Public Class ExchangeRateService
    Implements IExchangeRateService

    Public Function GetExchangeRateAsync(baseCurrency As String, targetCurrency As String) As Task(Of Double)
       
    End Function

End Class</pre>



<h2 class="wp-block-heading">Mit dem S aus &#8222;SOLID&#8220; im Kopf</h2>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2021/09/Single-Reponsibility-Principle-in-SOLID.jpg"><img loading="lazy" decoding="async" width="640" height="360" src="https://robbelroot.de/wp-content/uploads/2021/09/Single-Reponsibility-Principle-in-SOLID.jpg" alt="Single Reponsibility Principle in SOLID" class="wp-image-6275" title="Single Reponsibility Principle in SOLID"/></a><figcaption>Single Reponsibility Principle in SOLID</figcaption></figure>



<p>Mit dem &#8222;Single Responsibility&#8220;-<strong>Prinzip</strong>, <strong>Welches </strong>sich bei dem Akronym &#8222;SOLID&#8220; <strong>hinter </strong>dem Buchstaben &#8222;<strong>S</strong>&#8220; verbirgt im Kopf, arbeiten wir <strong>weiter an </strong>der <strong>Klasse</strong>.</p>



<p>Die <strong>Bedeutung </strong>des Prinzips ist <strong>letztendlich</strong> grob gesagt, <strong>dass </strong>eine <strong>Klasse </strong>jeweils <strong>nur einen Zweck </strong>haben sollte.</p>



<p><strong>Inwiefern </strong>viele <strong>Entwickler diesen </strong>Interpretations-Raum <strong>ausschöpfen</strong>, oder <strong>regulieren</strong>, mag erstmal <strong>dahingestellt </strong>sein.</p>



<p><strong>In unserem Fall hat </strong>die <strong>Klasse </strong>ja z. B. einen <strong>API-Key</strong>, <strong>Welchen </strong>Sie verwenden muss, <strong>um </strong>bei der Web-Schnittstelle <strong>authentifiziert </strong>zu werden.</p>



<p><strong>Diesen API-Key zu laden</strong>, <strong>ist </strong>allerdings eigentlich <strong>nicht </strong>die <strong>Aufgabe </strong>der <strong>Klasse </strong>selbst, <strong>sondern </strong>eher einer &#8222;Configuration&#8220;-like Klasse.</p>



<p>Die &#8222;<strong>Configuration</strong>&#8222;-<strong>Klasse </strong>könnte natürlich <strong>auch </strong>wieder ein <strong>Interface </strong>mit &#8222;Get&#8220;- und &#8222;Set&#8220;-Methoden implementieren.</p>



<p>Man <strong>könnte </strong>die <strong>Konfiguration </strong>im <strong>ersten Schritt </strong>durch die <strong>NET Settings</strong> realisieren, <strong>danach </strong>vielleicht auf <strong>Datenbank</strong>-, <strong>oder </strong>gar auf <strong>Web</strong>-Ebene.</p>



<p><strong>So </strong>würde alles schön <strong>sauber</strong>, <strong>separat </strong>und wart-, bzw. <strong>testbar </strong>sein – schön!</p>



<h2 class="wp-block-heading">Basis-Daten festlegen</h2>



<p><strong>Statt </strong>der eigenen Konfigurations-<strong>Klasse verwenden </strong>wir der Einfachheit halber einfach <strong>konstante Strings</strong>.</p>



<p>Diese <strong>definieren </strong>dann die benötigten <strong>Daten</strong>, <strong>wie </strong>z. B. den API-<strong>Schlüssel und </strong>die Basis-<strong>URL </strong>an Welche die Anfragen gesendet werden müssen.</p>



<p>Die <strong>Daten </strong>selbst <strong>verwenden </strong>wir dann später, <strong>um korrekt </strong>formatierte/aufgebaute <strong>Anfragen </strong>zu <strong>erstellen</strong>.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Public Const API_KEY As String = "&lt;myApiKey>"
Public Const BASE_URL As String = "https://api.exchangeratesapi.io/v1"</pre>



<h2 class="wp-block-heading">Ein Singleton, Welcher keiner ist – lol</h2>



<p>In <strong>Vielen verschiedenen Sprachen </strong>sollte man <strong><a href="https://de.wikipedia.org/wiki/Singleton_(Entwurfsmuster)" target="_blank" rel="noreferrer noopener">Singletons</a></strong> für Zugriffe auf das Web, also durch <strong><a href="https://de.wikipedia.org/wiki/Hypertext_Transfer_Protocol#HTTP_GET" target="_blank" rel="noreferrer noopener">GET</a></strong>-, <strong><a href="https://de.wikipedia.org/wiki/Hypertext_Transfer_Protocol#HTTP_POST" target="_blank" rel="noreferrer noopener">POST</a></strong>-, etc. Methoden erstellen.</p>



<p>Es <strong>macht keinen Sinn</strong>, für <strong>jede </strong>einzelne <strong>Anfrage </strong>einen <strong>weiteren &#8222;HttpClient&#8220; </strong>zu erzeugen, <strong>sondern </strong>eher den <strong>Selben </strong>erneut zu benutzen.</p>



<p><strong>Soweit </strong>ich mich <strong>erinnern </strong>kann, <strong>steht </strong>das <strong>sogar in </strong>der <strong>Dokumentation </strong>zum Client drin.</p>



<p><strong>Als </strong>ich <strong>damals </strong>mit Java <strong>für </strong>die <strong>Android</strong>-Entwicklung gearbeitet habe, <strong>war </strong>es <strong>dort </strong>übrigens <strong>auch so</strong>.</p>



<p><strong>Mittlerweile </strong>hat <strong>Google </strong>glaube ich <strong>selbst </strong>die Steuerung <strong>übernommen</strong>, <strong>damit </strong>man dies praktisch <strong>nicht mehr selbst </strong>realisieren muss.</p>



<p><strong>Schnell und einfach </strong>habe ich hier einfach <strong>folgenden Code </strong>verwendet:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Imports System.Net.Http

Public Class Http
  
  Public Shared &lt;ReadOnly> Client As HttpClient = New HttpClient()

End Class</pre>



<p>Dieser <strong>Code sorgt </strong>zwar <strong>nicht dafür</strong>, <strong>dass </strong>der <strong>Client nicht </strong>einfach <strong>neu gesetzt </strong>werden <strong>könnte</strong>, <strong>macht </strong>aber denke ich den Part der <strong>Wiederverwendung</strong> <strong>klar</strong>.</p>



<p>Setze ggf. einfach einen <strong>Readonly-Modifizierer</strong> <strong>vor </strong>den Namen des <strong>Clients</strong>.</p>



<h2 class="wp-block-heading">Den Request zusammenbauen – VB NET Web API</h2>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2021/09/exchangeratesapi-Server-Request.jpg"><img loading="lazy" decoding="async" width="640" height="360" src="https://robbelroot.de/wp-content/uploads/2021/09/exchangeratesapi-Server-Request.jpg" alt="ExchangeRatesApi Server Request - VB NET Web API" class="wp-image-6285" title="ExchangeRatesApi Server Request - VB NET Web API"/></a><figcaption>ExchangeRatesApi Server Request &#8211; VB NET Web API</figcaption></figure>



<p>Wir <strong>können </strong>natürlich <strong>nicht einfach irgendwelche Anfragen </strong>an irgendwelche URLs <strong>schicken</strong>, <strong>sondern müssen </strong>uns irgendwo an den <strong>korrekten Aufbau halten</strong>.</p>



<p>Die <strong>oben definierte Basis-URL</strong> <strong>dient </strong>schonmal wie der Name sagt <strong>als Basis </strong>für das Ganze.</p>



<p>Im <strong>nächsten Schritt </strong>müssen wir in der Dokumentation <strong>herausfinden</strong>, <strong>welchen </strong>sogenannten <strong>Endpunkt </strong>wir verwenden müssen.</p>



<p>In <strong>unserem Fall </strong>ist der korrekte <strong>Endpunkt </strong>der &#8222;<strong>/latest</strong>&#8222;-Endpunkt, <strong>Welcher </strong>natürlich <strong>noch </strong>zusätzliche <strong>Daten </strong>übermittelt bekommen <strong>möchte</strong>.</p>



<p><strong>Unsere Funktion</strong> <strong>muss </strong>also nun einen <strong>GET-Request</strong> <strong>an </strong>den genannten <strong>Endpunkt senden</strong>.</p>



<p><strong>Aus </strong>der <strong>Dokumentation </strong>geht hervor, dass <strong>jeder </strong>(gesicherte) <strong>Endpunkt </strong>unseren <strong>API-Key</strong> in Form eines <strong>Query</strong>&#8211;<strong>Parameters </strong>übergeben <strong>bekommen </strong>möchte.</p>



<p>Des <strong>Weiteren braucht </strong>der <strong>Endpunkt </strong>die Information, welche <strong>Basis-Währung</strong> verwendet werden soll.</p>



<p><strong>Standardmäßig </strong>kann man <strong>im Free-Plan</strong> leider <strong>nur Euro </strong>verwenden, ich <strong>werde </strong>die <strong>Implementierung</strong> des Services natürlich <strong>trotzdem korrekt gestalten</strong>.</p>



<p><strong>Behalte </strong>allerdings deshalb <strong>im</strong> <strong>Kopf</strong>, <strong>dass </strong>Du <strong>nur </strong>&#8222;<strong>EUR</strong>&#8220; als Basis-Währung <strong>übermitteln kannst </strong>und Du sonst vermutlich einen Fehler bekommen wirst.</p>



<p><strong>Alternativ </strong>könntest Du den <strong>Parameter </strong>auch eventuell <strong>weglassen </strong>und die <strong>Web-Schnittstelle</strong> <strong>würde </strong>so automatisch &#8222;<strong>EUR</strong>&#8220; <strong>ziehen</strong>.</p>



<p><strong>Gleich </strong>findest Du einen <strong>möglichen Aufruf</strong>, bzw. eine <strong>mögliche Verwendung </strong>der bekannten Aspekte.</p>



<p><strong>Zuerst wandle </strong>ich die übergebenen <strong>Währungen </strong>(wie Sie üblich benötigt werden) <strong>in Großbuchstaben </strong>um (eur -&gt; EUR).</p>



<h3 class="wp-block-heading">Query-Parameter</h3>



<p><strong>Danach </strong>mache ich mir den <strong>Rückgabewert </strong>der <strong><a href="https://docs.microsoft.com/de-de/dotnet/api/system.web.httputility.parsequerystring?view=net-5.0" target="_blank" rel="noreferrer noopener">ParseQueryString</a></strong>-Funktion der <strong><a href="https://docs.microsoft.com/de-de/dotnet/api/system.web.httputility?view=net-5.0" target="_blank" rel="noreferrer noopener">HttpUtility</a></strong>-Klasse zu Nutze.</p>



<p><strong>Daraus </strong>bekommen wir eine <strong>Art </strong><a href="https://docs.microsoft.com/de-de/dotnet/api/system.collections.specialized.namevaluecollection?view=net-5.0" target="_blank" rel="noreferrer noopener"><strong>NameValueCollection</strong></a>, ich sage deshalb &#8222;Art&#8220;, <strong>weil </strong>es <strong>wohl </strong>eine <strong>davon erbende </strong>Variante sein muss.</p>



<p><strong>In Visual Studio </strong>selbst, <strong>sagt </strong>die <strong>Dokumentation </strong>leider im Tooltip dazu <strong>nicht mehr</strong>.</p>



<p><strong>Vielleicht übersehe ich </strong>auch <strong>etwas</strong>, aber <strong>probiere mal </strong>die manuelle <strong>Erstellung </strong>einer &#8222;NameValueCollection&#8220;.</p>



<p><strong>Füge </strong>anschließend 2-3 <strong>Einträge</strong> <strong>hinzu </strong>und <strong>gebe </strong>Diese dann <strong>als String aus </strong>und Du wirst einen Unterschied feststellen.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Dim myNVC = new NameValueCollection()
myNVC.Add("entry1", "value1")
myNVC.Add("entry2", "value2")
myNVC.Add("entry3", "value3")
' "normal"
Dim str = myNVC.ToString()
' or with Interpolation
' Dim str = $"{myNVC}"</pre>



<p>Im <strong>obigen Beispiel </strong>bekommst Du <strong>folgendes Ergebnis </strong>(wenn Du es ausgibst..):</p>



<figure class="wp-block-image size-full is-resized"><a href="https://robbelroot.de/wp-content/uploads/2021/09/NameValueCollection-ToString-Aufruf.png"><img loading="lazy" decoding="async" src="https://robbelroot.de/wp-content/uploads/2021/09/NameValueCollection-ToString-Aufruf.png" alt="NameValueCollection ToString Aufruf" class="wp-image-6289" width="418" height="76" title="NameValueCollection ToString Aufruf"/></a><figcaption>NameValueCollection ToString Aufruf</figcaption></figure>



<p>Man <strong>bekommt </strong>also <strong>praktisch nur </strong>den vollständigen <strong>Pfad der Klasse </strong>inkl. Namespace zurück.</p>



<p><strong>Wenn </strong>Du Dir <strong>allerdings </strong>den &#8222;ToString&#8220;-Wert des <strong>folgenden Beispiels </strong>anschaust, wird die Situation klarer:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Dim API_KEY = "BLA"
Dim baseCurrency = "EUR"
Dim targetCurrency = "USD"

Dim query = HttpUtility.ParseQueryString(String.Empty)
query.Add("access_key", API_KEY)
query.Add("base", baseCurrency)
query.Add("symbols", targetCurrency)

Dim str = query.ToString()
Console.WriteLine(str)
Console.ReadKey()</pre>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2021/09/Query-NameValueCollection-ToString.png"><img loading="lazy" decoding="async" width="297" height="78" src="https://robbelroot.de/wp-content/uploads/2021/09/Query-NameValueCollection-ToString.png" alt="Query NameValueCollection ToString" class="wp-image-6291" title="Query NameValueCollection ToString"/></a><figcaption>Query NameValueCollection ToString</figcaption></figure>



<p><strong>Hier </strong>bekommen wir <strong>nun </strong>die einzelnen <strong>Schlüssel- und Wert-Paare</strong> wie wir Sie <strong>für </strong>die <strong>URL benötigen </strong>zurück.</p>



<p><strong>Die </strong>von der &#8222;NameValueCollection&#8220; erbende <strong>Klasse</strong>, Welche wir vermutlich von &#8222;HttpUtility.ParseQueryString&#8220; zurückbekommen, <strong>wird </strong>also die &#8222;<strong>ToString</strong>&#8222;-Funktion <strong>überschreiben</strong>.</p>



<p><strong>Somit </strong>sieht also unser erster <strong>API aufrufender Code</strong> so aus:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Public Function GetExchangeRateAsync(baseCurrency As String, targetCurrency As String) As Task(Of Double)
    baseCurrency = baseCurrency.ToUpper()
    targetCurrency = targetCurrency.ToUpper()

    Dim query = HttpUtility.ParseQueryString(String.Empty)
    query.Add("access_key", API_KEY)
    query.Add("base", baseCurrency)
    query.Add("symbols", targetCurrency)

    Dim apiUrl = $"{BASE_URL}/latest?{query}"
    Dim response = Await Http.Client.GetAsync(apiUrl)
    Dim responseContent = Await response.Content.ReadAsStringAsync()

    ' parsing..

    Return 0
End Function</pre>



<p><strong>Setze </strong>Dir gerne mal einen <strong>Haltepunkt auf </strong>den &#8222;<strong>responseContent</strong>&#8220; und <strong>schaue </strong>Dir das <strong>Ergebnis </strong>an:</p>



<pre class="wp-block-code"><code>{"success":true,"timestamp":1632925144,"base":"EUR","date":"2021-09-29","rates":{"JPY":129.884571}}</code></pre>



<h2 class="wp-block-heading">API-Antwort verarbeiten – VB NET Web API</h2>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2021/09/JSON-zu-NET-Objekt-umwandeln.jpg"><img loading="lazy" decoding="async" width="640" height="360" src="https://robbelroot.de/wp-content/uploads/2021/09/JSON-zu-NET-Objekt-umwandeln.jpg" alt="JSON zu NET Objekt umwandeln - VB NET Web API" class="wp-image-6298" title="JSON zu NET Objekt umwandeln - VB NET Web API"/></a><figcaption>JSON zu NET Objekt umwandeln &#8211; VB NET Web API</figcaption></figure>



<p><strong>Einige </strong>werden das <strong>obige Format</strong>, Welches als Antwort von der API kommt vermutlich <strong>bereits kennen </strong>und <strong>verstehen</strong>.</p>



<p><strong>Für andere </strong>noch nicht so in der Entwicklung tief verankerte Personen, ist es <strong>ggf</strong>. ein <strong>kryptisches </strong>Gebilde.</p>



<p><strong>Bei </strong>dem kryptischen <strong>Text </strong>handelt es sich aber um nichts Geringeres, als die <strong><a href="https://de.wikipedia.org/wiki/JavaScript_Object_Notation" target="_blank" rel="noreferrer noopener">&#8222;JavaScript Object Notation&#8220; – kurz JSON</a></strong>.</p>



<p>Sie <strong>sieht im Vergleich </strong>zum ebenfalls sehr bekannten, aber zugegebenermaßen bereits in die Jahre gekommenen <strong>XML</strong>-Standard <strong>kryptischer </strong>aus.</p>



<p>Allerdings ist <strong>JSON wesentlich kompakter </strong>und für das geschulte Auge auch <strong>nicht wesentlich schwieriger </strong>zu lesen.</p>



<h3 class="wp-block-heading">JSON in Objekt umwandeln</h3>



<p><strong>Um nun </strong>mit unserer Arbeit an der API <strong>fortfahren </strong>zu können, <strong>müssen </strong>wir den obigen <strong>JSON-String</strong> <strong>in </strong>ein NET-<strong>Objekt umwandeln</strong>.</p>



<p><strong>Nur so </strong>ermöglichen wir uns eine <strong>einfache </strong>und <strong>saubere Arbeit </strong>damit, denn wer möchte hier schon <strong>manuelle Arbeit </strong>mit <strong>Funktionen </strong>wie z. B. <strong><a href="https://docs.microsoft.com/de-de/dotnet/api/system.string.substring?view=net-5.0" target="_blank" rel="noreferrer noopener">Substring</a></strong>, etc. leisten.</p>



<p><strong>Für </strong>die <strong>Umwandlung selbst benötigen </strong>wir im ersten Schritt erstmal eine <strong>Klasse</strong>, <strong>Welche </strong>das in <strong>JSON </strong>formulierte <strong>Objekt </strong>auf NET-Ebene <strong>widerspiegelt</strong>.</p>



<p>Dazu <strong>könnten </strong>wir <strong>einerseits händisch </strong>loslegen und die einzelnen <strong>Eigenschaften definieren</strong>:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Public Class ApiResponse

  Public Property success As Boolean

  Public Property timestamp As Integer

  ' ...

End Class</pre>



<p>Oder uns <strong>andererseits durch </strong>moderne <strong>Hilfsmittel </strong>in Visual Studio helfen lassen.</p>



<p><strong>Visual Studio</strong> besitzt die Funktionalität, einen <strong>JSON-String</strong> gar automatisiert <strong>in </strong>passende <strong>Klassen umzuwandeln</strong>:</p>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2021/09/JSON-String-mit-Visual-Studio-in-NET-Objekt-umwandeln.gif"><img loading="lazy" decoding="async" width="924" height="719" src="https://robbelroot.de/wp-content/uploads/2021/09/JSON-String-mit-Visual-Studio-in-NET-Objekt-umwandeln.gif" alt="JSON String mit Visual Studio in NET Objekt umwandeln - VB NET Web API" class="wp-image-6306" title="JSON String mit Visual Studio in NET Objekt umwandeln - VB NET Web API"/></a><figcaption>JSON String mit Visual Studio in NET Objekt umwandeln &#8211; VB NET Web API</figcaption></figure>



<p>JSON String mit Visual Studio in NET Objekt umwandeln</p>



<p><strong>Auch wenn </strong>es mit dem aktuellen Stand schon <strong>funktionieren </strong>würde, den <strong>String in </strong>ein <strong>Objekt </strong>(mit Sub-Objekten) <strong>umzuwandeln</strong>.</p>



<p><strong>Leider kann </strong>die <strong>API </strong>ja <strong>mit</strong> <strong>dynamischen </strong>&#8222;<strong>symbols</strong>&#8220; <strong>aufgerufen </strong>werden, weshalb ggf. unterschiedliche und <strong>nie fixe </strong>&#8222;<strong>Properties</strong>&#8220; in dem &#8222;Rate&#8220;-Objekt zurückkommen.</p>



<p><strong>Wenn </strong>Dich das <strong>nicht weiter stört</strong>, <strong>könntest </strong>Du natürlich die &#8222;<strong>Rate</strong>&#8222;-Klasse so <strong>ausbauen</strong>, <strong>dass sämtliche Währungen </strong>dort drinnen <strong>vertreten </strong>wären.</p>



<p><strong>Ich persönlich fände </strong>das allerdings <strong>nicht </strong>so <strong>prickelnd</strong>, <strong>daher bauen </strong>wir die &#8222;<strong>RootObject</strong>&#8222;-Klasse noch ein wenig <strong>um und </strong>lassen die &#8222;<strong>Rates</strong>&#8222;-Klasse <strong>verschwinden</strong>.</p>



<h3 class="wp-block-heading">JSON Parser installieren</h3>



<p><strong>Als nächstes installieren </strong>wir das bekannte <strong><a href="https://www.nuget.org/packages/Newtonsoft.Json/" target="_blank" rel="noreferrer noopener">Newtonsoft Json NuGet-Paket</a></strong>, um eine <strong>einfache Handhabung</strong> mit JSON-Objekten zu erhalten.</p>



<p><strong>Danach passen </strong>wir die &#8222;<strong>RootObject</strong>&#8222;-<strong>Klasse</strong> an, <strong>indem </strong>wir Sie zuerst einmal <strong>sinnvoller benennen</strong>, also <strong>etwa </strong>&#8222;<strong>ExchangeRatesApiResponse</strong>&#8222;.</p>



<p><strong>Anschließend ändern </strong>wir den <strong>Rückgabetyp </strong>der &#8222;<strong>rates</strong>&#8222;-Eigenschaft in &#8222;<a href="https://www.newtonsoft.com/json/help/html/t_newtonsoft_json_linq_jobject.htm" target="_blank" rel="noreferrer noopener"><strong>JObject</strong></a>&#8220; um, Welches es uns die Arbeit erleichtert.</p>



<p><strong>Nun </strong>können wir die &#8222;<strong>responseContent</strong>&#8222;-<strong>Variable</strong>, worin unser JSON-String steckt endlich <strong>umwandeln</strong>.</p>



<p>Im <strong>gleichen Schritt können </strong>wir auch noch die &#8222;exchangeRate&#8220;, also den <strong>Wechselkurs</strong>, typisiert <strong>aus </strong>der &#8222;<strong>rates</strong>&#8222;-Eigenschaft <strong>ziehen</strong>.</p>



<h3 class="wp-block-heading">Die Umwandlung selbst – VB NET Web API</h3>



<p>Dazu rufe ich <strong>im ersten Schritt</strong> die &#8222;<strong><a href="https://www.newtonsoft.com/json/help/html/Overload_Newtonsoft_Json_JsonConvert_DeserializeObject.htm" target="_blank" rel="noreferrer noopener">DeserializeObject</a></strong>&#8222;-Funktion der &#8222;<strong><a href="https://www.newtonsoft.com/json/help/html/t_newtonsoft_json_jsonconvert.htm" target="_blank" rel="noreferrer noopener">JsonConvert</a></strong>&#8222;-Klasse auf, Welche wir uns mit dem NuGet-Package installiert haben.</p>



<p><strong>Dabei übergebe </strong>ich den <strong>generischen Parameter </strong>&#8222;ExchangeRatesApiResponse&#8220;, Welcher unseren Ziel-<strong>Datentyp für </strong>die &#8222;<strong>Antwort</strong>-Klasse&#8220; widerspiegelt.</p>



<p>Schon haben wir den <strong>letztendlichen Wechselkurs </strong>vorliegen!</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Dim apiResponse = JsonConvert.DeserializeObject(Of ExchangeRatesApiResponse)(responseContent)
Dim exchangeRate = apiResponse.rates.Value(Of Double)(targetCurrency)</pre>



<p>Ein <strong>beispielhafter Aufruf </strong>unseres Services innerhalb einer Konsolenanwendung könnte nun final <strong>so </strong>aussehen:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Module Program

    Sub Main(args As String())
        Dim service = New ExchangeRateService()
        Dim exchangeRate = service.GetExchangeRateAsync("EUR", "JPY").Wait()
        ' do something with exchangeRate..
    End Sub

End Module</pre>



<h2 class="wp-block-heading">Weiterführende Links</h2>



<ul class="wp-block-list"><li><strong><a href="https://robbelroot.de/blog/vb-net-mouseclick-simulieren-mit-autoit3/" target="_blank" rel="noreferrer noopener">VB NET MouseClick simulieren – mit AutoIt3</a></strong></li><li><strong><a href="https://robbelroot.de/blog/vb-net-imagesearch-bilder-in-spielen-desktop-und-co-suchen/" target="_blank" rel="noreferrer noopener">VB NET ImageSearch – Bilder in Spielen, Desktop und Co. suchen</a></strong></li></ul>



<h2 class="margin-after-video-block wp-block-heading">Downloads</h2>



<p>Hier findest Du wie immer die zugehörigen <strong>Downloads zum Beitrag</strong>.</p>



<div class="wp-block-buttons is-layout-flex wp-block-buttons-is-layout-flex">
<div class="wp-block-button"><a class="wp-block-button__link" href="/downloads/vbnet/SimpleCurrencyExchangeRateServiceExample.zip" target="_blank" rel="noreferrer noopener">ServiceExample.zip</a></div>
</div>
<p>Der Beitrag <a href="https://robbelroot.de/blog/vb-net-web-api-waehrungskurs-service-konsum-von-grund-auf-erklaert/">VB NET Web API &#8211; Währungskurs Service Konsum von Grund auf erklärt</a> erschien zuerst auf <a href="https://robbelroot.de">Robert Skibbe</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://robbelroot.de/blog/vb-net-web-api-waehrungskurs-service-konsum-von-grund-auf-erklaert/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
	</channel>
</rss>
