Currency Converter using AngularJS, ASP.NET Web API and Web Forms

Welcome to PART 5 of AngularJS tutorial series and we are going to see in detail how to use AngularJS in ASP.NET Web forms a...



Welcome to PART 5 of AngularJS tutorial series and we are going to see in detail how to use AngularJS in ASP.NET Web forms application, making use of $http service to make ajax calls to server. If you are new to AngularJS and wondering why we should go for it when we have many other ways to communicate with server side technologies, then I recommend you to read my previous articles on AngularJS to quickly understand what it is.

Let me start by explaining $http service provided by AngularJS. $http service enables your angularjs application to communicate with server side technology by firing ajax calls to the server. If you know jQuery, then it is similar to $ajax method in jQuery. To demonstrate this, I came up with a small project and created a currency converter application powered by European Central Bank currency feed. This application also deals with other features of angularjs such as custom directives, $scope.watch method.

So first, let us understand the requirements for this simple currency converter application. As you might be knowing, currency rates are subject to change every day, every hour and hence we require a source from where we can get the updated currency rates with a base currency. These kind of currency feeds are licensed and one good open source currency feed, I was able to find is the one provided by European Central Bank. This currency feed is an xml file, that consists of the current equivalent euro value for popular 33 currencies of the world and is updated once every day.

I am going to use ASP.NET Web API in an ASP.NET Web Forms application to query the above explained currency xml file. With ASP.NET Web API, we can access a server side action method using a simple url. It is very easy to understand and can be reused across applications. If you do not have any idea about, how to use ASP.NET Web API in ASP.NET Web Forms application, you can very well take a look at this article to get started instantly. This is not a requirement though to continue reading this tutorial.


1. Let us now create an ASP.NET Web Forms application. The core functionality of getting the exchanged currency value for an input currency value should be done on the server side in a Web API method. Right click on the Web Forms application, Add ->New Item -> Web API Controller class -> Name it as CurrencyController.cs.



2. Delete all the code the wizard had created in CurrencyController.cs and add the below code in it.

namespace WebForms
{
using CurrencyCalculatorAngularJS;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using System.Xml;
using System.Xml.Linq;
using System.Xml.XPath;

public class CurrencyController : ApiController
{
[HttpGet]
[ActionName("convertcurrency")]
public Double ConvertCurrency(string incurrcode,string incurrvalue,string outcurrcode)
{
  string currencyUrl = "http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml";
  string rate = "";
  string incurrcodetoeuro="";
  string outcurrcodetoeuro="";

  Double outcurrencyvalue = 0;
  try
  {
   if (incurrvalue.Equals("0"))
   {                    
      outcurrencyvalue = 0;
   }
   else
   {
    // If input currency code and output currency code are same then return
    // currency value as output currency value
    if (incurrcode.Equals(outcurrcode))
    {
       outcurrencyvalue = Convert.ToDouble(incurrvalue);
    }
    else
    {
 //Fetch Currency Feed XML File
 XDocument xmlDoc = XDocument.Load(currencyUrl);
 foreach (XElement element in xmlDoc.Root.Descendants())
 {
   XName name = element.Name;
   if (name.LocalName == "Cube")
   {
    foreach (XElement elem in element.DescendantNodes())
    {
     //string time = elem.Attribute("time").Value;
     foreach (XElement element1 in elem.DescendantNodes())
     {
  if (element1.Attribute("currency").Value.Equals(incurrcode))
         {
      // the value of 1 equivalent euro to input currency
      //ex input currency code as "USD", 1 EURO = 1.36 USD
             // then, incurrcodetoeuro = 1.36
      incurrcodetoeuro = element1.LastAttribute.Value.ToString();
  }
  else if (element1.Attribute("currency").Value.Equals(outcurrcode))
  {
    // the value of 1 equivalent euro 
           // ex output currency code as "USD", 1 EURO = 1.36 USD
    // then, outcurrcodetoeuro = 1.36
    outcurrcodetoeuro = element1.LastAttribute.Value.ToString();
          }

        }

     }
         }

        }

 // Since the base currency is euro, return outcurrcodetoeuro
 // if the input currency code is equal to "EUR" (Euro)
     
 if (incurrcode.Equals("EUR"))
 {
   rate = outcurrcodetoeuro;
   Double currVal = Convert.ToDouble(rate) * Convert.ToDouble(incurrvalue);                            
          outcurrencyvalue = currVal;
        }

 // If output currency code is "EUR
 // return value = (1/incurrcodetoeuro) * the value to be converted

 else if (outcurrcode.Equals("EUR"))
 {
   rate = incurrcodetoeuro;
   Double currVal = (1 / Convert.ToDouble(rate)) * Convert.ToDouble(incurrvalue);                            
   outcurrencyvalue = currVal;

 }
     
 // return value = 1/incurrcodetoeuro * outcurrcodetoeuro * the value to be converted

 else
        {
   Double fromVal = Convert.ToDouble(incurrcodetoeuro);
   Double toVal = Convert.ToDouble(outcurrcodetoeuro);
   Double baseResult = (1 / fromVal);
   Double currVal = baseResult * toVal * Convert.ToDouble(incurrvalue);                            
   outcurrencyvalue = currVal;
 }
      }
    }
   //Return coverted currency value rounded to 4 decimals
   return Math.Round(outcurrencyvalue, 4);
  }
  catch (FormatException fex)
  {
      return 0;
  }                      
}
}
}

