<?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>https Archive - Robert Skibbe</title>
	<atom:link href="https://robbelroot.de/blog/tag/https/feed/" rel="self" type="application/rss+xml" />
	<link></link>
	<description>alias RobbelRoot – Freelance Full Stack Developer .NET</description>
	<lastBuildDate>Fri, 06 Jan 2023 19:04:02 +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>https Archive - Robert Skibbe</title>
	<link></link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Fehler &#8222;Es konnte kein geschützter SSL TLS Kanal erstellt werden&#8220; lösen</title>
		<link>https://robbelroot.de/blog/fehler-es-konnte-kein-geschuetzter-ssl-tls-kanal-erstellt-werden-loesen/</link>
					<comments>https://robbelroot.de/blog/fehler-es-konnte-kein-geschuetzter-ssl-tls-kanal-erstellt-werden-loesen/#comments</comments>
		
		<dc:creator><![CDATA[Robert Skibbe]]></dc:creator>
		<pubDate>Wed, 16 Feb 2022 15:09:50 +0000</pubDate>
				<category><![CDATA[Allgemein]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[error]]></category>
		<category><![CDATA[erstellen]]></category>
		<category><![CDATA[fehler]]></category>
		<category><![CDATA[http]]></category>
		<category><![CDATA[https]]></category>
		<category><![CDATA[kanal]]></category>
		<category><![CDATA[layer]]></category>
		<category><![CDATA[nicht]]></category>
		<category><![CDATA[secure]]></category>
		<category><![CDATA[security]]></category>
		<category><![CDATA[sicherheit]]></category>
		<category><![CDATA[sockets]]></category>
		<category><![CDATA[ssl]]></category>
		<category><![CDATA[tls]]></category>
		<category><![CDATA[transport]]></category>
		<category><![CDATA[übertragung]]></category>
		<category><![CDATA[webclient]]></category>
		<category><![CDATA[webrequest]]></category>
		<guid isPermaLink="false">https://robbelroot.de/?p=9271</guid>

					<description><![CDATA[<p>Was tun, wenn kein geschützter SSL TLS Kanal erstellt werden kann? Du erhältst die Fehlermeldung &#8222;Es konnte kein geschützter SSL TLS Kanal erstellt werden&#8220;? Dann herzlich willkommen zum heutigen Beitrag, wo ich Dir eine mögliche Lösung zeigen werde. Ich selbst habe diese Fehlermeldung gestern bei einem Kundenprojekt bekommen, aber wusste &#8230;</p>
<p>Der Beitrag <a href="https://robbelroot.de/blog/fehler-es-konnte-kein-geschuetzter-ssl-tls-kanal-erstellt-werden-loesen/">Fehler &#8222;Es konnte kein geschützter SSL TLS Kanal erstellt werden&#8220; lösen</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/02/Es-konnte-kein-geschuetzter-SSL-TLS-Kanal-erstellt-werden.jpg"><img fetchpriority="high" decoding="async" width="1200" height="628" src="https://robbelroot.de/wp-content/uploads/2022/02/Es-konnte-kein-geschuetzter-SSL-TLS-Kanal-erstellt-werden.jpg" alt="Es konnte kein geschützter SSL TLS Kanal erstellt werden" class="wp-image-9272" title="Es konnte kein geschützter SSL TLS Kanal erstellt werden"/></a><figcaption class="wp-element-caption">Es konnte kein geschützter SSL TLS Kanal erstellt werden</figcaption></figure>






<h2 class="wp-block-heading" id="was-tun-wenn-kein-geschutzter-ssl-tls-kanal-erstellt-werden-kann">Was tun, wenn kein geschützter SSL TLS Kanal erstellt werden kann?</h2>



<p>Du erhältst die Fehlermeldung &#8222;Es konnte <strong>kein geschützter</strong> SSL TLS <strong>Kanal erstellt</strong> werden&#8220;? Dann herzlich willkommen zum heutigen Beitrag, wo ich Dir eine mögliche Lösung zeigen werde. Ich selbst habe diese Fehlermeldung gestern bei einem Kundenprojekt bekommen, aber wusste zum Glück, was zu tun ist. Wenn man die Fehlermeldung das erste Mal sieht, kann man schon daran verzweifeln..</p>



<h2 class="wp-block-heading">Als Video ansehen</h2>



<p>Keine Lust auf viel Text? Kein Problem, schau Dir einfach das <strong><a href="https://youtu.be/cXDXRYEqvK0" target="_blank" rel="noreferrer noopener">kurze Video</a></strong> an und löse Dein Problem in wenigen Sekunden.</p>


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



<p>Im Endeffekt ist die dazugehörige Lösung – egal ob bei VB.NET oder C# Applikation – häufig vermeintlich einfach. Grundsätzlich stolpert man gängiger weise in Kombination <strong>mit Web-Requests</strong> über diese <strong>Fehlermeldung</strong>. Das liegt natürlich daran, dass dort für das HTTP (S) Protokoll, eine gesicherte Verbindung aufgebaut wird. Schauen wir uns das im nächsten Schritt einmal genauer an!</p>



<h2 class="wp-block-heading" id="fehler-forcieren-konnte-keinen-ssl-kanal-erstellen">Fehler nachstellen – &#8222;Konnte keinen SSL Kanal erstellen&#8220;</h2>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2022/02/Kein-geschuetzter-SSL-TLS-Kanal-Fehler-forcieren.jpg"><img decoding="async" width="1200" height="628" src="https://robbelroot.de/wp-content/uploads/2022/02/Kein-geschuetzter-SSL-TLS-Kanal-Fehler-forcieren.jpg" alt="Kein geschützter SSL TLS Kanal Fehler forcieren" class="wp-image-9287" title="Kein geschützter SSL TLS Kanal Fehler forcieren"/></a><figcaption class="wp-element-caption">Kein geschützter SSL TLS Kanal Fehler forcieren</figcaption></figure>



<p>Gehen wir im <strong>nächsten Schritt </strong>einmal hin und <strong>stellen</strong> diesen <strong>Fehler </strong>der problemhaften SSL-Kanal-Erstellung nach. <strong>Aus </strong>dem <strong>Kopf heraus </strong>kann ich da glaube ich ein relativ <strong>einfaches Szenario </strong>zusammenstückeln. <strong>Beachte</strong>, <strong>dass </strong>es vermutlich noch einige <strong>andere Situationen </strong>geben wird, ich aber Diese hier konkret weiß..</p>



<p><strong>Den Anfang </strong>findet das Ganze wie oben erwähnt – denke ich – am besten <strong>bei </strong>der <strong>NET Framework </strong>Version. <strong>Schalte </strong>also zunächst einfach die <strong>NET Framework </strong>Deines Projektes (wenn möglich) auf z. B. <strong>Version </strong>&#8222;<strong>4</strong>&#8222;. Im Video verwende ich hier ein älteres Projekt, wo ich den Fehler auch schon einmal hatte, wundere Dich also bitte nicht über den alten Code.</p>



<h3 class="wp-block-heading" id="net-framework-version-des-projekts-umstellen">NET Framework Version des Projekts umstellen</h3>



<p><strong>&#x1f4a1;</strong> Hinweis: Verwende zum Testen ggf. ein separates Projekt, um nichts in Deinem aktuellen Projekt zu zerstören!</p>



<p>Um die .NET-Framework Version Deines Projektes umzustellen, kannst Du im Visual Studio einfach oben auf &#8222;Projekt->Eigenschaften&#8220; gehen.</p>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2022/02/Visual-Studio-Projekt-Eigenschaften-oeffnen.png"><img decoding="async" width="498" height="476" src="https://robbelroot.de/wp-content/uploads/2022/02/Visual-Studio-Projekt-Eigenschaften-oeffnen.png" alt="Visual Studio Projekt-Eigenschaften öffnen" class="wp-image-9285" title="Visual Studio Projekt-Eigenschaften öffnen"/></a><figcaption class="wp-element-caption">Visual Studio Projekt-Eigenschaften öffnen</figcaption></figure>



<p>Gehe danach <strong>links auf </strong>den Reiter namens &#8222;<strong>Anwendung</strong>&#8220; und <strong>wähle </strong>unter dem Punkt &#8222;<strong>Zielframework</strong>&#8220; z. B. die <strong>Version 4</strong>. Anschließend wirst Du ggf. darum gebeten, die kommende Meldung zu bestätigen, Diese bestätigst Du dann einfach. Im nächsten Schritt wird dann mehr oder weniger alles durch Visual Studio umgestellt.</p>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2022/02/NET-Framework-in-den-Visual-Studio-Projekt-Eigenschaften-umstellen.png"><img loading="lazy" decoding="async" width="857" height="721" src="https://robbelroot.de/wp-content/uploads/2022/02/NET-Framework-in-den-Visual-Studio-Projekt-Eigenschaften-umstellen.png" alt="NET Framework in den Visual Studio Projekt-Eigenschaften umstellen" class="wp-image-9291" title="NET Framework in den Visual Studio Projekt-Eigenschaften umstellen"/></a><figcaption class="wp-element-caption">NET Framework in den Visual Studio Projekt-Eigenschaften umstellen</figcaption></figure>



<h3 class="wp-block-heading" id="aufruf-und-exception">Aufruf und Exception</h3>



<p>Im nächsten Schritt rufen wir dann einfach mal eine die Fehlermeldung (voraussichtlich) triggernde Funktion / Methode auf. Welche das ist / sind? Im ersten Schritt die Funktionen, Welche mit dem Netzwerk zu tun haben. Als Beispiel deklarieren wir daher einfach einen simplen &#8222;<a href="https://docs.microsoft.com/de-de/dotnet/api/system.net.webclient" target="_blank" rel="noreferrer noopener"><strong>WebClient</strong></a>&#8220; auf Form-Ebene und instanziieren Ihn im Konstruktor:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="visualbasic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="VB.NET" data-enlighter-group="webclient-instanziieren">Public Class Form1

    Private WithEvents _webClient As WebClient

    Sub New()
        _webClient = New WebClient()
    End Sub

End Class</pre>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="C#" data-enlighter-group="webclient-instanziieren">public class Form1

    private WebClient _webClient;

    public Form1()
    {
        _webClient = new WebClient();
    }

End Class</pre>



<p><strong>Danach</strong> <strong>rufe </strong>ich z. B. die &#8222;<strong><a href="https://docs.microsoft.com/de-de/dotnet/api/system.net.webclient.downloadstring" target="_blank" rel="noreferrer noopener">DownloadString</a></strong>&#8222;-Methode des &#8222;WebClients&#8220; mit einer passenden URL auf. Dabei <strong>kann </strong>es sich wie in meinem Beispiel, <strong>um </strong>eine <strong>normale Textdatei handeln</strong>, Welche nur einen schmalen String beinhaltet. Mein Aufruf sah dort z. B. wie folgt 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="">Dim version = ""
Try
  version = wc.DownloadString("&lt;URLToTextFileForExample>")
Catch ex As Exception
  ' catch the error..
End Try</pre>



<p>Anschließend hat der Code dann den benannten <strong>Fehler </strong>getriggert: &#8222;Es konnte kein geschützter SSL / TLS Kanal erstellt werden&#8220;:</p>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2022/02/Es-konnte-kein-geschuetzter-SSL-TLS-Kanal-erstellt-werden-Exception.png"><img loading="lazy" decoding="async" width="832" height="238" src="https://robbelroot.de/wp-content/uploads/2022/02/Es-konnte-kein-geschuetzter-SSL-TLS-Kanal-erstellt-werden-Exception.png" alt="Es konnte kein geschützter SSL TLS Kanal erstellt werden Exception" class="wp-image-9302" title="Es konnte kein geschützter SSL TLS Kanal erstellt werden Exception"/></a><figcaption class="wp-element-caption">Es konnte kein geschützter SSL TLS Kanal erstellt werden Exception</figcaption></figure>



<style>
.information-banner {
  padding: 1.5em;
  background: #ffd400;
  border-radius: 1em;
}
</style>



<p class="information-banner"><strong>Wichtig</strong>: In meinem Fall war meiner Meinung nach auch noch ein weiterer / anderer Aspekt wichtig. Es handelte sich bei dem auf der Domain verwendeten <strong>SSL Zertifikat, um ein</strong> durch <strong><a href="https://de.wikipedia.org/wiki/Let%E2%80%99s_Encrypt" target="_blank" rel="noreferrer noopener">LetsEncrypt</a></strong> <strong>generiertes Zertifikat</strong>!</p>



<h2 class="wp-block-heading" id="die-losung">Die Lösung!</h2>



<p>Ich <strong>will mich </strong>mit diesem Beitrag durchaus <strong>nicht </strong>als &#8222;<strong>Profi</strong>&#8220; in diesem Gebiet <strong>darstellen</strong>, jedoch <strong>möchte ich </strong>im Sinne Deiner <strong>Zeit-Einsparung</strong> berichten, <strong>wie </strong>es letztlich bei mir <strong>funktionierte</strong>. <strong>Selbstverständlich habe </strong>ich – so wie Du vermutlich vor einigen Sekunden – im Internet nach Problemlösungen <strong>gesucht</strong>.</p>



<p><strong>Leider </strong>haben <strong>vorgeschlagene </strong>Methoden <strong>nicht funktioniert </strong>– <strong>bis </strong>ich dann die gleich <strong>Folgende </strong>heraus hatte. Es <strong>wurde vorgeschlagen</strong>, Code wie <strong>diesen hier</strong>, <strong>vor dem ersten Netzwerk</strong>-Aufruf zu <strong>setzen</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="">ServicePointManager.Expect100Continue = True
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls
ServicePointManager.ServerCertificateValidationCallback = Function(sndr, cert, chain, sllPolicyErrors) True</pre>



<p><strong>Dafür würde </strong>sich natürlich ein <strong>Einstiegspunkt </strong>des Programmes, <strong>wie z. B.</strong> der &#8222;<strong>Load</strong>&#8222;-Ereignishandler der ersten Form, oder so etwas wie eine &#8222;Main-Methode&#8220; <strong>eignen</strong>. Allerdings <strong>klappte </strong>das wie oben bereits erwähnt leider <strong>nicht wirklich</strong>.. <strong>Nach </strong>einiger <strong>Fummelei</strong>, habe ich dann herausgefunden, dass ich für meinen Fall nur <strong>eine Codezeile benötigte</strong>.</p>



<p>Ebenso <strong>musste </strong>ich das <strong>NET Framework hochsetzen</strong>, um die passende <strong>Codezeile verwenden </strong>zu können. <strong>Setze </strong>also Dein <strong>Zielframework </strong>(wenn hoffentlich möglich) <strong>auf &#8222;4.5&#8220;</strong> und <strong>verwende </strong>diesen Code. Man <strong>beachte </strong>das <strong>hinten </strong>geänderte &#8222;Tls&#8220; zu &#8222;Tls12&#8220;, <strong>Welches </strong>scheinbar erst <strong>ab NET Framework 4.5</strong> (und laut Doku ab Win 7) <strong>verfügbar </strong>ist.</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="">ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12</pre>



<h2 class="wp-block-heading" id="fazit">Fazit</h2>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2022/02/VB-NET-Tutorial-1-Fazit.jpg"><img loading="lazy" decoding="async" width="1200" height="628" src="https://robbelroot.de/wp-content/uploads/2022/02/VB-NET-Tutorial-1-Fazit.jpg" alt="SSL Kanal erstellen Exception Fazit" class="wp-image-8236" title="SSL Kanal erstellen Exception Fazit"/></a><figcaption class="wp-element-caption">SSL Kanal erstellen Exception Fazit</figcaption></figure>



<p><strong>Am Ende </strong>dieses Beitrages angekommen können wir nun also <strong>folgendes</strong> <strong>Fazit </strong>ziehen. Wenn man mit <strong>Netzwerk-Anfragen</strong> in <strong>Kombination </strong>mit einem <strong>selbst signierten SSL Zertifikat </strong>arbeitet, kann es Probleme geben. <strong>Besonders </strong>unsere <strong>verwendete NET Framework Version (4.0)</strong> <strong>hatte </strong>ein bekanntes &#8222;<strong>Problem</strong>&#8222;, bzw. einen <strong>bekannten Fehler</strong>.</p>



<p><strong>Um </strong>diesen Fehler &#8222;Es <strong>konnte kein geschützter SSL TLS Kanal erstellt</strong> werden&#8220; zu <strong>lösen</strong>, <strong>muss </strong>man das Transport-<strong>Protokoll </strong>umstellen. <strong>Dies kann </strong>man erledigen, <strong>indem </strong>man die <strong>Eigenschaft </strong>&#8222;<a href="https://docs.microsoft.com/de-de/dotnet/api/system.net.servicepointmanager.securityprotocol?view=net-6.0" target="_blank" rel="noreferrer noopener"><strong>SecurityProtocol</strong></a>&#8220; der &#8222;<strong><a href="https://docs.microsoft.com/de-de/dotnet/api/system.net.servicepointmanager?view=net-6.0" target="_blank" rel="noreferrer noopener">ServicePointManager</a></strong>&#8222;-Klasse auf &#8222;Tls12&#8220; setzt. Die <strong>Umstellung muss </strong>allerdings (irgendwo logisch) <strong>vor </strong>dem <strong>ersten </strong>netzwerkbezogenen <strong>Aufruf </strong>stattfinden.</p>



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



<ul class="wp-block-list">
<li><strong><a href="https://robbelroot.de/blog/vb-net-webbrowser-alternative/" target="_blank" rel="noreferrer noopener">Einen alternatives Webbrowser-Control in VB NET verwenden</a></strong></li>



<li><strong><a href="https://robbelroot.de/blog/ein-vb-net-datagridview-fuellen/" target="_blank" rel="noreferrer noopener">Ein VB NET DataGridView füllen</a></strong></li>



<li><strong><a href="https://robbelroot.de/blog/dein-vb-net-plugin-system-im-eigenbau-das-ultimative-beispiel/" target="_blank" rel="noreferrer noopener">Dein eigenes Plugin-System mit Visual Basic .NET</a></strong></li>
</ul>
<p>Der Beitrag <a href="https://robbelroot.de/blog/fehler-es-konnte-kein-geschuetzter-ssl-tls-kanal-erstellt-werden-loesen/">Fehler &#8222;Es konnte kein geschützter SSL TLS Kanal erstellt werden&#8220; lösen</a> erschien zuerst auf <a href="https://robbelroot.de">Robert Skibbe</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://robbelroot.de/blog/fehler-es-konnte-kein-geschuetzter-ssl-tls-kanal-erstellt-werden-loesen/feed/</wfw:commentRss>
			<slash:comments>11</slash:comments>
		
		
			</item>
		<item>
		<title>&#x1f575;&#xfe0f; Hacking a Webshop – don&#8217;t fall for this common trap!</title>
		<link>https://robbelroot.de/blog/hacking-a-webshop/</link>
					<comments>https://robbelroot.de/blog/hacking-a-webshop/#comments</comments>
		
		<dc:creator><![CDATA[Robert Skibbe]]></dc:creator>
		<pubDate>Sat, 22 Jan 2022 14:49:51 +0000</pubDate>
				<category><![CDATA[Allgemein]]></category>
		<category><![CDATA[General]]></category>
		<category><![CDATA[Security]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[api]]></category>
		<category><![CDATA[app]]></category>
		<category><![CDATA[bad]]></category>
		<category><![CDATA[budget]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[console]]></category>
		<category><![CDATA[crud]]></category>
		<category><![CDATA[danger]]></category>
		<category><![CDATA[dangerous]]></category>
		<category><![CDATA[hack]]></category>
		<category><![CDATA[hacked]]></category>
		<category><![CDATA[hacker]]></category>
		<category><![CDATA[hacking]]></category>
		<category><![CDATA[http]]></category>
		<category><![CDATA[https]]></category>
		<category><![CDATA[manipulate]]></category>
		<category><![CDATA[manipulating]]></category>
		<category><![CDATA[method]]></category>
		<category><![CDATA[network]]></category>
		<category><![CDATA[post]]></category>
		<category><![CDATA[request]]></category>
		<category><![CDATA[rest]]></category>
		<category><![CDATA[security]]></category>
		<category><![CDATA[shop]]></category>
		<category><![CDATA[vulnerability]]></category>
		<category><![CDATA[web]]></category>
		<category><![CDATA[webapi]]></category>
		<category><![CDATA[webapp]]></category>
		<category><![CDATA[webshop]]></category>
		<guid isPermaLink="false">https://robbelroot.de/?p=7503</guid>

					<description><![CDATA[<p>Hacking a Webshop So you are interested in hacking a webshop, or in software development security in general? I welcome you to todays post on application security and how to use or protect against this special case. In this example you can simply follow along by just downloading and executing &#8230;</p>
<p>Der Beitrag <a href="https://robbelroot.de/blog/hacking-a-webshop/">&#x1f575;&#xfe0f; Hacking a Webshop – don&#8217;t fall for this common trap!</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/01/Hacking-a-webshop-post-image.png"><img loading="lazy" decoding="async" width="1200" height="628" src="https://robbelroot.de/wp-content/uploads/2022/01/Hacking-a-webshop-post-image.png" alt="Hacking a Webshop – a crappy one, the &quot;Crapshop&quot;" class="wp-image-7506" title="Hacking a Webshop – a crappy one, the &quot;Crapshop&quot;"/></a><figcaption> Hacking a Webshop – a crappy one, the &#8222;Crapshop&#8220;</figcaption></figure>






<h2 class="wp-block-heading" id="hacking-a-webshop">Hacking a Webshop</h2>



<p>So you are interested in <strong>hacking a webshop</strong>, or in <strong>software development security</strong> in general?</p>



<p>I <strong>welcome</strong> you to todays post on application security and <strong>how to use or protect against this special case</strong>.</p>



<p>In <strong>this example</strong> you can <strong>simply follow along</strong> by just <strong>downloading </strong>and executing the <strong>example code</strong>.</p>



<p><strong>Especially when i</strong> first <strong>started </strong>programming, I found a lot of code like the one you will see.</p>



<p>Easy <strong>cart items</strong> just <strong>being added </strong>without enough checking or protection <strong>against </strong>some <strong>malicious </strong>boi.</p>



<h3 class="wp-block-heading" id="i-m-still-working-on-this-article-so-more-content-will-come-in-a-few-hours">I&#8217;m still working on this article, so more content will come in a few hours 🙂</h3>


<div class="async-youtube" data-embed="_XNaOH-1PZI" data-alt="">
    <div class="play-button"></div>      
  </div>



<p><strong>Here </strong>comes <strong>the big thing</strong> – <strong>even today </strong>some shops will still be programmed like that..</p>



<p>So <strong>hacking a webshop</strong> like this will still be possible for some of those badly programmed ones.</p>



<p><strong>On my journey</strong> i <strong>continiously asked </strong>myself the &#8222;<strong>why</strong>&#8220; behind that problem.</p>



<p><strong>Most of the time</strong>, you will potentially find the <strong>same answer</strong> as i already did.</p>



<p>We need to <strong>consider</strong> the <strong>different </strong>aspects, or the different <strong>roles </strong>here:</p>



<ul class="wp-block-list"><li>the <strong>customer</strong>, <strong>ordering </strong>the software</li><li>a <strong>developer </strong>actually <strong>creating </strong>that piece of application</li><li>the <strong>users using </strong>that software</li></ul>



<h2 class="wp-block-heading" id="how-bad-software-is-created-the-roles">How bad software is created – the roles</h2>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2022/01/Hacking-a-webshop-Customer-and-Developer-role.png"><img loading="lazy" decoding="async" width="1200" height="628" src="https://robbelroot.de/wp-content/uploads/2022/01/Hacking-a-webshop-Customer-and-Developer-role.png" alt="Hacking a webshop - Customer and Developer role" class="wp-image-7517" title="Hacking a webshop - Customer and Developer role"/></a><figcaption>Hacking a webshop &#8211; Customer and Developer role</figcaption></figure>



<p><strong>When thinking about</strong> that <strong>bad software</strong> which is actually <strong>vulnerable </strong>to a hacker, we have to <strong>consider </strong>the involved <strong>roles</strong>.</p>



<p>As i <strong>already mentioned</strong> above, there are <strong>3 roles involved</strong>, but <strong>one </strong>isn&#8217;t really responsible in the process itself, so..</p>



<p><strong>For sure</strong>, this <strong>also depends on the type of project</strong> and if theres something like a special beta phase, etc.</p>



<p>Let&#8217;s have <strong>a basic look</strong> at <strong>those roles </strong>and see what we can like expect or take into consideration.</p>



<h3 class="wp-block-heading" id="an-end-user"><a href="https://emojiterra.com/de/stehende-person/">&#x1f9cd;</a> An end user</h3>



<figure class="wp-block-image size-full is-resized"><a href="https://robbelroot.de/wp-content/uploads/2022/01/How-developers-imagine-the-end-user.gif"><img loading="lazy" decoding="async" src="https://robbelroot.de/wp-content/uploads/2022/01/How-developers-imagine-the-end-user.gif" alt="How developers imagine the end user" class="wp-image-7525" width="345" height="194" title="How developers imagine the end user"/></a><figcaption>How developers imagine the end user</figcaption></figure>



<p>The <strong>end user can</strong> like <strong>report </strong>some <strong>problems </strong>he found, <strong>but </strong>for <strong>security thingys</strong>, this <strong>mostly won&#8217;t</strong> be the case.</p>



<p>You <strong>can&#8217;t expect a normal user</strong> to actually tell you about your security.</p>



<p>He <strong>won&#8217;t get in touch</strong> in a (any) way, where he <strong>could </strong>really understand <strong>or judge </strong>that thing.</p>



<p><strong>Obviously </strong>it <strong>isn&#8217;t his responsibility</strong> either, so forget about that as quick as possible!</p>



<p>You <strong>can be glad</strong>, <strong>if</strong> an end <strong>user </strong>actually <strong>takes </strong>the <strong>time </strong>to report a problem he faced.</p>



<p>This is great, because you then have the nice <strong>chance</strong> <strong>to </strong>actually <strong>fix </strong>that.</p>



<p><strong>End users</strong> just <strong>want one thing</strong>, or well we could say 3 things – u<strong>se </strong>your god damn (sorry) <strong>app </strong>as:</p>



<ul class="wp-block-list"><li><strong>easy</strong></li><li><strong>intuitive</strong></li><li>and <strong>bug free</strong></li></ul>



<p>as possible – full stop!</p>



<p>So if that happens to you, <strong>be glad your customer did that</strong> and <strong>give </strong>him some <strong>treat</strong>!</p>



<p>In the past <strong>i</strong> pretty much <strong>contacted every company </strong>where i faced some problem by email.</p>



<p><strong>Some of them</strong> were <strong>nice </strong>and gave like some sort of bonus, <strong>some of them</strong> were <strong>ignorant.</strong></p>



<p>There even were <strong>some </strong>companies, where they just <strong>got pissed</strong> and argued, but well..</p>



<p><strong>Don&#8217;t be</strong> that <strong>last kind </strong>of company!</p>



<h3 class="wp-block-heading" id="the-devs-customer"><a href="https://emojipedia.org/money-with-wings/">&#x1f4b8;</a> The (devs) customer</h3>



<figure class="wp-block-image size-full is-resized is-style-default"><a href="https://robbelroot.de/wp-content/uploads/2022/01/The-developers-customer.jpg"><img loading="lazy" decoding="async" src="https://robbelroot.de/wp-content/uploads/2022/01/The-developers-customer.jpg" alt="The developers customer" class="wp-image-7531" width="320" height="183" title="The developers customer"/></a><figcaption>The developers customer</figcaption></figure>



<p><strong>Now </strong>we are getting to the <strong>first interesting role</strong> as this one probably <strong>made </strong>this whole <strong>situation start</strong>.</p>



<p>There is <strong>one guy</strong> or even a whole company <strong>with a plan</strong> of a software (hopefully they have a plan..).</p>



<p>They may want to outsource that software due to missing time inside the original team.</p>



<p>It <strong>could also be</strong> another type of <strong>person </strong>– like a private one – which <strong>has </strong>an <strong>idea</strong>.</p>



<p>In a <strong>typical scenario</strong>, the <strong>problem </strong>we are discussing here is <strong>mostly faced</strong>, <strong>when hiring </strong>a (maybe) unexperienced freelancer.</p>



<p>As I have seen it in my past a lot as well, this <strong>also counts for</strong> like <strong>small agencies</strong>.</p>



<p><strong>Even if </strong>most persons think, that about <strong>everything is the developers fault</strong>, theres more to consider.</p>



<p>Especially he <strong>customer has a chance to control</strong> this process and the <strong>outcoming quality</strong> as well.</p>



<p>Why/How? Well, let me do <strong>one quick example</strong>:</p>



<p><strong>If you want a ferrari</strong> and you want to &#8222;vroom, vroom&#8220;, then <strong>you will</strong> <strong>have to pay for that</strong>.</p>



<p>The <strong>problem </strong>here <strong>with &#8222;little&#8220; customers</strong> is, that they commonly want that big &#8222;Amazony&#8220; application.</p>



<p><strong>All </strong>the <strong>possibilities </strong>and <strong>strengths </strong>and more, but they <strong>only want to pay for like a basic</strong> &#8222;add, edit, delete, list&#8220;-<strong>thingy</strong>.</p>



<p><strong>Furthermore </strong>this <strong>also </strong>sometimes <strong>applies to &#8222;bigger&#8220; companies</strong>, as they <strong>want to save</strong> money as well..</p>



<p><strong>Obviously that won&#8217;t work</strong>..</p>



<h2 class="wp-block-heading" id="developer-developing-firm"><a href="https://emojiterra.com/man-technologist/">&#x1f468;&#x200d;&#x1f4bb;</a> Developer (developing firm)</h2>



<figure class="wp-block-image size-full is-resized"><a href="https://robbelroot.de/wp-content/uploads/2022/01/Software-Developer-working-Hacking-a-webshop.jpg"><img loading="lazy" decoding="async" src="https://robbelroot.de/wp-content/uploads/2022/01/Software-Developer-working-Hacking-a-webshop.jpg" alt="Software Developer working - Hacking a webshop" class="wp-image-7607" width="320" height="214" title="Software Developer working - Hacking a webshop"/></a><figcaption>Software Developer working &#8211; Hacking a webshop</figcaption></figure>



<p>The <strong>last role</strong> is likely to be the <strong>most responsible one</strong>, as <strong>important </strong>and <strong>fundamental tasks </strong>lie on its shoulders.</p>



<p>However most projects start <strong>with </strong>the actual <strong>contact from </strong>the <strong>developers to </strong>the <strong>customer</strong>.</p>



<p>This can be done by like some <strong>freelancing platform</strong>, <strong>creating </strong>the <strong>basic </strong>&#8222;<strong>frame</strong>&#8220; around that project.</p>



<p>You can believe me when i say, that <strong>at this point</strong> there can already be <strong>so many things going wrong</strong>.</p>



<p>I&#8217;m talking about <strong>budget</strong>, <strong>milestones</strong>, <strong>communication </strong>between the different parties, the <strong>final deadline</strong> and <strong>more</strong>..</p>



<p>But i think that&#8217;s <strong>part of another big story</strong>, so I&#8217;ll just continue..</p>



<p><strong>Going over </strong>the <strong>experience </strong>of the working <strong>team</strong>, <strong>next to </strong>the experience and <strong>tools of </strong>the <strong>individual developer</strong>.</p>



<p>The <strong>vulnerable spot</strong> that you will see in a moment, is <strong>mostly created by inexperienced</strong> devs.</p>



<p>For sure, such <strong>big mistakes</strong> can also be created through <strong>being close to a deadline</strong> and whatsoever reason.</p>



<p>I mean this <strong>won&#8217;t be any excuse</strong>, because:</p>



<ul class="wp-block-list"><li>either you <strong>have that budget</strong> you need to accomplish the work</li><li>or you&#8217;ve <strong>told the client</strong>, that this is <strong>not realistic</strong> and therfore <strong>won&#8217;t work</strong></li></ul>



<h2 class="wp-block-heading" id="jumping-in-the-code-of-hacking-a-webshop">Jumping in the code of hacking a webshop</h2>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2022/01/Webshop-hack-thumbnail.png"><img loading="lazy" decoding="async" width="1920" height="1080" src="https://robbelroot.de/wp-content/uploads/2022/01/Webshop-hack-thumbnail.png" alt="Hacking a webshop – Thumbnail" class="wp-image-7611" title="Hacking a webshop – Thumbnail"/></a><figcaption>Hacking a webshop – Thumbnail</figcaption></figure>



<p><strong>Before </strong>we actually <strong>start talking about the code</strong> behind, I would <strong>recommend downloading </strong>the <strong>code</strong>.</p>



<p>To do so, <strong>go to the bottom</strong> of the page and download that <strong><a href="https://bit.ly/hacking-a-webshop-download" target="_blank" rel="noreferrer noopener">&#8222;crapshop.zip&#8220; file</a></strong>, <strong>or just</strong> the link <strong>here</strong>!</p>



<p><strong>Extract </strong>the containing <strong>project folder</strong> to a location of your desire <strong>and </strong>we are like <strong>ready to go</strong>.</p>



<h3 class="wp-block-heading" id="prolog">Prolog</h3>



<p><strong>Keep in mind</strong> that our <strong>focus </strong>in this blog post <strong>is </strong>to actually <strong>understand and hack</strong> the crappy webshop itself.</p>



<p>So I pretty much <strong>won&#8217;t use time on explaining</strong> how to setup the <strong>Slim web application</strong> (API), or the concepts.</p>



<p>I <strong>will concentrate on</strong> the specific web api <strong>route and </strong>the process of <strong>adding a product to</strong> our <strong>cart</strong>.</p>



<p>Please <strong>also </strong>keep in mind, that there are <strong>so many</strong> other <strong>things which could be improved</strong>.</p>



<p>I just <strong>tried to come up with a quick</strong>, usable <strong>example</strong>, <strong>nothing more</strong>, so..</p>



<h3 class="wp-block-heading" id="prerequisites">Prerequisites</h3>



<p><strong>Before </strong>you are <strong>able to </strong>start or <strong>execute </strong>the code, you <strong>should have some tools</strong> ready:</p>



<ul class="wp-block-list"><li>The used package manager <strong>composer</strong> (<strong><a href="https://getcomposer.org/" target="_blank" rel="noreferrer noopener">weblink to composer</a></strong>)</li><li>A code editor like <strong><a href="https://code.visualstudio.com/" target="_blank" rel="noreferrer noopener">Visual Studio Code</a></strong></li><li><strong>Installed PHP binaries</strong> e. g. through WinNMP or XAMPP, or raw..</li></ul>



<h3 class="wp-block-heading" id="installing-dependencies-with-composer">Installing dependencies with composer</h3>



<p>In the <strong>first step</strong> you <strong>need to</strong> use the composer package manager to <strong>install dependencies</strong>.</p>



<p>You can <strong>do so by opening the project folder</strong> <strong>in </strong>like a Visual Studio Code <strong>terminal</strong>, or the normal console.</p>



<p>Then go ahead and <strong>execute the following command to install</strong> the <strong>dependencies</strong>:</p>



<pre class="wp-block-code"><code>composer install</code></pre>



<h3 class="wp-block-heading" id="starting-the-app">Starting the app</h3>



<p><strong>After everything</strong> is <strong>installed </strong>successfully you can <strong>start the app using</strong> the native PHP server.</p>



<p>To <strong>run that native PHP server</strong> you can execute this command here:</p>



<pre class="wp-block-code"><code>php -S localhost:8000 public/index.php</code></pre>



<p>It <strong>will </strong>basically <strong>start the server</strong> at the &#8222;public/index.php&#8220; location, with &#8222;localhost&#8220; as host and listening port 8000.</p>



<p>After that, visit &#8222;<strong>https://localhost:8000</strong>&#8220; in your favourite browser and you will see the webshop starting page:</p>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2022/01/Hacking-a-webshop-starting-page.png"><img loading="lazy" decoding="async" width="1229" height="574" src="https://robbelroot.de/wp-content/uploads/2022/01/Hacking-a-webshop-starting-page.png" alt="Hacking a webshop starting page" class="wp-image-7634" title="Hacking a webshop starting page"/></a><figcaption>Hacking a webshop starting page</figcaption></figure>



<h3 class="wp-block-heading" id="a-little-product-search-page">A little product search page</h3>



<p>After you have started the server, you can <strong>now navigate to the product search page</strong>.</p>



<p>Do so by <strong>clicking th</strong>e &#8222;Products&#8220;-link and you will see a basic <strong>page with listed products</strong>.</p>



<p><strong>Just for fun</strong> I&#8217;ve implemented a little <strong>search functionality</strong>, but this <strong>isn&#8217;t really necessary</strong> here.</p>



<p><strong>Let&#8217;s see what happens</strong>, if you <strong>click on</strong> that &#8222;add to cart&#8220;-<strong>button </strong>on the listing page:</p>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2022/01/Clicking-the-add-to-cart-button-inside-our-hacky-webshop-example.png"><img loading="lazy" decoding="async" width="1273" height="949" src="https://robbelroot.de/wp-content/uploads/2022/01/Clicking-the-add-to-cart-button-inside-our-hacky-webshop-example.png" alt="Clicking the add to cart button inside our hacky webshop example" class="wp-image-7640" title="Clicking the add to cart button inside our hacky webshop example"/></a><figcaption>Clicking the add to cart button inside our hacky webshop example</figcaption></figure>



<p>As you can see there is <strong>a POST request being executed to our backend </strong>at &#8222;/api/cart/add-product&#8220;.</p>



<h3 class="wp-block-heading" id="the-clientside-code">The clientside code</h3>



<p>Let&#8217;s take a <strong>look at the code which triggered the request</strong> (you can find it in &#8222;public/js/page_products.js&#8220;):</p>



<pre class="EnlighterJSRAW" data-enlighter-language="js" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="page_products.js" data-enlighter-group="">document.addEventListener('click', function (e) {
  if (e.target.classList.contains('btnAddToCart')) {
    addProductToCart(e.target);
  }
});

function addProductToCart(btnAddToCart) {
  var id = parseInt(btnAddToCart.dataset.id);
  var price = parseFloat(btnAddToCart.dataset.price);
  var xhr = new XMLHttpRequest();
  xhr.open("POST", '/api/cart/add-product', true);
  xhr.setRequestHeader('Content-Type', 'application/json');
  // xhr.onload = function () {
  //   location.reload();
  // };
  xhr.send(JSON.stringify({
    id,
    price,
  }));
}</pre>



<p>There isn&#8217;t much more going on than <strong>registering that click-callback</strong> <strong>on </strong>the <strong>document </strong>and reacting to that.</p>



<p><strong>If</strong> an element with our &#8222;.<strong>btnAddToCart</strong>&#8222;-class <strong>is clicked</strong>, we respond to that by <strong>executing</strong> the &#8222;addProductToCart&#8220;-<strong>function</strong>.</p>



<p><strong>The function</strong> itself <strong>will pull</strong> the <strong>id and the price</strong> from the corresponding &#8222;data&#8220;-attribute.</p>



<p>After that, it <strong>will send a new</strong> &#8222;XMLHttpRequest&#8220; <strong>to the server</strong> and that&#8217;s it.</p>



<p><strong>If</strong> you <strong>want to refresh</strong> the page after doing so, you can <strong>uncomment the lines</strong> with &#8222;onload&#8220;.</p>



<p>I&#8217;ve <strong>omitted it on purpose</strong> as this <strong>will </strong>mostly <strong>clear the network history</strong> and you won&#8217;t be able to see the request. </p>



<h3 class="wp-block-heading" id="the-dangerous-web-api-endpoint">The dangerous web api endpoint</h3>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2022/01/Dangerous-web-api-hacking-a-webshop.jpg"><img loading="lazy" decoding="async" width="1280" height="640" src="https://robbelroot.de/wp-content/uploads/2022/01/Dangerous-web-api-hacking-a-webshop.jpg" alt="Dangerous web api - hacking a webshop" class="wp-image-7675" title="Dangerous web api - hacking a webshop"/></a><figcaption>Dangerous web api &#8211; hacking a webshop</figcaption></figure>



<p><strong>After </strong>explaining the <strong>client code</strong> which has been executed above, we will <strong>now focus on the server</strong> side.</p>



<p><strong>You may</strong> have already <strong>guessed the problem</strong> in our case, but <strong>let&#8217;s dive deeper</strong> anyways.</p>



<p>Go ahead, <strong>step into your code editor</strong> and <strong>open </strong>the &#8222;<strong>src/Controller/CartController.php</strong>&#8222;-file.</p>



<p><strong>When </strong>you have the <strong>file ready</strong>, <strong>focus on the </strong>&#8222;addProduct&#8220;-function, which represents the corresponding endpoint.</p>



<h3 class="wp-block-heading" id="the-code-explained">The code explained</h3>



<p>In the <strong>first two lines</strong>, we will <strong>pull the json contents</strong> sent by javascript:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="php" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">    $json = $request->getBody();
    $data = json_decode($json, true);</pre>



<p><strong>Then </strong>we&#8217;re <strong>checking</strong>, <strong>if</strong> the needed <strong>data </strong>– product id and price – have been <strong>provided</strong>.</p>



<p><strong>If</strong> those are <strong>not present</strong>, <strong>we </strong>will <strong>respond with </strong>a nice <strong>400 Http response status</strong>, which means &#8222;bad request&#8220;.</p>



<p><strong>Additionally </strong>there will be some c<strong>ode identifying what</strong> the actual <strong>problem </strong>was:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="php" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">    if (!array_key_exists('id', $data)) {
      return $response
        ->withJson([ 'code' => 'ID_MISSING' ], 400);
    }

    if (!array_key_exists('price', $data)) {
      return $response
        ->withJson([ 'code' => 'PRICE_MISSING' ], 400);
    }</pre>



<p>Next we are fetching and parsing the id, to check if it&#8217;s kinda correct, so like above &#8222;0&#8220;.</p>



<p>Sure this <strong>could be done better</strong>, <strong>but </strong>this is <strong>enough </strong>for this purpose..</p>



<pre class="EnlighterJSRAW" data-enlighter-language="php" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">    $id = intval($data['id']);
    if ($id &lt;= 0) {
      return $response
        ->withJson([ 'code' => 'INVALID_ID' ], 400);
    }</pre>



<p>After that, we are <strong>fetching </strong>the <strong>product information</strong> from our small &#8222;ProductService&#8220;-class.</p>



<p>This <strong>enables </strong>us <strong>checking</strong>, <strong>if</strong> that <strong>product is </strong>actually a product <strong>from our</strong> &#8222;database&#8220;.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="php" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">    $product = $this->productService->getProductById($id);
    if (!$product) {
      return $response
        ->withJson([ 'code' => 'PRODUCT_NOT_FOUND' ], 404);
    }</pre>



<p><strong>NOW </strong>the <strong>important </strong>and dangerous <strong>part</strong> starts, which is <strong>accepting the price from the client</strong> side.</p>



<p><strong>Later I&#8217;ll sum up how to correctly</strong> work with that price <strong>and what</strong> you should also take into <strong>consideration</strong>.</p>



<p>I mean I added the small thingy, that we are <strong>at least checking</strong>, <strong>that </strong>the <strong>price can&#8217;t be negative</strong>, so &#8222;it&#8217;s something&#8220;.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="php" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">    $price = floatval($data['price']);
    if ($price &lt;= 0) {
      return $response
        ->withJson([ 'code' => 'INVALID_PRICE' ], 400);
    }</pre>



<p><strong>Then we are doing</strong> some <strong>basic cart stuff</strong> like fetching the cart from the session (which could also be done by database).</p>



<p>We are also <strong>checking if the product has already been added</strong> to that cart.</p>



<p><strong>If</strong> it has been already added, we just <strong>increment</strong> this <strong>quantity </strong>for now, <strong>if not</strong>, it&#8217;s <strong>added in general</strong>.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="php" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">    $cart = $this->session->get('cart') ?? [];

    $alreadyExists = null;
    foreach ($cart as $key => $value) {
      $item = $cart[$key];
      if ($item['id'] === $id &amp;&amp; $item['price'] === $price) {
        $alreadyExists = $key;
        break;
      }
    }

    if ($alreadyExists !== null) {
      $cart[$alreadyExists]['quantity'] = $cart[$alreadyExists]['quantity'] + 1;
    } else {
      $cart[] = [
        'id' => $id,
        'title' => $product['title'],
        'thumbnail' => $product['thumbnail'],
        'quantity' => 1,
        'price' => $price,
      ];
    }</pre>



<p><strong>In </strong>the <strong>last step</strong> we are just <strong>setting the new value for</strong> our <strong>cart </strong>inside the session <strong>and </strong>we are <strong>returning a response</strong> to the client.</p>



<pre class="EnlighterJSRAW" data-enlighter-language="php" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">    $this->session->set('cart', $cart);

    return $response;</pre>



<h2 class="wp-block-heading" id="manipulating-that-request-hacking-a-webshop">Manipulating that request – hacking a webshop</h2>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2022/01/Manipulating-the-request-attacking-the-api.jpg"><img loading="lazy" decoding="async" width="1280" height="736" src="https://robbelroot.de/wp-content/uploads/2022/01/Manipulating-the-request-attacking-the-api.jpg" alt="Manipulating the request attacking the api" class="wp-image-7678" title="Manipulating the request attacking the api"/></a><figcaption>Manipulating the request attacking the api</figcaption></figure>



<p>It&#8217;s <strong>now time</strong> <strong>to </strong>get to the final point of <strong>creating</strong> our <strong>own version of that request</strong>.</p>



<p>To work on that <strong>we need to analyse the request being sent</strong> and provide our own data.</p>



<p><strong>Then </strong>we need to <strong>re-send that request</strong> with our own data <strong>being accepted by the server</strong>.</p>



<p>The <strong>easiest way</strong> to do so <strong>is</strong> by <strong>opening</strong> that <strong>network tab</strong> of the webbrowser console, again.</p>



<h3 class="wp-block-heading" id="opening-the-browsers-developer-tools">Opening the browsers developer tools</h3>



<p><strong>Visit </strong>the <strong>product list page</strong> once again and <strong>open the browser console</strong> with F12.</p>



<p><strong>Go to</strong> the <strong>network tab</strong> and then <strong>execute the code</strong> by clicking that &#8222;<strong>add to cart</strong>&#8222;-button.</p>



<p><strong>Now </strong>you could <strong>inspect the request</strong> itself by just left clicking it:</p>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2022/01/Inspecting-the-add-product-api-request.png"><img loading="lazy" decoding="async" width="879" height="403" src="https://robbelroot.de/wp-content/uploads/2022/01/Inspecting-the-add-product-api-request.png" alt="Inspecting the add product api request" class="wp-image-7681" title="Inspecting the add product api request"/></a><figcaption>Inspecting the add product api request</figcaption></figure>



<p><strong>We </strong>already <strong>know </strong>which <strong>data </strong>is <strong>send</strong>, <strong>therefore </strong>we <strong>don&#8217;t</strong> really need to <strong>inspect </strong>the &#8222;<strong>payload</strong>&#8222;-tab to get an idea.</p>



<p><strong>Now </strong>the easiest way to test a custom request is, to <strong>right click that &#8222;add-product&#8220;</strong> on the left, which opens a context menu.</p>



<p><strong>There </strong>you can <strong>select </strong>the &#8222;<strong>Copy</strong>&#8220; and &#8222;<strong>Copy as fetch</strong>&#8220; items – to <strong>copy the fetch instructions into your clipboard</strong>.</p>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2022/01/Copying-the-web-api-request-as-fetch.png"><img loading="lazy" decoding="async" width="541" height="503" src="https://robbelroot.de/wp-content/uploads/2022/01/Copying-the-web-api-request-as-fetch.png" alt="Copying the web api request as fetch" class="wp-image-7686" title="Copying the web api request as fetch"/></a><figcaption>Copying the web api request as fetch</figcaption></figure>



<p><strong>Now</strong>, in the <strong>final step</strong>, you can then <strong>copy the clipboard</strong> contents <strong>to </strong>your &#8222;<strong>Console</strong>&#8222;-tab.</p>



<p><strong>There </strong>you can actually <strong>make</strong> your <strong>custom changes</strong> like <strong>changing </strong>the <strong>product </strong>id which you want to put in your cart.</p>



<p>The <strong>most important thing</strong> here is, <strong>we can change the price</strong>, too!</p>



<h3 class="wp-block-heading" id="executing-with-manipulated-request-data">Executing with manipulated request data</h3>



<p>So <strong>go ahead</strong> and do something <strong>like this</strong> here:</p>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2022/01/Changing-the-request-body-creating-our-request.png"><img loading="lazy" decoding="async" width="667" height="388" src="https://robbelroot.de/wp-content/uploads/2022/01/Changing-the-request-body-creating-our-request.png" alt="Changing the request body creating our request" class="wp-image-7691" title="Changing the request body creating our request"/></a><figcaption>Changing the request body creating our request</figcaption></figure>



<p><strong>I changed</strong> the product <strong>id </strong>to &#8222;3&#8220; <strong>and </strong>the <strong>price </strong>to something low like &#8222;5&#8220;.</p>



<p><strong>Hit enter</strong> on your keyboard <strong>while</strong> the <strong>console is focused</strong> and the request will be executed.</p>



<p><strong>After that</strong> you can <strong>visit the cart</strong> and you will see the <strong>expensive item now</strong> as a <strong>very cheap</strong> one!</p>



<p><strong>In the end</strong>, <strong>this is</strong> how our <strong>final cart screen</strong> looks like:</p>



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2022/01/Final-cart-screen-with-manipulated-price.png"><img loading="lazy" decoding="async" width="1279" height="817" src="https://robbelroot.de/wp-content/uploads/2022/01/Final-cart-screen-with-manipulated-price.png" alt="Final cart screen with manipulated price" class="wp-image-7696" title="Final cart screen with manipulated price"/></a><figcaption>Final cart screen with manipulated price</figcaption></figure>



<h2 class="wp-block-heading" id="conclusion-hacking-a-webshop">Conclusion – Hacking a webshop</h2>



<p>So <strong>at the end</strong> of this interesting blog post, i think <strong>we can agree on</strong> one thing: <strong>Never trust the client side</strong>!!</p>



<p><strong>For normal users</strong>, the client side may be the <strong>bright side of life</strong>, but <strong>not for us</strong> as <strong>developers</strong>!</p>



<p><strong>Next to many other things</strong> which could&#8217;ve been improved or being implemented at all, <strong>theres the dangerous main thing</strong>.</p>



<p>The <strong>product price gets send by the client and trusted by the server</strong>, which is (in mortal combat language) &#8222;fatality&#8220;!</p>



<p><strong>Instead of this</strong>, <strong>you should</strong> actually <strong>have </strong>some sort of <strong>dataset </strong>in your database, to <strong>pull the price</strong> at request.</p>



<p>The <strong>client saying</strong>: &#8222;<strong>I want that product</strong> in my cart&#8220; is <strong>not a problem</strong> at all.</p>



<p><strong>Next thing</strong> you should <strong>keep in mind</strong> when designing/creating such a type of thing also has to do with like pricing.</p>



<p><strong>Even if</strong> you <strong>pull </strong>that <strong>price from the database</strong> at the moment the customer puts it into the cart, <strong>think about changes</strong>.</p>



<p><strong>When some guy</strong> using like a CRM to <strong>change that price while</strong> a customer has the <strong>product inside its cart</strong>, that could also be a problem.</p>



<h2 class="wp-block-heading" id="downloads">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="https://bit.ly/hacking-a-webshop-download" target="_blank" rel="noreferrer noopener">crapshop.zip</a></div>
</div>



<h2 class="wp-block-heading" id="related-posts">Related posts</h2>



<ul class="wp-block-list"><li><a href="https://robbelroot.de/blog/hacking-a-net-application/" target="_blank" rel="noreferrer noopener"><strong>Hacking a NET Application</strong></a></li></ul>
<p>Der Beitrag <a href="https://robbelroot.de/blog/hacking-a-webshop/">&#x1f575;&#xfe0f; Hacking a Webshop – don&#8217;t fall for this common trap!</a> erschien zuerst auf <a href="https://robbelroot.de">Robert Skibbe</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://robbelroot.de/blog/hacking-a-webshop/feed/</wfw:commentRss>
			<slash:comments>4</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>
		<item>
		<title>VB.NET Webbrowser Control</title>
		<link>https://robbelroot.de/blog/vbnet-webbrowser-control/</link>
					<comments>https://robbelroot.de/blog/vbnet-webbrowser-control/#comments</comments>
		
		<dc:creator><![CDATA[Robert Skibbe]]></dc:creator>
		<pubDate>Sun, 04 Jul 2021 14:07:54 +0000</pubDate>
				<category><![CDATA[Allgemein]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[Visual Basic .NET]]></category>
		<category><![CDATA[Visual Basic .NET lernen]]></category>
		<category><![CDATA[browse]]></category>
		<category><![CDATA[browser]]></category>
		<category><![CDATA[chrome]]></category>
		<category><![CDATA[control]]></category>
		<category><![CDATA[edge]]></category>
		<category><![CDATA[firefox]]></category>
		<category><![CDATA[http]]></category>
		<category><![CDATA[https]]></category>
		<category><![CDATA[internet]]></category>
		<category><![CDATA[internet explorer]]></category>
		<category><![CDATA[navigate]]></category>
		<category><![CDATA[navigieren]]></category>
		<category><![CDATA[net]]></category>
		<category><![CDATA[opera]]></category>
		<category><![CDATA[steuerelement]]></category>
		<category><![CDATA[url]]></category>
		<category><![CDATA[vb.net]]></category>
		<category><![CDATA[vbnet]]></category>
		<category><![CDATA[webbrowser]]></category>
		<category><![CDATA[www]]></category>
		<guid isPermaLink="false">https://robbelroot.de/?p=2935</guid>

					<description><![CDATA[<p>VB.NET Webbrowser Control In diesem Beitrag zeige ich Dir wichtige Eigenschaften und Funktionalitäten des VB.NET Webbrowser Control. Von Zeit zu Zeit könnte es vorkommen, dass Du in deinem Programm auch mal einen Webbrowser darstellen und ggf. im Detail damit arbeiten musst. Diese Arbeit kann unter anderem sein, dass Du den &#8230;</p>
<p>Der Beitrag <a href="https://robbelroot.de/blog/vbnet-webbrowser-control/">VB.NET Webbrowser Control</a> erschien zuerst auf <a href="https://robbelroot.de">Robert Skibbe</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-large"><a href="https://robbelroot.de/wp-content/uploads/2021/07/VB.NET-Webbrowser-Control.png"><img loading="lazy" decoding="async" width="1024" height="536" src="https://robbelroot.de/wp-content/uploads/2021/07/VB.NET-Webbrowser-Control-1024x536.png" alt="VB.NET Webbrowser Control" class="wp-image-2937" title="VB.NET Webbrowser Control" srcset="https://robbelroot.de/wp-content/uploads/2021/07/VB.NET-Webbrowser-Control-1024x536.png 1024w, https://robbelroot.de/wp-content/uploads/2021/07/VB.NET-Webbrowser-Control-300x157.png 300w, https://robbelroot.de/wp-content/uploads/2021/07/VB.NET-Webbrowser-Control-768x402.png 768w, https://robbelroot.de/wp-content/uploads/2021/07/VB.NET-Webbrowser-Control-700x366.png 700w, https://robbelroot.de/wp-content/uploads/2021/07/VB.NET-Webbrowser-Control-332x174.png 332w, https://robbelroot.de/wp-content/uploads/2021/07/VB.NET-Webbrowser-Control.png 1200w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a><figcaption>VB.NET Webbrowser Control</figcaption></figure>






<h2 class="wp-block-heading" id="vb-net-webbrowser-control">VB.NET Webbrowser Control</h2>



<p>In <strong>diesem Beitrag </strong>zeige ich Dir <strong>wichtige Eigenschaften </strong>und <strong>Funktionalitäten </strong>des <strong>VB.NET Webbrowser Control</strong>.</p>



<p>Von Zeit zu Zeit <strong>könnte </strong>es <strong>vorkommen</strong>, <strong>dass </strong>Du <strong>in </strong>deinem <strong>Programm </strong>auch mal <strong>einen Webbrowser </strong>darstellen und ggf. <strong>im Detail </strong>damit<strong> arbeiten </strong>musst.</p>



<p>Diese <strong>Arbeit kann </strong>unter anderem <strong>sein</strong>, <strong>dass </strong>Du den <strong>Quelltext </strong>einer Seite <strong>auslesen oder </strong>die <strong>Oberfläche automatisieren </strong>möchtest, das zeige ich auch im Beitrag &#8222;<strong><a href="https://robbelroot.de/blog/vbnet-webbrowser-get-element-by-class/" target="_blank" rel="noreferrer noopener">VB.NET Get Element By Class</a></strong>&#8222;.</p>



<p><strong>Falls </strong>Du z. B. <strong>nur </strong>eine <strong>Webseite </strong>ohne eigenes Steuerelement <strong>öffnen </strong>möchtest, wirst Du in meinem <strong><a href="/blog/vbnet-webseite-oeffnen" target="_blank" rel="noreferrer noopener">VB.NET Webseite öffnen Beitrag fündig</a></strong>.</p>



<h2 class="wp-block-heading" id="code">Code</h2>



<p><strong>Um mit </strong>dem <strong>VB.NET Webbrowser Control</strong> <strong>zu starten</strong>, <strong>ziehen </strong>wir es einfach <strong>aus </strong>der <strong>Toolbox</strong> auf die Form und starten durch &#x1f913;.</p>



<p>In meinem ersten Beispiel stelle ich die <strong><a href="https://docs.microsoft.com/de-de/dotnet/api/system.windows.forms.control.dock?view=net-5.0" target="_blank" rel="noreferrer noopener">Dock-Eigenschaft</a></strong> des <strong><a href="https://docs.microsoft.com/de-de/dotnet/api/system.windows.forms.webbrowser?view=net-5.0" target="_blank" rel="noreferrer noopener">Webbrowsers</a></strong> <strong>auf None</strong>, <strong>damit </strong>Dieser <strong>nicht </strong>die komplette <strong>Form einnimmt </strong>und ich noch <strong>für Buttons Platz </strong>habe.</p>



<p>Ebenso <strong>stelle ich </strong>die Eigenschaft <strong><a href="https://docs.microsoft.com/de-de/dotnet/api/system.windows.forms.webbrowser.scripterrorssuppressed?view=net-5.0" target="_blank" rel="noreferrer noopener">ScriptErrorsSuppressed</a></strong> <strong>auf True</strong>, ansonsten <strong>bekommt man </strong>so gut wie auf jeder Seite <strong>hunderte Errors </strong>an den Kopf geschmissen.</p>



<p><strong>Zu </strong>guter <strong>Letzt </strong>stelle ich den <strong>Namen </strong>des <strong>Webbrowsers auf </strong>&#8222;<strong>wb</strong>&#8222;, um nicht jedes Mal &#8222;<strong>Webbrowser1</strong>&#8220; <strong>schreiben </strong>zu <strong>müssen</strong>.</p>



<p><strong>Da </strong>es der <strong>einzige Webbrowser </strong>der Anwendung sein wird, sehe ich hier auch <strong>keinen Grund </strong>es – wie sonst immer – <strong>passend </strong>zu <strong>benennen</strong>, denn: &#8222;Was ist hier passend!?&#8220;.</p>



<h3 class="wp-block-heading" id="seite-offnen">Seite öffnen</h3>



<p><strong>Um </strong>mit dem <strong>VB.NET Webbrowser Control</strong> gezielt, also via URL zu <strong>navigieren</strong>, bzw. Ihn mehr oder weniger navigieren zu lassen, <strong>können </strong>wir dessen <strong><a href="https://docs.microsoft.com/de-de/dotnet/api/system.windows.forms.webbrowser.navigate?view=net-5.0" target="_blank" rel="noreferrer noopener">Navigate-Methode</a></strong> <strong>verwenden</strong>.</p>



<p><strong>Dafür </strong>nehme ich das <strong>Beispiel </strong>aus dem Sample-Code, wo wir <strong>analog zu </strong>den gängigen <strong>Browsern aus </strong>einer <strong>Textbox </strong>heraus <strong>navigieren</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="">Private Sub btnGo_Click(sender As Object, e As EventArgs) Handles btnGo.Click
    wb.Navigate("https://google.de")
End Sub</pre>



<h3 class="wp-block-heading" id="seite-bei-start-laden-vb-net-webbrowser-control">Seite bei Start laden – VB.NET Webbrowser Control</h3>



<p>Wir können <strong>neben </strong>dem <strong>manuellen Navigieren auch </strong>schon <strong>bei Start </strong>der Form eine URL <strong>laden </strong>lassen.</p>



<p>Um den <strong>Browser </strong>schon <strong>bei Start </strong>eine <strong>Url laden </strong>zu lassen, setzen wir einfach <strong>im Designer </strong>die <strong><a href="https://docs.microsoft.com/de-de/dotnet/api/system.windows.forms.webbrowser.url?view=net-5.0" target="_blank" rel="noreferrer noopener">Url-Eigenschaft</a></strong></p>



<h3 class="wp-block-heading" id="aktualisieren">Aktualisieren</h3>



<p><strong>Ähnlich wie </strong>in bekannten <strong>Webbrowsern</strong>, haben wir <strong>auch hier </strong>die Möglichkeit den <strong>Browser</strong>, bzw. dessen Seite mit Hilfe der <strong><a href="https://docs.microsoft.com/de-de/dotnet/api/system.windows.forms.webbrowser.refresh?view=net-5.0" target="_blank" rel="noreferrer noopener">Refresh-Methode</a></strong> <strong>zu aktualisieren</strong>.</p>



<p>In unserem Beispiel <strong>platziere </strong>ich den Aktualisierungs-<strong>Button </strong>– wie gängig – oben:</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 btnRefresh_Click(sender As Object, e As EventArgs) Handles btnRefresh.Click
    wb.Refresh()
End Sub</pre>



<h3 class="wp-block-heading" id="vorwarts-navigieren">Vorwärts navigieren</h3>



<p>Der Webbrowser kann durch den Aufruf der <strong><a href="https://docs.microsoft.com/de-de/dotnet/api/system.windows.forms.webbrowser.goforward?view=net-5.0" target="_blank" rel="noreferrer noopener">&#8222;GoForward&#8220;-Methode</a></strong> vorwärts navigieren, aber um es sauber zu machen, müssen wir auch auf die passende Eigenschaft namens &#8222;<strong><a href="https://docs.microsoft.com/en-us/dotnet/api/system.windows.forms.webbrowser.cangoforward?view=net-5.0" target="_blank" rel="noreferrer noopener">CanGoForward</a></strong>&#8220; achten.</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 btnForward_Click(sender As Object, e As EventArgs) Handles btnForward.Click
    If wb.CanGoForward Then
        wb.GoForward()
    End If
End Sub</pre>



<h3 class="wp-block-heading" id="ruckwarts-navigieren">Rückwärts navigieren</h3>



<p><strong>Ähnlich wie </strong>beim navigieren <strong>nach vorn</strong>, verfahren wir auch hier, wir <strong>prüfen </strong>die <strong><a href="https://docs.microsoft.com/en-us/dotnet/api/system.windows.forms.webbrowser.cangoback?view=net-5.0" target="_blank" rel="noreferrer noopener">&#8222;CanGoBack&#8220;-Eigenschaft</a></strong> und <strong>navigieren </strong>entsprechend.</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 btnBack_Click(sender As Object, e As EventArgs) Handles btnBack.Click
    If wb.CanGoBack Then
        wb.GoBack()
    End If
End Sub</pre>



<h3 class="wp-block-heading" id="scrollbalken-scrollbarsenabled">Scrollbalken – ScrollBarsEnabled</h3>



<p>Man kann in dem <strong>Webbrowser</strong>-Control auch die <strong>Scrollbalken kontrollieren </strong>indem man dafür die <strong>vorgesehene Eigenschaft </strong>namens &#8222;<strong>ScrollBarsEnabled</strong>&#8220; entsprechend auf <strong>True</strong>, <strong>oder False </strong>stellt.</p>



<h3 class="wp-block-heading" id="kontextmenu-iswebbrowsercontextmenuenabled">Kontextmenü – IsWebBrowserContextMenuEnabled</h3>



<p>Da <strong>Webbrowser </strong>für <strong>gewöhnlich </strong>ein <strong>eigenes Kontextmenü </strong>haben, hat sich das .NET-Team <strong>auch hier </strong>für eine <strong>Konfigurationsmöglichkeit </strong>entschieden</p>



<p>Es <strong>handelt sich um </strong>die <strong>IsWebBrowserContextMenuEnabled</strong>-Eigenschaft, mit dessen Hilfe wir – wie der Name schon erraten lässt – das <strong>native Kontextmenü </strong>des Browsers <strong>aktivieren</strong>, oder <strong>deaktivieren </strong>können.</p>



<h3 class="wp-block-heading" id="seite-fixieren-allownavigation">Seite fixieren – AllowNavigation</h3>



<p>In <strong>gewissen Anwendungsfällen </strong>kann es vorkommen, dass man nach dem <strong>initialen Aufruf </strong>einer Webseite <strong>nicht </strong>möchte, dass zu einer <strong>anderen Seite navigiert </strong>werden kann.</p>



<p>Mit der <strong>AllowNavigation</strong>&#8211;<strong>Eigenschaft </strong>können wir <strong>vermeiden</strong>, dass <strong>andere Webseiten aufgerufen </strong>werden.</p>



<h3 class="wp-block-heading" id="tastenkombinationen-webbrowsershortcutsenabled">Tastenkombinationen – WebBrowserShortcutsEnabled</h3>



<p>Die <strong><a href="https://docs.microsoft.com/de-de/dotnet/api/system.windows.forms.webbrowser.webbrowsershortcutsenabled?view=net-5.0" target="_blank" rel="noreferrer noopener">WebBrowserShortcutsEnabled-Eigenschaft</a></strong> legt fest, ob im Browser die <strong>Tastenkombinationen</strong>, bzw. die Tastenkürzel <strong>aktiviert</strong>, oder <strong>deaktiviert </strong>sind.</p>



<h2 class="wp-block-heading" id="style-engine">Style &amp; Engine</h2>



<h3 class="wp-block-heading" id="moderneres-vb-net-webbrowser-control">Moderneres VB.NET Webbrowser Control</h3>



<p><strong>Nach </strong>einiger <strong>Zeit </strong>die Du <strong>mit </strong>dem <strong>Webbrowser </strong>verbracht hast, wirst Du Dich vermutlich <strong>fragen</strong>, <strong>ob</strong> es nicht <strong>auch </strong>eine <strong>schönere </strong>und <strong>modernere Variante </strong>für das Steuerelement gibt.</p>



<p>Zum Glück <strong>kann </strong>ich <strong>dich beruhigen</strong>, ja diese neuere und <strong>tollere Variante </strong>gibt es!</p>



<p>So können wir einerseits die <strong>Verarbeitung </strong>von <strong>Stylesheets verbessern</strong>, die <strong>Fehler </strong>die im alten Control häufiger auftreten <strong>reduzieren </strong>und vor allem <strong>Performance </strong>und <strong>Support optimieren</strong>.</p>



<p><strong>Wie </strong>man ein <strong>alternatives Webbrowser</strong>-Control verwendet zeige ich Dir <strong>in </strong>einem <strong><a href="https://robbelroot.de/blog/vb-net-webbrowser-alternative/" target="_blank" rel="noreferrer noopener">anderen Beitrag</a></strong>.</p>



<h2 class="wp-block-heading" id="dokument-vb-net-webbrowser-control">Dokument – VB.NET Webbrowser Control</h2>



<p><strong>Wer </strong>ein wenig <strong>Erfahrung </strong>mit <strong>JavaScript </strong>hat wird sich eventuell <strong>fragen</strong>, <strong>ob </strong>man auch in VB.NET an das <strong>Document </strong>des Webbrowsers rankommen kann, kurze Antwort: &#8222;<strong>Ja</strong>, kann man!&#8220;.</p>



<p><strong>Um </strong>an das <strong>Document </strong>des Browsers zu kommen, muss man <strong>einfach nur </strong>die <strong>Document</strong>-Eigenschaft des <strong>Browsers </strong>verwenden und kann dann einige <strong>gewohnte Funktionen </strong>wie <strong>getElementById</strong>() aus <strong>JavaScript </strong>verwenden.</p>



<p><strong>Diese Funktionen </strong>sind <strong>insbesondere </strong>für die <strong>Automation </strong>des VB.NET Webbrowser Controls von <strong>Vorteil </strong>und können Dir so auf verschiedene Arten und Weisen einen Vorteil verschaffen <strong>z. B.</strong> <strong>für </strong>einen <strong>Login </strong>o. Ä.</p>



<h2 class="wp-block-heading" id="kompletter-code-vb-net-webbrowser-control">Kompletter Code – VB.NET Webbrowser Control</h2>



<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 Form1

    Private Sub btnRefresh_Click(sender As Object, e As EventArgs) Handles btnRefresh.Click
        wb.Refresh()
    End Sub

    Private Sub btnGo_Click(sender As Object, e As EventArgs) Handles btnGo.Click
        wb.Navigate(tbUrl.Text)
    End Sub

    Private Sub btnBack_Click(sender As Object, e As EventArgs) Handles btnBack.Click
        If wb.CanGoBack Then
            wb.GoBack()
        End If
    End Sub

    Private Sub btnForward_Click(sender As Object, e As EventArgs) Handles btnForward.Click
        If wb.CanGoForward Then
            wb.GoForward()
        End If
    End Sub

    Private Sub tbUrl_KeyDown(sender As Object, e As KeyEventArgs) Handles tbUrl.KeyDown
        If e.KeyCode = Keys.Enter Then
            wb.Navigate(tbUrl.Text)
        End If
    End Sub

End Class</pre>



<h2 class="wp-block-heading" id="downloads">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/vbnet/WebbrowserControlExample.zip" target="_blank" rel="noreferrer noopener">WebbrowserControlExample.zip</a></div>
</div>



<p></p>
<p>Der Beitrag <a href="https://robbelroot.de/blog/vbnet-webbrowser-control/">VB.NET Webbrowser Control</a> erschien zuerst auf <a href="https://robbelroot.de">Robert Skibbe</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://robbelroot.de/blog/vbnet-webbrowser-control/feed/</wfw:commentRss>
			<slash:comments>3</slash:comments>
		
		
			</item>
	</channel>
</rss>
