In this article, we will build a simple calculator by using WPF and will use IronJS for writing the various calculator operations.We are using an external JavaScript as our dynamic scripting language.This Java Script file will have all the functions that the Calculator will use.
Introduction
In the previous article , we have seen how to invoke a dynamic scripting language (e.g. Java Script) using Iron Python.But in that article, we were building the functions programatically.In this article, we will extend our same example to demonstrate the power of IronJS of invoking an external Java Script file.The development environment is Microsoft Visual Studio Community 2015.
Environment Setup
Let's create a solution file and add two project, one WPF(CalciPL) and another Class Library(CalciBL) projects.Choose the Class Library(CalciBL) project, click on Managed Nuget Packages.

In the Search box Type "IronJS" and click "Search"

Click on the Install button to install "IronJS". We are using version 0.2.0.1

Once installed, we will get the below screen

Now we are good to go for writing our Business Logic(s)
Using the code
Let us first create a javascript file say CaliOperations.js which will have the below functions
/*
Function Name: Add
Purpose: For Addition of two numbers
*/
function Add(a,b)
{
return a+b;
}
/*
Function Name: Sub
Purpose: For Subtraction of two numbers
*/
function Sub(a,b)
{
return a-b;
}
/*
Function Name: Mul
Purpose: For Multiplication of two numbers
*/
function Mul(a,b)
{
return a*b;
}
/*
Function Name: Div
Purpose: For Division of two numbers
*/
function Div(a,b)
{
return a/b;
}
Let us write the below code in the CaliOperation.cs file
using IronJS;
using System;
namespace CalciBL
{
public class CaliOperation
{
public int CaliOperations(int a, int b, string @operator)
{
const string FILEPATH = @"D:\CaliOperations.js";
string operation = string.Empty;
// Instantiate the IronJS Engine
var context = new IronJS.Hosting.CSharp.Context();
//Reads Javascript Source Code
context.ExecuteFile(FILEPATH);
//Set the operation mode as per the operator choosen
switch (@operator)
{
case "+":
operation = "Add";
break;
case "-":
operation = "Sub";
break;
case "*":
operation = "Mul";
break;
case "/":
operation = "Div";
break;
}
//fo holds the needed JS function
FunctionObject fo = context.Globals.GetT<FunctionObject>(operation);
//invoke the JS dynamic method
BoxedValue bv = fo.Call(context.Globals, Convert.ToDouble(a), Convert.ToDouble(b));
//unboxing the unknown values to a known value
double result = bv.Unbox<double>();
//Execute method runs the dynamic code
return Convert.ToInt32(result);
}
}
}
Code Explanation
The very first thing we need to perform is to instantiate the IronJS Engine which can be achieve by the below code
new IronJS.Hosting.CSharp.Context()
Next we are invoking the ExecuteFile method of the on the context object. The ExecuteFile caches the AST tree for the parsed "CaliOperations.js" file and uses the cache.
Next, based on the operator choosen at runtime, we are setting the operation that is defined in the "CaliOperations.js" JavaScript file.
IronJS automatically sends the function being called into the FunctionObject parameter.The FunctionObject class is derived from CommonObject.
//fo holds the needed JS function
FunctionObject fo = context.Globals.GetT<FunctionObject>(operation);
The FunctionObject has a call method that invokes the dynamic methods
//invoke the JS dynamic method
BoxedValue bv = fo.Call(context.Globals, Convert.ToDouble(a), Convert.ToDouble(b));
As can be figure out that, the Call method returns a BoxedValue type. This is a NaN-tagged struct that is used for representing values that don't have a known type at runtime.IronJS passes integers as doubles, so we need to cast them.
Convert.ToDouble(a)
Finally, we are unboxing the unknown values to a known value by invoking the Unbox function
To test our function, we can write a simple Unit Test project as under
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace CalciBL.Tests
{
[TestClass()]
public class CaliOperationTest
{
[TestMethod()]
public void CaliOperationAdditionSuccessTest()
{
CaliOperation objCalciOp = new CaliOperation();
var expected = 60;
var actual = objCalciOp.CaliOperations(20, 40, "+");
Assert.AreEqual(expected, actual);
}
[TestMethod()]
public void CaliOperationAdditionFaliureTest()
{
CaliOperation objCalciOp = new CaliOperation();
var expected = 35;
var actual = objCalciOp.CaliOperations(-20, 40, "+");
Assert.AreNotEqual(expected, actual);
}
[TestMethod()]
public void CaliOperationSubtractionSuccessTest()
{
CaliOperation objCalciOp = new CaliOperation();
var expected = -20;
var actual = objCalciOp.CaliOperations(20, 40, "-");
Assert.AreEqual(expected, actual);
}
[TestMethod()]
public void CaliOperationSubtractionFaliureTest()
{
CaliOperation objCalciOp = new CaliOperation();
var expected = 35;
var actual = objCalciOp.CaliOperations(-20, 40, "-");
Assert.AreNotEqual(expected, actual);
}
[TestMethod()]
public void CaliOperationMultiplicationSuccessTest()
{
CaliOperation objCalciOp = new CaliOperation();
var expected = -800;
var actual = objCalciOp.CaliOperations(-20, 40, "*");
Assert.AreEqual(expected, actual);
}
[TestMethod()]
public void CaliOperationMultiplicationFaliureTest()
{
CaliOperation objCalciOp = new CaliOperation();
var expected = 35;
var actual = objCalciOp.CaliOperations(20, 40, "*");
Assert.AreNotEqual(expected, actual);
}
[TestMethod()]
public void CaliOperationDivisionSuccessTest()
{
CaliOperation objCalciOp = new CaliOperation();
var expected = 10;
var actual = objCalciOp.CaliOperations(400, 40, "/");
Assert.AreEqual(expected, actual);
}
[TestMethod()]
public void CaliOperationDivisionFaliureTest()
{
CaliOperation objCalciOp = new CaliOperation();
var expected = 35;
var actual = objCalciOp.CaliOperations(56, 40, "/");
Assert.AreNotEqual(expected, actual);
}
}
}
Now let us make our UI design in WPF which will be as under

And the code is as under
using CalciBL;
using System;
using System.Windows;
namespace CalciPL
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
CaliOperation objCalciOp;
public MainWindow()
{
InitializeComponent();
objCalciOp = new CaliOperation();
}
private void btnAdd_Click(object sender, RoutedEventArgs e)
{
var nums = InputValues();
txtResult.Text = Convert.ToString(objCalciOp.CaliOperations(nums.Item1, nums.Item2, "+"));
}
private void btnSub_Click(object sender, RoutedEventArgs e)
{
var nums = InputValues();
txtResult.Text = Convert.ToString(objCalciOp.CaliOperations(nums.Item1, nums.Item2, "-"));
}
private void btnMul_Click(object sender, RoutedEventArgs e)
{
var nums = InputValues();
txtResult.Text = Convert.ToString(objCalciOp.CaliOperations(nums.Item1, nums.Item2, "*"));
}
private void btnDiv_Click(object sender, RoutedEventArgs e)
{
var nums = InputValues();
txtResult.Text = Convert.ToString(objCalciOp.CaliOperations(nums.Item1, nums.Item2, "/"));
}
private Tuple<int, int> InputValues()
{
var num1 = Convert.ToInt32(txtNum1.Text);
var num2 = Convert.ToInt32(txtNum2.Text);
return Tuple.Create(num1, num2);
}
}
}
Now run the application and we can feel the taste of our simple calculator.

Conclusion
So in this article we have seen how to invoke an external dynamic language like Java Script file functions using IronPython.Hope this will be helpful.Attached is the zipped file.Thanks for reading.