Method ConvertCurrency takes three arguments,

incurrcode = from currency code
outcurrcode = currency code to which the value is to be converted
incurrvalue = currency value which is to be converted

and returns one value,

outcurrencyvalue = final converted currency value.

3. Now we have to add a URI route, so that whenever the uri, 'api/{controller}/{action}/{incurrcode}/{incurrvalue}/{outcurrcode}' is called, it is routed to the Web API method we created in step 2. Open Global.asax.cs file from Solution Explorer and add the following in App_Start method,

using System.Web.Http;

protected void Application_Start(object sender, EventArgs e)
        {
            RouteTable.Routes.MapHttpRoute(
            name: "ActionApi",
            routeTemplate: "api/{controller}/{action}/{incurrcode}/{incurrvalue}/{outcurrcode}",
            defaults: new { incurrvalue = System.Web.Http.RouteParameter.Optional }
            );
        }

4. Server side logic is ready. Let us move on to front end logic. Before doing that, let me quickly explain angularjs $http service. $http service provided by angularjs is meant for making ajax communication with the server, it takes on configuration object with the details of the request and returns two methods, success and error. Syntax for making a typical $http service call is shown below.

$http({method: 'GET', url: '/someUrl'}).
  success(function(data, status, headers, config) {
    // this callback will be called asynchronously
    // when the response is available
  }).
  error(function(data, status, headers, config) {
    // called asynchronously if an error occurs
    // or server returns response with an error status.
  });

You can also use shortcut methods such as this,

$http.get('/someUrl').success(successCallback);
$http.post('/someUrl', data).success(successCallback);

Now create a web page and paste the below html in it. Note please download angularjs library and add correct path to the reference made in the below html. I have used bootstrap.css file for styling and it is optional.

<!DOCTYPE html>

<html data-ng-app="currencyApp" style="background-attachment: scroll;">
<head runat="server">
    <title>Currency Calculator | ProgrammingFree</title>
    <link href="style/bootstrap.min.css" rel="stylesheet" />
    <script src="scripts/angularjs.min.js"></script>    
    <script src="scripts/app.js"></script>
