Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / desktop / WPF

Yahoo Currency .NET CORE API - C#

0.00/5 (No votes)
18 Nov 2017CPOL6 min read 8.8K  
Convert between over 100 different currencies in .NET using Yahoo's APIs

GitHub (Lib and Demo) and Short Teaser Video

Introduction

Actually, I've never needed an API to do currency conversions, but I've just found these services provided by Yahoo YQL interesting and so I built an API to wrap this.

This is a .NET CORE 2 API written in C#(7) thought to be multi-platform and usable in mobile development (through Xamarin Forms and etc).

Think about this API as an Object Model for the Yahoo Currency API. It encapsulates all the data and lets you to work with it more naturally.

The most interesting thing is that it implements Async support and also INotifyPropertyChanged. That means, you can declare it and bind it to XAML, in a very nice way.

This project and a WPF demo is completely available on GITHUB.

This is the first release of this project, I did many tests and it worked very well. As I'm sharing this on GITHUB, the main goal is to improve it, as possible, with the hand of everyone. So, if you find an unexpected behavior or a bug, please don't vote down. Fork it or just let me know, let's improve it together.

Background

The main thing here is about the Yahoo Query Language or, in short words, YQL!

What is YQL? According to Wikipedia:

Quote:

Yahoo! Query Language (YQL) is an SQL-like query language created by Yahoo! as part of their Developer Network. YQL is designed to retrieve and manipulate data from APIs through a single Web interface, thus allowing mashups that enable developers to create their own applications.

Initially launched in October 2008 with access to Yahoo APIs, February 2009 saw the addition of open data tables from third parties such as Google Reader, the Guardian, and The New York Times. Some of these APIs still require an API key to access them. On April 29 of 2009, Yahoo introduced the capability to execute the tables of data built through YQL using JavaScript run on the company's servers for free.

So, in short, I've just managed to write a simple and clear code to "talk" with Yahoo, through the YQL, asking for the updated currency quotes.

You can obtain the updated currency quotes easily by accessing this link. As you see, it returns an XML document with the updated quotes for all the currencies available!

So, what I've done is just send a web request to that web address, get the response and parse it! Way simple!

I'm not going to explain abount YQL, this is just pointless. You can find the complete documentation, samples and more on the official site:

YQL - Yahoo Developer Network

Using the Code

