<?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>json Archive - Robert Skibbe</title>
	<atom:link href="https://robbelroot.de/blog/tag/json/feed/" rel="self" type="application/rss+xml" />
	<link></link>
	<description>alias RobbelRoot – Freelance Full Stack Developer .NET</description>
	<lastBuildDate>Mon, 19 Dec 2022 08:53:40 +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>json Archive - Robert Skibbe</title>
	<link></link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>rskibbe.I18n.Winforms – Translate your Windows forms apps – but easy</title>
		<link>https://robbelroot.de/blog/rskibbe-i18n-winforms-translate-your-windows-forms-apps-but-easy/</link>
					<comments>https://robbelroot.de/blog/rskibbe-i18n-winforms-translate-your-windows-forms-apps-but-easy/#respond</comments>
		
		<dc:creator><![CDATA[Robert Skibbe]]></dc:creator>
		<pubDate>Mon, 19 Dec 2022 06:45:53 +0000</pubDate>
				<category><![CDATA[General]]></category>
		<category><![CDATA[NuGet Packages]]></category>
		<category><![CDATA[rskibbe]]></category>
		<category><![CDATA[rskibbe.I18n.Winforms]]></category>
		<category><![CDATA[c#]]></category>
		<category><![CDATA[csharp]]></category>
		<category><![CDATA[forms]]></category>
		<category><![CDATA[i18n]]></category>
		<category><![CDATA[ini]]></category>
		<category><![CDATA[internationalization]]></category>
		<category><![CDATA[json]]></category>
		<category><![CDATA[language]]></category>
		<category><![CDATA[multilanguage]]></category>
		<category><![CDATA[net]]></category>
		<category><![CDATA[translate]]></category>
		<category><![CDATA[translation]]></category>
		<category><![CDATA[vbnet]]></category>
		<category><![CDATA[windows]]></category>
		<category><![CDATA[winforms]]></category>
		<guid isPermaLink="false">https://robbelroot.de/?p=12908</guid>

					<description><![CDATA[<p>What is rskibbe.I18n.Winforms? rskibbe.I18n.Winforms is a sub-package that helps you translate your Windows Forms apps easily. It extends the other rskibbe.I18n packages to provide specialized help with the Winforms technology. Keep in mind, that there is another package for WPF as well and that you can refer to the base &#8230;</p>
<p>Der Beitrag <a href="https://robbelroot.de/blog/rskibbe-i18n-winforms-translate-your-windows-forms-apps-but-easy/">rskibbe.I18n.Winforms – Translate your Windows forms apps – but easy</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/12/rskibbe.I18n.Winforms-Multilanguage-Winforms-apps-but-easy-Translate-your-Windows-Forms-apps.png"><img fetchpriority="high" decoding="async" width="640" height="360" src="https://robbelroot.de/wp-content/uploads/2022/12/rskibbe.I18n.Winforms-Multilanguage-Winforms-apps-but-easy-Translate-your-Windows-Forms-apps.png" alt="rskibbe.I18n.Winforms - Multilanguage Winforms apps - but easy - Translate your Windows Forms apps" class="wp-image-12913"/></a><figcaption class="wp-element-caption">rskibbe.I18n.Winforms &#8211; Multilanguage Winforms apps &#8211; but easy &#8211; Translate your Windows Forms apps</figcaption></figure>






<h2 class="wp-block-heading">What is rskibbe.I18n.Winforms?</h2>



<p>rskibbe.I18n.Winforms is a sub-package that helps you translate your Windows Forms apps easily. It extends the other rskibbe.I18n packages to provide specialized help with the Winforms technology. Keep in mind, that there is another package for WPF as well and that you can refer to the <strong><a href="https://robbelroot.de/blog/rskibbe-i18n-translate-create-multilanguage-winforms-wpf-apps/" target="_blank" rel="noreferrer noopener">base package</a></strong> for more information.</p>



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



<p class="info-banner">&#x1f4a1; In a hurry?: No problem, just navigate to the points of interest by using the <strong><a href="#toc_container">table of contents</a></strong> from above, or watch the provided setup video down below.</p>



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


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



<h2 class="wp-block-heading">How to get started?</h2>



<p>To begin with the easy translation of Windows Forms Apps, you first need to install the desired and essential packages. You can do so, by visiting the NuGet Package Manager of your Visual Studio installation. For sure, you can use the NuGet console as well, just as you wish. Search for the term &#8222;rskibbe.I18n&#8220; and you will get all available packages.</p>



<h3 class="wp-block-heading">What we are going to do</h3>



<p>In this quick example, we are going to create a json file based translation for our Windows Forms App. For this, we need to install the following &#8222;rskibbe.I18n&#8220;-packages:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">// install the base package first
Install-Package rskibbe.I18n

// then execute this as well, to install the JSON sub-package
Install-Package rskibbe.I18n.Json

// in the last step, get the package for the Windows Forms stack
Install-Package rskibbe.I18n.Winforms</pre>



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



<p>After you have completed installing the needed / desired packages, you can now go ahead and <strong>import the essential namespaces</strong>. With doing so, you are able to create the translator instance of your needs and translate your forms. Please refer to the <strong><a href="https://robbelroot.de/blog/rskibbe-i18n-translate-create-multilanguage-winforms-wpf-apps/" target="_blank" rel="noreferrer noopener">base package documentation</a></strong>, if you need more information corresponding to it.</p>



<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="namespaces">// don't forget the imports
using rskibbe.I18n.Models;
using rskibbe.I18n.Winforms;</pre>



<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="namespaces">' don't forget the imports
Imports rskibbe.I18n.Models
Imports rskibbe.I18n.Winforms</pre>



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



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2022/11/Setting-up-rskibbe.I18n-for-Winforms-and-WPF-Translation.png"><img decoding="async" width="640" height="360" src="https://robbelroot.de/wp-content/uploads/2022/11/Setting-up-rskibbe.I18n-for-Winforms-and-WPF-Translation.png" alt="Setting up rskibbe.I18n.Winforms for easy Windows Forms translations" class="wp-image-12232"/></a><figcaption class="wp-element-caption">Setting up rskibbe.I18n.Winforms for easy Windows Forms translations</figcaption></figure>



<p>To setup your custom translator, you can just use this easy and quick method:</p>



<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="setup">// before like the first Form InitializeComponent
Translator.Builder
    .WithAutoFormTranslation()
    .Build()
    .StoreInstance();</pre>



<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="setup">' before like the first Form InitializeComponent
Translator.Builder _
    .WithAutoFormTranslation() _
    .Build() _
    .StoreInstance()</pre>



<h3 class="wp-block-heading">An important note</h3>



<p>In this case I&#8217;m using the autodetection feature, that means, I don&#8217;t need to explicitly define the used format like JSON or INI. It will see, which package we&#8217;ve installed, so it will pick it right away. In this case we are using the JSON package. Now it will automatically translate and update corresponding controls like Labels, Buttons and Forms. You don&#8217;t need to configure much more from the coding side &#8211; isn&#8217;t this nice?</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>Remember to do this &#8222;bestly&#8220; before any UI going on, the Bootstrapping point Program.cs/Program.vb or like the first Form Constructor could be the best place (but make sure it doesn&#8217;t get called multiple times).</p>
</blockquote>



<h2 class="wp-block-heading">Marking controls as translatable</h2>



<p>Away from the coding side, we are now going to configure the UI to actually take those translations. For this, you need to tell the translator: &#8222;Hey, <strong>I want this translation, to go over here</strong>&#8222;. You can do so, by just <strong>specifying its tag property</strong> inside the designer!</p>



<h3 class="wp-block-heading">Currently supported Controls</h3>



<p>At this moment, the package supports auto-translation for the following types of controls:</p>



<ul class="wp-block-list">
<li>Buttons</li>



<li>CheckBoxes</li>



<li>GroupBoxes</li>



<li>Labels</li>



<li>LinkLabels</li>
</ul>



<h2 class="wp-block-heading">Full Example</h2>



<h3 class="wp-block-heading">Step 1 – Install packages from NuGet</h3>



<p>The base package is always necessary&nbsp;<a href="https://robbelroot.de/blog/rskibbe-i18n-translate-create-multilanguage-winforms-wpf-apps/" target="_blank" rel="noreferrer noopener"><strong>rskibbe.I18n</strong></a>. Depending on the translation style you want to use (InMemory, file-based like Json or Ini, etc.), install the next package like&nbsp;<a href="https://robbelroot.de/blog/rskibbe-i18n-json-a-json-file-based-translation-sub-package/" target="_blank" rel="noreferrer noopener"><strong>rskibbe.I18n.Json</strong></a>. Now you can install the last helper package for Windows Forms (this one you are looking at right now..)&nbsp;rskibbe.I18n.Winforms.</p>



<h3 class="wp-block-heading">Step 2 – Create a &#8222;Form&#8220;</h3>



<p>Go on like your first form &#8211; usually Form1 &#8211; and put a button on top of it. Name it as you wish, but <strong>specify the Tag property</strong> as &#8222;i18n:myTranslationKey&#8220;. The translator will search for the i18n prefix and will know, that it has to translate it with the corresponding translation key (the thing after the colon).</p>



<h3 class="wp-block-heading">Step 3 – Create the necessary files</h3>



<p>Please take a look at the corresponding package like <strong><a href="https://robbelroot.de/blog/rskibbe-i18n-json-a-json-file-based-translation-sub-package/" target="_blank" rel="noreferrer noopener">rskibbe.I18n.Json</a></strong> or <strong><a href="https://robbelroot.de/blog/rskibbe-i18n-ini-an-ini-file-based-translation-sub-package/" target="_blank" rel="noreferrer noopener">rskibbe.I18n.Ini</a></strong> for file and folder / content structures. More packages for loading from web APIs and like SQL are planned.</p>



<h3 class="wp-block-heading">Step 4 – Specify the code</h3>



<p>To let the translator handle its work, go ahead and use (for example) this code:</p>



<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="full-example">public partial class Form1 : Form
{
    public Form1()
    {
        Translator.Builder
            .WithAutoFormTranslation()
            .Build()
            .StoreInstance();
        InitializeComponent();
    }

    private async void Form1_Load(object sender, EventArgs e)
    {
        await Translator.Instance.LoadLanguagesAsync();
        if (Translator.Instance.HasLanguages)
        {
            var language = Translator.Instance.Languages.SingleOrDefault(x => x.Iso == "en-US");
            await Translator.Instance.ChangeLanguageAsync(language);
        }
    }

    private async void btnSetGerman_Click(object sender, EventArgs e)
    {
        await Translator.Instance.ChangeLanguageAsync("de-DE");
    }

    private async void btnSetEnglish_Click(object sender, EventArgs e)
    {
        await Translator.Instance.ChangeLanguageAsync("en-US");
    }
}</pre>



<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="full-example">Public Partial Class Form1
    Inherits Form

    Public Sub New()
        Translator.Builder _
            .WithAutoFormTranslation() _
            .Build() _
            .StoreInstance()
        InitializeComponent()
    End Sub

    Private Async Sub Form1_Load(ByVal sender As Object, ByVal e As EventArgs)
        Await Translator.Instance.LoadLanguagesAsync()

        If Translator.Instance.HasLanguages Then
            Dim language = Translator.Instance.Languages.SingleOrDefault(Function(x) x.Iso = "en-US")
            Await Translator.Instance.ChangeLanguageAsync(language)
        End If
    End Sub

    Private Async Sub btnSetGerman_Click(ByVal sender As Object, ByVal e As EventArgs)
        Await Translator.Instance.ChangeLanguageAsync("de-DE")
    End Sub

    Private Async Sub btnSetEnglish_Click(ByVal sender As Object, ByVal e As EventArgs)
        Await Translator.Instance.ChangeLanguageAsync("en-US")
    End Sub
End Class</pre>



<p>Please take a look at the base package for more information like getting the available languages, changing the language, etc.</p>
<p>Der Beitrag <a href="https://robbelroot.de/blog/rskibbe-i18n-winforms-translate-your-windows-forms-apps-but-easy/">rskibbe.I18n.Winforms – Translate your Windows forms apps – but easy</a> erschien zuerst auf <a href="https://robbelroot.de">Robert Skibbe</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://robbelroot.de/blog/rskibbe-i18n-winforms-translate-your-windows-forms-apps-but-easy/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>rskibbe.I18n.Json – A JSON file based translation sub-package</title>
		<link>https://robbelroot.de/blog/rskibbe-i18n-json-a-json-file-based-translation-sub-package/</link>
					<comments>https://robbelroot.de/blog/rskibbe-i18n-json-a-json-file-based-translation-sub-package/#comments</comments>
		
		<dc:creator><![CDATA[Robert Skibbe]]></dc:creator>
		<pubDate>Mon, 14 Nov 2022 03:39:42 +0000</pubDate>
				<category><![CDATA[General]]></category>
		<category><![CDATA[NuGet Packages]]></category>
		<category><![CDATA[rskibbe]]></category>
		<category><![CDATA[rskibbe.I18n]]></category>
		<category><![CDATA[rskibbe.I18n.Json]]></category>
		<category><![CDATA[c#]]></category>
		<category><![CDATA[csharp]]></category>
		<category><![CDATA[dotnet]]></category>
		<category><![CDATA[file]]></category>
		<category><![CDATA[i18n]]></category>
		<category><![CDATA[internationalization]]></category>
		<category><![CDATA[json]]></category>
		<category><![CDATA[language]]></category>
		<category><![CDATA[multi]]></category>
		<category><![CDATA[net]]></category>
		<category><![CDATA[parse]]></category>
		<category><![CDATA[read]]></category>
		<category><![CDATA[translate]]></category>
		<category><![CDATA[translation]]></category>
		<category><![CDATA[vbnet]]></category>
		<category><![CDATA[write]]></category>
		<guid isPermaLink="false">https://robbelroot.de/?p=12320</guid>

					<description><![CDATA[<p>What is rskibbe.I18n.Json? This is a sub-package of rskibbe.I18n to provide you with basic implementations for JSON file based translations. Now, go ahead and translate Windows Forms, WPF and Console applications &#8211; but easy. Multi-Language / internationalized apps &#8211; let&#8217;s go! In the next few paragraphs, I&#8217;m going to show &#8230;</p>
<p>Der Beitrag <a href="https://robbelroot.de/blog/rskibbe-i18n-json-a-json-file-based-translation-sub-package/">rskibbe.I18n.Json – A JSON file based translation sub-package</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/11/rskibbe.I18n.Json_.png"><img decoding="async" width="640" height="360" src="https://robbelroot.de/wp-content/uploads/2022/11/rskibbe.I18n.Json_.png" alt="rskibbe.I18n.Json - Translate your .NET apps with this helper package – even easier" class="wp-image-12343" title="rskibbe.I18n.Json - Translate your .NET apps with this helper package – even easier"/></a><figcaption class="wp-element-caption">rskibbe.I18n.Json &#8211; Translate your .NET apps with this helper package – even easier</figcaption></figure>






<h2 class="wp-block-heading">What is rskibbe.I18n.Json?</h2>



<p>This is a sub-package of <strong><a href="https://robbelroot.de/blog/rskibbe-i18n-translate-create-multilanguage-winforms-wpf-apps/" target="_blank" rel="noreferrer noopener">rskibbe.I18n</a></strong> to provide you <strong>with basic implementations for JSON file based translations</strong>. Now, go ahead and translate Windows Forms, WPF and Console applications &#8211; but easy. Multi-Language / internationalized apps &#8211; let&#8217;s go!</p>



<p>In the next few paragraphs, I&#8217;m going to show you, how to get started. As you&#8217;ve probably already seen, this package is a sub-package of <strong><a href="https://robbelroot.de/blog/rskibbe-i18n-translate-create-multilanguage-winforms-wpf-apps/" target="_blank" rel="noreferrer noopener">rskibbe.I18n</a></strong>, so don&#8217;t forget to install that base package as well. As the name already suggests, rskibbe.I18n.Json focusses on file based translations using the JSON format.</p>



<p class="info-banner">&#x1f4a1; In a hurry?: No problem, just navigate to the points of interest by using the&nbsp;<strong><a href="#toc_container">table of contents</a></strong>&nbsp;from above.</p>



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



<h2 class="wp-block-heading">How to get started?</h2>



<p>You can use the NuGet Package Manager from Visual Studio to install this package. If you are in Visual Studio, just click the &#8222;Extra&#8220; menu button on top and navigate to the corresponding item. You could also do a right click on your project (inside the project explorer on the right side) and click &#8222;manage NuGet packages&#8220; next. Now, just search for &#8222;rskibbe.I18n&#8220; and you should be able to see every matching package – and there will be some &#x1f609;.</p>



<p>Or you could just use the following NuGet console commands:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">// install the base package first
Install-Package rskibbe.I18n

// then execute this as well, to install the sub-package
Install-Package rskibbe.I18n.Json</pre>



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



<p>After you have successfully installed both packages, go ahead and import the namespaces to get started. This will make the builder available, so you can get going fast. I won&#8217;t go to deep on the details of the base package, please refer to <strong><a href="https://robbelroot.de/blog/rskibbe-i18n-translate-create-multilanguage-winforms-wpf-apps/" target="_blank" rel="noreferrer noopener">its own documentation</a></strong> for that.</p>



<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="imports-code">using rskibbe.I18n.Models;
using rskibbe.I18n.Json;</pre>



<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="imports-code">Imports rskibbe.I18n.Models
Imports rskibbe.I18n.Json</pre>



<p>Now you are ready to <strong>build your custom Translator</strong> fitting your individual Windows Forms, WPF, or Console App.</p>



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



<figure class="wp-block-image size-full"><a href="https://robbelroot.de/wp-content/uploads/2022/11/Setting-up-rskibbe.I18n-for-Winforms-and-WPF-Translation.png"><img loading="lazy" decoding="async" width="640" height="360" src="https://robbelroot.de/wp-content/uploads/2022/11/Setting-up-rskibbe.I18n-for-Winforms-and-WPF-Translation.png" alt="Setting up rskibbe.I18n.Json for Windows Forms, WPF and Console App Translation" class="wp-image-12232" title="Setting up rskibbe.I18n.Json for Windows Forms, WPF and Console App Translation"/></a><figcaption class="wp-element-caption">Setting up rskibbe.I18n.Json for Windows Forms, WPF and Console App Translation</figcaption></figure>



<h3 class="wp-block-heading">Creating the folder structure</h3>



<p>Inside your output directory (where the finished exe resides, like bin/debug..), create this folder structure: The &#8222;i18n&#8220; base folder at first, then the additional subfolder &#8222;json&#8220;. Inside of that &#8222;json&#8220; folder, create the listed files:</p>



<ul class="wp-block-list">
<li>bin
<ul class="wp-block-list">
<li>debug
<ul class="wp-block-list">
<li><strong>i18n</strong>
<ul class="wp-block-list">
<li><strong>json</strong>
<ul class="wp-block-list">
<li><strong>languages.json</strong></li>



<li><strong>en-US_English.json</strong></li>



<li><strong>de-DE_Deutsch.json</strong></li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>



<h3 class="wp-block-heading">languages.json</h3>



<p>This file represents/contains all available languages for your application &#8211; remember, in JSON format. Matching example contents to the example from above could look like this:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="json" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">[{"iso": "de-DE", "name": "Deutsch"},{"iso": "en-US", "name": "English"}]</pre>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>I specified the german and english language over here. Each one with a name and an iso &#8222;property&#8220;.</p>
</blockquote>



<h3 class="wp-block-heading">Translation files</h3>



<p>Next, we will take a look at the translation files like <strong>&#8222;en-US_English.json&#8220;</strong> from above. As you can see, you need to first <strong>mention the iso code</strong> (should correspond to your language file of course!). Then you just <strong>append</strong> an <strong>underscore with</strong> the specific <strong>language name</strong>.</p>



<p>The corresponding files from above would look like this:</p>



<h4 class="wp-block-heading">Simple</h4>



<h5 class="wp-block-heading">en-US_English.json</h5>



<pre class="EnlighterJSRAW" data-enlighter-language="json" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">{"key1": "Actions", "greeting": "Hello!"}</pre>



<h5 class="wp-block-heading">de-DE_Deutsch.json</h5>



<pre class="EnlighterJSRAW" data-enlighter-language="json" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">{"key1": "Aktionen", "greeting": "Hallo!"}</pre>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>The corresponding translation key would be <strong>&#8222;key1&#8220;</strong>, which would result in &#8222;Actions&#8220; or &#8222;Aktionen&#8220; depending on the language.</p>
</blockquote>



<h4 class="wp-block-heading">Namespaces / nested</h4>



<h5 class="wp-block-heading">en-US_English.json</h5>



<pre class="EnlighterJSRAW" data-enlighter-language="json" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">{"frmMain": {"tsmiActions": "Actions"}}</pre>



<h5 class="wp-block-heading">de-DE_Deutsch.json</h5>



<pre class="EnlighterJSRAW" data-enlighter-language="json" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">{"frmMain": {"tsmiActions": "Aktionen"}}</pre>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>The corresponding translation key would be <strong>&#8222;frmMain.tsmiActions&#8220;</strong>, which is a &#8222;namespaced&#8220; / nested one.</p>
</blockquote>



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



<p>Don&#8217;t forget to take a look at the base package setup, if you need more information. Here&#8217;s just an easy setup using the installed JSON implementations of <strong>ILanguagesLoader</strong> &amp; <strong>ITranslationTablesLoader</strong>. Setting up the translator should be done as early as possible.</p>



<p>In the next step, we are telling the TranslatorBuilder to actually <strong>use the provided loaders from the package</strong>. It will then know &#8222;how do I load the languages&#8220; and &#8222;how do I load the corresponding translations&#8220;. Don&#8217;t forget the imports mentioned above!</p>



<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="code-example">// don't forget the imports somewhere above..
using rskibbe.I18n.Models;
using rskibbe.I18n.Json;

// create and save the instance for later, DI, etc.
var translator = Translator.Builder
     .WithLanguagesLoader&lt;JsonLanguagesLoader>()
     .WithTranslationTableLoader&lt;JsonTranslationTableLoader>()
     .Build()
     .StoreInstance();</pre>



<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="code-example">' don't forget the imports somewhere above..
Imports rskibbe.I18n.Models
Imports rskibbe.I18n.Json

' create and save the instance for later, DI, etc.
Dim translator = Translator.Builder _
     .WithLanguagesLoader(Of JsonLanguagesLoader)() _
     .WithTranslationTableLoader(Of JsonTranslationTableLoader)() _
     .Build() _
     .StoreInstance()</pre>



<h2 class="wp-block-heading">Full Code example</h2>



<p>This is how a full code example could look like (don&#8217;t forget to install all needed packages and import the namespaces):</p>



<pre class="EnlighterJSRAW" data-enlighter-language="csharp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">using rskibbe.I18n.Json;
using rskibbe.I18n.Models;

namespace &lt;YourProjectName>;

public partial class Form1 : Form
{
    public Form1()
    {
        var translator = Translator.Builder
            .WithLanguagesLoader&lt;JsonLanguagesLoader>()
            .WithTranslationTableLoader&lt;JsonTranslationTableLoader>()
            .Build()
            .StoreInstance();
        InitializeComponent();
        Load += Form1_Load;
    }

    private async void Form1_Load(object? sender, EventArgs e)
    {
        await Translator.Instance.LoadLanguagesAsync();
        // after the languages have been loaded, the translator
        // set the language automatically, if WithLanguage("en-US")
        // has been used during initialization
        // if not, you could just trigger the initial language
        // change/set now
        // await Translator.Instance.ChangeLanguageAsync("en-US");

        // you could now get a specific translation by
        // (keep in mind, that on using WithLanguage, you
        // would actually need to like listen to the initial
        // LanguageChanged event, to get the translation)
        ITranslation translation = Translator.Instance.Translate("key1");
        // translation.Value -> Actions in en-US, Aktionen in de-DE
    }
}</pre>
<p>Der Beitrag <a href="https://robbelroot.de/blog/rskibbe-i18n-json-a-json-file-based-translation-sub-package/">rskibbe.I18n.Json – A JSON file based translation sub-package</a> erschien zuerst auf <a href="https://robbelroot.de">Robert Skibbe</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://robbelroot.de/blog/rskibbe-i18n-json-a-json-file-based-translation-sub-package/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>VB NET Web API &#8211; Währungskurs Service Konsum von Grund auf erklärt</title>
		<link>https://robbelroot.de/blog/vb-net-web-api-waehrungskurs-service-konsum-von-grund-auf-erklaert/</link>
					<comments>https://robbelroot.de/blog/vb-net-web-api-waehrungskurs-service-konsum-von-grund-auf-erklaert/#comments</comments>
		
		<dc:creator><![CDATA[Robert Skibbe]]></dc:creator>
		<pubDate>Wed, 29 Sep 2021 16:34:25 +0000</pubDate>
				<category><![CDATA[Allgemein]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[Visual Basic .NET]]></category>
		<category><![CDATA[Visual Basic .NET Problemlösungen]]></category>
		<category><![CDATA[anfrage]]></category>
		<category><![CDATA[api]]></category>
		<category><![CDATA[async]]></category>
		<category><![CDATA[consume]]></category>
		<category><![CDATA[convert]]></category>
		<category><![CDATA[deserialize]]></category>
		<category><![CDATA[get]]></category>
		<category><![CDATA[http]]></category>
		<category><![CDATA[https]]></category>
		<category><![CDATA[json]]></category>
		<category><![CDATA[jsonconvert]]></category>
		<category><![CDATA[konsum]]></category>
		<category><![CDATA[load]]></category>
		<category><![CDATA[method]]></category>
		<category><![CDATA[net]]></category>
		<category><![CDATA[newtonsoft]]></category>
		<category><![CDATA[nuget]]></category>
		<category><![CDATA[object]]></category>
		<category><![CDATA[request]]></category>
		<category><![CDATA[schnittstelle]]></category>
		<category><![CDATA[serialize]]></category>
		<category><![CDATA[service]]></category>
		<category><![CDATA[task]]></category>
		<category><![CDATA[vb.net]]></category>
		<category><![CDATA[vbnet]]></category>
		<category><![CDATA[visual basic]]></category>
		<category><![CDATA[visual basic net]]></category>
		<category><![CDATA[web]]></category>
		<guid isPermaLink="false">https://robbelroot.de/?p=6176</guid>

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






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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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

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

End Interface</pre>



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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

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

End Class</pre>



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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

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

End Class</pre>



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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

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

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



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



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



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



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



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

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

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

    ' parsing..

    Return 0
End Function</pre>



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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

  Public Property success As Boolean

  Public Property timestamp As Integer

  ' ...

End Class</pre>



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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



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

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

End Module</pre>



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



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



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



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



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