</head>
<body>
  <form id="form1" runat="server">
   <div class="container" data-ng-controller="currencyController">    
      <div class="row">                       
        <div > 
        <p>Currency Converter</p>                   
        <table>
           <tr>
             <td>
               <div>
                 <asp:TextBox ID="tbFromCurrency" runat="server" name="number" data-ng-model="fromcurrval" is-number></asp:TextBox>                                                                    
                 <asp:TextBox ID="tbToCurrency" runat="server" Text="{{outcurrvalue}}" ReadOnly="true" data-ng-model="outcurrvalue"></asp:TextBox>                             
               </div>
             </td>
             <td>
               <asp:DropDownList ID="ddFromCurrency" runat="server" data-ng-model="fromcurrency" CssClass="inputsize" data-ng-change="update()">
                <asp:ListItem Value="EUR">EURO</asp:ListItem>
                <asp:ListItem Value="USD">US DOLLAR</asp:ListItem>
                <asp:ListItem Value="JPY">JAPANESE YEN</asp:ListItem>
                <asp:ListItem Value="BGN">BULGARIAN LEV</asp:ListItem>
                <asp:ListItem Value="CZK">CZECH REPUBLIC KORUNA</asp:ListItem>
                <asp:ListItem Value="DKK">DANISH KRONE</asp:ListItem>
                <asp:ListItem Value="GBP">BRITISH POUND STERLING</asp:ListItem>
  <asp:ListItem Value="HUF">HUNGARIAN FORINT</asp:ListItem>
  <asp:ListItem Value="LTL">LITHUANIAN LITAS</asp:ListItem>
  <asp:ListItem Value="LVL">LATVIAN LATS</asp:ListItem>
  <asp:ListItem Value="PLN">POLISH ZLOTY</asp:ListItem>
  <asp:ListItem Value="RON">ROMANIAN LEU</asp:ListItem>
  <asp:ListItem Value="SEK">SWEDISH KRONA</asp:ListItem>
  <asp:ListItem Value="CHF">SWISS FRANC</asp:ListItem>
  <asp:ListItem Value="NOK">NORWEGIAN KRONE</asp:ListItem>
  <asp:ListItem Value="HRK">CROATIAN KNA</asp:ListItem>
  <asp:ListItem Value="RUB">RUSSIAN RUBLE</asp:ListItem>
  <asp:ListItem Value="TRY">TURKISH LURA</asp:ListItem>
  <asp:ListItem Value="AUD">AUSTRALIAN DOLLAR</asp:ListItem>
  <asp:ListItem Value="BRL">BRAZILIAN REAL</asp:ListItem>
  <asp:ListItem Value="CAD">CANADIAN DOLLAR</asp:ListItem>
  <asp:ListItem Value="CNY">CHINESE YUAN</asp:ListItem>
  <asp:ListItem Value="HKD">HONG KONG DOLLAR</asp:ListItem>
  <asp:ListItem Value="IDR">INDONESIAN RUPIAH</asp:ListItem>
  <asp:ListItem Value="ILS">ISREALI NEW SHEQEL</asp:ListItem>
  <asp:ListItem Value="INR">INDIAN RUPEE</asp:ListItem>
  <asp:ListItem Value="KRW">SOUTH KOREAN WON</asp:ListItem>
  <asp:ListItem Value="MXN">MEXICAN PESO</asp:ListItem>
  <asp:ListItem Value="MYR">MALAYSIAN RINGITT</asp:ListItem>
  <asp:ListItem Value="NZD">NEW ZEALAND DOLLAR</asp:ListItem>
  <asp:ListItem Value="PHP">PHILIPPINE PESO</asp:ListItem>
  <asp:ListItem Value="SGD">SINGAPORE DOLLAR</asp:ListItem>
  <asp:ListItem Value="THB">THAI BAHT</asp:ListItem>
  <asp:ListItem Value="ZAR">SOUTH AFRICAN RAND</asp:ListItem>
               </asp:DropDownList>
               <asp:DropDownList ID="ddToCurrency" runat="server" data-ng-model="tocurrency" CssClass="inputsize" data-ng-change="update()">
                <asp:ListItem Value="EUR">EURO</asp:ListItem>
                <asp:ListItem Value="USD">US DOLLAR</asp:ListItem>
                <asp:ListItem Value="JPY">JAPANESE YEN</asp:ListItem>
                <asp:ListItem Value="BGN">BULGARIAN LEV</asp:ListItem>
                <asp:ListItem Value="CZK">CZECH REPUBLIC KORUNA</asp:ListItem>
                <asp:ListItem Value="DKK">DANISH KRONE</asp:ListItem>
                <asp:ListItem Value="GBP">BRITISH POUND STERLING</asp:ListItem>
  <asp:ListItem Value="HUF">HUNGARIAN FORINT</asp:ListItem>
  <asp:ListItem Value="LTL">LITHUANIAN LITAS</asp:ListItem>
  <asp:ListItem Value="LVL">LATVIAN LATS</asp:ListItem>
  <asp:ListItem Value="PLN">POLISH ZLOTY</asp:ListItem>
  <asp:ListItem Value="RON">ROMANIAN LEU</asp:ListItem>
  <asp:ListItem Value="SEK">SWEDISH KRONA</asp:ListItem>
  <asp:ListItem Value="CHF">SWISS FRANC</asp:ListItem>
  <asp:ListItem Value="NOK">NORWEGIAN KRONE</asp:ListItem>
  <asp:ListItem Value="HRK">CROATIAN KNA</asp:ListItem>
  <asp:ListItem Value="RUB">RUSSIAN RUBLE</asp:ListItem>
  <asp:ListItem Value="TRY">TURKISH LURA</asp:ListItem>
  <asp:ListItem Value="AUD">AUSTRALIAN DOLLAR</asp:ListItem>
  <asp:ListItem Value="BRL">BRAZILIAN REAL</asp:ListItem>
  <asp:ListItem Value="CAD">CANADIAN DOLLAR</asp:ListItem>
  <asp:ListItem Value="CNY">CHINESE YUAN</asp:ListItem>
  <asp:ListItem Value="HKD">HONG KONG DOLLAR</asp:ListItem>
  <asp:ListItem Value="IDR">INDONESIAN RUPIAH</asp:ListItem>
  <asp:ListItem Value="ILS">ISREALI NEW SHEQEL</asp:ListItem>
  <asp:ListItem Value="INR">INDIAN RUPEE</asp:ListItem>
  <asp:ListItem Value="KRW">SOUTH KOREAN WON</asp:ListItem>
  <asp:ListItem Value="MXN">MEXICAN PESO</asp:ListItem>
  <asp:ListItem Value="MYR">MALAYSIAN RINGITT</asp:ListItem>
  <asp:ListItem Value="NZD">NEW ZEALAND DOLLAR</asp:ListItem>
  <asp:ListItem Value="PHP">PHILIPPINE PESO</asp:ListItem>
  <asp:ListItem Value="SGD">SINGAPORE DOLLAR</asp:ListItem>
  <asp:ListItem Value="THB">THAI BAHT</asp:ListItem>
  <asp:ListItem Value="ZAR">SOUTH AFRICAN RAND</asp:ListItem>
               </asp:DropDownList>
             </td>
             </tr>
          </table>   
          <div>                       
          <img src="../images/loading-blue.gif" width="50px" height="50px" alt="Loading.." data-ng-show="loading" />
        </div>                     
      </div>
    </div> 
   </div>   
 </form>