There are, basically, two ways of coding with this library. The first one is through the code behind (C# or VB.NET) in an asynchronous or synchronous way as you can see below:
C#
/// <summary>
/// The code bellow is simple example of how tu use the await keyword in the initialization
/// </summary>
/// <returns></returns>
public static async Task AsyncExample()
{
    HL.YahooCurrency.Currency currency = new HL.YahooCurrency.Currency();
    
    //YOU MUST NOT FORGET THE LINE BELLOW
    //It's very important that you wait the initialization of this object
    await currency.WaitLoad();
    
    //Select the source conversion unit(currency)
    currency.SourceUnit = currency.Units.ElementAt(0);
    //Select the output conversion unit(currency)
    currency.OutputUnit = currency.Units.ElementAt(1);
    //Gives a value for conversion
    currency.SourceValue = 2.32f;
    //Writes out the value converted to the output unit(currency)
    System.Diagnostics.Debug.WriteLine(currency.OutputValue);
}

/// <summary>
/// The code bellow is a simple example of how you should code (Synchronous)
/// </summary>
public static void SynchronousExample()
{
    HL.YahooCurrency.Currency currency = new HL.YahooCurrency.Currency();
    
    //YOU MUST NOT FORGET THE LINE BELLOW
    //It's very important that you wait the initialization of this object
    //Instead of using await and waiting asynchronous, you can use .Wait() and
    //it will block the current thread till the background data gets all downloaded and parsed
    //this usually takes 1 second in a good internet connection but, 
    //in a modest environment, it can take like 6 seconds
    currency.WaitLoad().Wait();
    
    //Select the source conversion unit(currency)
    currency.SourceUnit = currency.Units.ElementAt(0);
    //Select the output conversion unit(currency)
    currency.OutputUnit = currency.Units.ElementAt(1);
    //Gives a value for conversion
    currency.SourceValue = 2.32f;
    //Writes out the value converted to the output unit(currency)
    System.Diagnostics.Debug.WriteLine(currency.OutputValue);
}

It is very important to mention that on both synchronous and asynchronous contexts, you MUST invoke the method WaitLoad(). Why? Simple!

As you well know, we can't declare an async constructor and this just sounds crazy! Anyway, the constructor of the class Currency invokes a async Task to make a web request and parse the data in a way that prevents the user interface from freezing while waiting for this process (That takes between 1 to 5 seconds, depending on the user network connection speed).

The main thing here is: The WaitLoad() method returns the running task created for initialize the Currency object in background. So, as you might have thought, it is trivial to wait for that task to end. If you are going to use async, you just need to await the WaitLoad(). If you are not in an async context, you shall block the executing thread while the background task is still running. Both scenarios are coded above, as you can see.

The second way, is directly on XAML:
XML
<Window x:Class="Yahoo_Currency_WPF_DEMO.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:Yahoo_Currency_WPF_DEMO"
xmlns:yahoo="clr-namespace:HL.YahooCurrency;assembly=HL.YahooCurrency"
        mc:Ignorable="d"
        Title="HL.YahooWeather WPF DEMO" Height="350" 
        Width="600" WindowStartupLocation="CenterScreen">
    <Window.Resources>
        <BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
        <local:InvertBoolConverter x:Key="InvertBoolConverter"/>
        <local:BytesToBitmapImageValueConverter x:Key="BytesToBitmapImageValueConverter"/>
        <local:StringToDoubleConverter x:Key="StringToDoubleConverter"/>
    </Window.Resources>
    <Window.DataContext>
        <yahoo:Currency/>
    </Window.DataContext>
    <Grid IsEnabled="{Binding IsLoading, 
    Converter={StaticResource InvertBoolConverter}, Mode=OneWay}">
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <GridSplitter HorizontalAlignment="Center" 
        Margin="0" Grid.ColumnSpan="2" 
        Width="1" Background="Black"/>
        <Label Content="Input" HorizontalAlignment="Center" 
        Margin="0,15,0,0" VerticalAlignment="Top" FontSize="18.667"/>
        <Label Content="Output" HorizontalAlignment="Center" 
        Margin="0,15,0,0" VerticalAlignment="Top" 
        FontSize="18.667" Grid.Column="1"/>
        <TextBox Height="23" Margin="10,102.6,10,0" 
        TextWrapping="Wrap" Text="{Binding SourceValue, 
        BindsDirectlyToSource=True, Converter={StaticResource StringToDoubleConverter}, 
        IsAsync=True, Mode=OneWayToSource, ValidatesOnNotifyDataErrors=False, 
        UpdateSourceTrigger=PropertyChanged, TargetNullValue=0}" 
        VerticalAlignment="Top" Width="238.3" 
        PreviewTextInput="TextBox_PreviewTextInput" MaxLength="16"/>
        <ComboBox Margin="10,75.64,10,0" VerticalAlignment="Top" 
        Width="238.3" Grid.Column="1" ItemsSource="{Binding Units}" 
        SelectedIndex="0" SelectedValue="{Binding OutputUnit, 
        Mode=OneWayToSource}" IsSynchronizedWithCurrentItem="False" 
        Loaded="ComboBox_Loaded"/>
        <ComboBox Margin="10,75.64,10,0" VerticalAlignment="Top" 
        Width="238.3" ItemsSource="{Binding Units}" 
        SelectedIndex="0" SelectedValue="{Binding SourceUnit, 
        Mode=OneWayToSource}" IsSynchronizedWithCurrentItem="False" 
        TabIndex="2147483646" MinWidth="10" Loaded="ComboBox_Loaded"/>
        <TextBox Height="23" Margin="10,102.6,10,0" 
        TextWrapping="Wrap" Text="{Binding OutputValue, Mode=OneWay, 
        StringFormat=N2}" VerticalAlignment="Top" Width="238.3" 
        Grid.Column="1" IsReadOnly="True"/>
        <GroupBox Header="Information" Margin="10,130.6,10,10">
            <Grid>
                <Image HorizontalAlignment="Left" Height="55" 
                VerticalAlignment="Top" Width="88" 
                Source="{Binding SourceUnitInfo.Flag, 
                Converter={StaticResource BytesToBitmapImageValueConverter}}"/>
                <Label Content="{Binding SourceUnitInfo.Country, 
                Mode=OneWay}" HorizontalAlignment="Left" 
                Margin="93,15.04,0,0" VerticalAlignment="Top"/>
                <Label Content="Currency: " 
                HorizontalAlignment="Left" Margin="10,60,0,0" 
                VerticalAlignment="Top"/>
                <Label Content="Currency Symbol:" 
                HorizontalAlignment="Left" Margin="10,90.96,0,0" 
                VerticalAlignment="Top"/>
                <Label Content="{Binding SourceUnitInfo.Currency, 
                Mode=OneWay}" HorizontalAlignment="Left" 
                Margin="77.87,60,0,0" VerticalAlignment="Top"/>
                <Label Content="{Binding SourceUnitInfo.Symbol, Mode=OneWay}" 
                HorizontalAlignment="Left" Margin="112.376,90.96,0,0" 
                VerticalAlignment="Top"/>
            </Grid>
        </GroupBox>
        <GroupBox Header="Information" Margin="10,130.6,10,10" Grid.Column="1">
            <Grid>
                <Image HorizontalAlignment="Left" Height="55" 
                VerticalAlignment="Top" Width="88" 
                Source="{Binding OutputUnitInfo.Flag, 
                Converter={StaticResource BytesToBitmapImageValueConverter}}"/>
                <Label Content="{Binding OutputUnitInfo.Country, 
                Mode=OneWay}" HorizontalAlignment="Left" 
                Margin="93,15.04,0,0" VerticalAlignment="Top"/>
                <Label Content="Currency: " 
                HorizontalAlignment="Left" Margin="10,60,0,0" 
                VerticalAlignment="Top"/>
                <Label Content="Currency Symbol:" 
                HorizontalAlignment="Left" Margin="10,90.96,0,0" 
                VerticalAlignment="Top"/>
                <Label Content="{Binding OutputUnitInfo.Currency, 
                Mode=OneWay}" HorizontalAlignment="Left" 
                Margin="72.87,60,0,0" VerticalAlignment="Top"/>
                <Label Content="{Binding OutputUnitInfo.Symbol, 
                Mode=OneWay}" HorizontalAlignment="Left" 
                Margin="112.376,90.96,0,0" VerticalAlignment="Top"/>
            </Grid>
        </GroupBox>
        <!--IMPORTANT: THE CODE BELLOW CAUSES A CONSTANT 6% CPU TIME-->
        <Border BorderThickness="1" Grid.ColumnSpan="2" 
        Background="WhiteSmoke" Visibility="{Binding IsLoading, 
        Converter={StaticResource BooleanToVisibilityConverter}, Mode=OneWay}">
            <Grid>
                <TextBlock Text="Loading Data" VerticalAlignment="Center" 
                HorizontalAlignment="Center" FontSize="22"/>
                <ProgressBar HorizontalAlignment="Center" Height="10" 
                VerticalAlignment="Center" Width="140" 
                Margin="0,54,0,0" IsIndeterminate="True"/>
            </Grid>
        </Border>
    </Grid>