</body>
</html>

We have two text boxes and two dropdownlists. The textboxes are meant for displaying input and output currency values and the dropdownlists enables users to select the input and output currency codes. The first textbox is bound to 'fromcurrval' ng-model attribute and the second textbox is bound to 'outcurrval' ng-model attribute.

5. Create a javascript file called 'app.js' and use the below angularjs code in it. Note that we have already referenced this file in the head section of the web page.

This code is responsible for validating the input currency value textbox and firing ajax calls to Web API method for fetching converted currency value.

var currencyModule = angular.module('currencyApp', []);

currencyModule.controller('currencyController', function ($scope,currencyService) {
    $scope.fromcurrval = 1;
    $scope.fromcurrency = "EUR";
    $scope.tocurrency = "USD";
    $scope.loading = true;
    $scope.update = function () {
        if ($scope.fromcurrency == $scope.tocurrency) {
            $scope.outcurrvalue = $scope.fromcurrval;
        }
        else if ($scope.fromcurrval == "") {
            $scope.outcurrvalue = "";
        }
        else {
            $scope.loading = true;
            currencyService.calculate($scope.fromcurrency, $scope.fromcurrval, $scope.tocurrency).success(function (outcurrvalue) {
                $scope.outcurrvalue = outcurrvalue
                $scope.loading = false
            });
        }        
    }         
});
// Factory
currencyModule.factory('currencyService', function ($http) {
    return {
        calculate: function (fromCurrCode, fromCurrVal, toCurrCode) {
            return $http.get('api/currency/convertcurrency/' + fromCurrCode + '/' + fromCurrVal + '/' + toCurrCode);
        }
    }
});

currencyModule.directive('isNumber', function (currencyService) {
    return {
        require: 'ngModel',
        link: function (scope) {
            scope.$watch('fromcurrval', function (newValue, oldValue) {
                var arr = String(newValue).split("");
                if (arr.length === 0) {
                    scope.outcurrvalue = "";
                }
                else if (arr.length === 1 && (arr[0] === '.')) return;
                else if (isNaN(newValue)) {
                    scope.fromcurrval = oldValue;
                }
                else {
                    if (scope.fromcurrency === scope.tocurrency) {
                        scope.outcurrvalue = scope.fromcurrval;
                    }
                    else {
                        scope.loading = true;
                        currencyService.calculate(scope.fromcurrency, scope.fromcurrval, scope.tocurrency).success(function (outcurrvalue) {
                            scope.outcurrvalue = outcurrvalue
                            scope.loading = false
                        });                        
                    }
                }                    
            });
        }
    };
});


Step by step explanation of above code,

-- First, we create an angularjs module called 'currencyApp', which is mentioned in <html> tag's ng-app directive. This means angularjs is available to the whole html document.

-- A controller called 'currencyController' is created and registered in the 'currencyApp' module created in the first step. Inside this controller, all the ng-model attributes are instantiated with a default value. When the application loads for the first time, the value of the input textbox is assigned to '1', input currency code to "EUR" (euro) and output currency code to "USD" (us dollar). This controller is assigned to a div element in the html code which wraps up all the other currency converter elements.

-- Next, a service called 'currencyService' is registered using the factory function inside which $http call to the server side Web API method is made and output currency value is returned.

-- Before calling the service, the input currency value should be validated to allow users to enter only decimal numbers alone. Also whenever the value of the input textbox changes, for all valid entries, $http service must be called to fire ajax calls to server side method and the user interface must be updated with the results. To achieve this, we have created a custom directive called 'is-number' and it is added as an attribute to the first textbox in the html code.

<asp:TextBox ID="tbFromCurrency" runat="server" name="number" data-ng-model="fromcurrval" is-number></asp:TextBox>

-- The 'is-number' directive uses $scope.watch method. $scope.watch method looks for any changes in the textbox value and validates it for decimal or numeric value. If the value entered is not valid, it does not display it, instead displays the previously entered correct value. For example, if an user first enters 1 in the textbox and then types 'a', a will not be displayed instead '1' will be retained as it is in the textbox. If the value entered is valid then it calls the 'currencyService' method to fetch output currency value.

-- We also have to update the output currency values whenever the value in any of the dropdownlist changes, hence update method is created which again calls 'currencyService' service to fetch results. This time we have used ng-change directive to watch for changes in the dropdownlist selected item.

-- Sometimes, it might take some time for the calculations to happen at the back-end based on network bandwidth since we are querying an url for fetching currency exchange rates. It makes sense to notify the user that calculation is being done at the back end, otherwise for every change in the textbox if the value is not returned instantly, user might think the program had failed. For this, we have used a loading image which shows and hides itself based on the boolean value we set in its ng-show directive.

I know I could have made the dropdownlist values hard coded inside model in app.js file, but I thought it is not necessary since I am not adding or changing any of the values from front end. That is all. I have pretty much explained all that I have used in this small project of mine. Try this app and let me know, how good or bad this looks to you.


If you think this article and other information on this website is useful to you, please keep yourself subscribed via email or other social networking sites to be notified whenever more useful articles are posted here. Thanks for reading!

Subscribe to GET LATEST ARTICLES!


Related

AngularJS 6965109943967001260

Post a Comment

  1. Thanks for the tutorial. the only thing that needs to be added is to have HttpGet attribute on api method or it would say permission denied

    ReplyDelete
    Replies
    1. ut any potential punters at ease. In short, it is illegal to operate an online casino canada.

      Delete
  2. facing the error Inconsistent accessibility: Base class 'CurrencyConverter.ApiController' is less accessible than class 'Webforms.CurrencyController'. Please provide solution asap

    ReplyDelete
  3. Nice blog.I invite people to the below link -
    http://www.angularjstraining.in/

    ReplyDelete

emo-but-icon

SUBSCRIBE


item