</Window>

In short, I'm declaring the Currency object as the Data Context in this window. Also, the Currency class has a bindable property called IsLoading. When any request or data parsing operation is going on in the background, this property will be set to true till the end of the task! This enables you to create a responsive and smart UI for your applications.The coolest things (I think) come now!!!

Special Features

I've embedded a database on this API that will return interesting information about all the currencies.

This information is:

  1. The name of the country from where this currency is.
  2. A flag picture of the currency country.
  3. The unicode symbol of the currency.
  4. The currency code.

In fact, this is not just a wrapper around Yahoo Services. It's more like a solution for currency conversion. Also, there's a method called UpdateAsync() that allows you to update the Currency object you are working with.

Points of Interest

The most interesting thing here, in my viewpoint, is the asynchronous initialization of an object. In fact, this is a very interesting approach.

Note that, on the XAML code of the WPF demo, there is a commented line about ~6% CPU usage. In fact, I've found that when you hide a progress bar control on WPF (at least here), it keeps draining CPU time to draw the progress bar, even though it's hidden! A bug on Windows Presentation Foundation?

I'd like to mention that I've also used some interesting value converters on this demo. The most interesting is the InvertBoolConverter. It can be used when you need to bind to a bool property and want to get that value inverted. For example, if you want to bind the IsEnabled property of some control to the IsLoading property of Currency. You might want to keep the IsEnabled to false when IsLoading is true. This is the trick!

API Documentation

Before you ask me, let me explain it.

All the classes, methods and properties of this API are summarized. So, you are going to get some help when coding.

Even though I know that would be nice to build a little documentation, by now I'm busy with some other things and don't have time for that :/.

However, as the API is very simple, and there is a demo, I believe you will not have any trouble to code with it!

Another Useful API

You can find on my GITHUB another wrapper for another Yahoo's services. This one is related to Weather.

It's an .NET Core 2 API, written like the Currency one, for getting forecast information. It also supports async, data binding, etc. I pretend to write an article/tip about it in the near future!

History

  • 18/11/2017 - Tip published

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)