How to implement Jint (a JavaScript interpreter) within a WinForms application in C#

How to implement Jint (a JavaScript interpreter) within a WinForms application in C#

Have you ever worked with Node.js ? Node.js is an open source command line tool built for the server side JavaScript code. In short words, it's just a thing that can be handled with a dynamic language (JavaScript) to do different things on a VM that is incredibly fast (V8). Node.js follows the principle of using native bindings in C++, now, imagine programming (with the same binding) in JavaScript with the power of C#! Using Jint you will be able to do the same thing you do with Node.js, however with C# instead of C++.

Jint is a Javascript interpreter for .NET that provides full ECMA 5.1 compliance and can run on any .NET platform because it doesn't generate any .NET bytecode nor use the DLR it runs relatively small scripts faster. The main features of Jint are:

Besides Jint is a maintained project, that means that an upcoming update for ECMAScript 6 will be someday possible.

In this article you will learn how to install and use the awesome Jint JS Interpreter in your WinForms application.

Installing Jint with NuGet

The first thing we need to do, is to install the Jint package using the NuGet manager. The installation of a package from Visual Studio is really simple, just look for the Solution Explorer area at the right top of VS, then right click on your project and from the dropdown menu selecte Manage NuGet Packages:

Now the NuGet package manager should start and you will be able to install packages on your project. Go to the Browse Tab of the emergent window and search for jint, in the list it should be the first item on the list (verify that the author is Sebastien Ros), select it and then click on Install:

Install Jint Javascript Interpreter in WinForms project

Once the installation of Jint finishes, you will be able to work with this awesome package in your project. For more information about the Jint project, please visit the official Github repository here.

Using Jint

Before work with the code, don't forget to include Jint in your C# class (wherever you want to use the JS Interpreter):

using Jint;

To understand how Jint works, there's no better way that showing it with examples. In some examples we will need a Form with 2 elements, a button identified as button1 and a multiline textbox identified as textBox1, that will contain the script that you want to run:

Expose native functions to JavaScript

To understand how easy is to manipulate native code with JavaScript, we are going to focus on the most classic and easy to understand example. As you know, in the browser, the alert function generates a Dialog that shows a message to the user. This function expects as unique argument a string that represents the message that needs to be shown to the user (alert("Message")).

As Jint isn't a Browser, but a JavaScript interpreter, such an alert function or a DOM doesn't exist in the JavaScript engine. Therefore, let's create a very simple alert function in C# that displays a Message box with some text inside:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

// Import Jint
using Jint;

namespace Sandbox
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {

        }

        /// <summary>
        /// Native alert function that shows a dialog with the specified message.
        /// </summary>
        /// <param name="Message"></param>
        private void Alert(string Message)
        {
            MessageBox.Show(Message, "Window Alert", MessageBoxButtons.OK);
        }

        private void button1_Click(object sender, EventArgs e)
        {
            string script = textBox1.Text;

            var JSEngine = new Engine()
                // Expose the alert function in JavaScript that triggers the native function (previously created) Alert
                .SetValue("alert", new Action<string>(Alert))
            ;

            try
            {
                JSEngine.Execute(script);
            }
            catch (Jint.Runtime.JavaScriptException Ex)
            {
                Console.WriteLine(Ex.Message);
            }
        }
    }
}

Note that we are not binding directly the MessageBox class of WinForms but a custom Alert function. The script to execute that allow you to test if the alert function was correctly exposed, would be:

alert("Hello C# with JavaScript");

And its execution in the example form would be:

However, you are not limited to pass a single argument. You can send many arguments as you want as long as they're declared in your native binding. You need to specify them as arguments in the Action class with its respective type (string, int etc.), for example:

private void NativeFunction(string Argument1, int Argument2)
{
    // "Value of argument 1"
    Console.WriteLine(Argument1);
    // 99999
    Console.WriteLine(Argument2);
}


string JavaScriptToExecute = @"
    theNameOfTheFunction('Value of argument 1', 99999)
";

var JSEngine = new Engine()
    // Expose the NativeFunction function in JavaScript and give it a name in JS
    .SetValue("theNameOfTheFunction", new Action<string, int>(NativeFunction))
;

// Run Script
JSEngine.Execute(JavaScriptToExecute);

You could now set a custom Title to the alert function:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

// Import Jint
using Jint;

namespace Sandbox
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {

        }

        private void Alert(string Message, string Title)
        {
            MessageBox.Show(Message, Title, MessageBoxButtons.OK);
        }

        private void button1_Click(object sender, EventArgs e)
        {
            string script = textBox1.Text;

            var JSEngine = new Engine()
                .SetValue("alert", new Action<string, string>(Alert))
            ;

            try
            {
                JSEngine.Execute(script);
            }
            catch (Jint.Runtime.JavaScriptException Ex)
            {
                Console.WriteLine(Ex.Message);
            }
        }
    }
}

The execution of the Script should generate something like:

The setValue function can be used to expose constants too, from variables in your C# code.

Note

If some argument in the native function isn't provided, you will get a simple string as replacement, namely "Error".

Allow access to .NET classes and assemblies

You can allow an engine to access any .NET class by configuring the engine instance like shown in the following example:

Engine JSEngine = new Engine(cfg => cfg.AllowClr());

try
{
    JSEngine.Execute("some script string here !!");
}
catch (Jint.Runtime.JavaScriptException Ex)
{
    Console.WriteLine(Ex.Message);
}

That means that you can write JavaScript that uses native functionalities stored in the System assembly. For example, if you execute the following JavaScript code on your engine:

// 0 stands for System.Environment.SpecialFolder.Desktop
var theFilePath = System.Environment.GetFolderPath(0) + "\\custom_file.txt";
var AFile = new System.IO.StreamWriter(theFilePath);

AFile.WriteLine("First Line of file in the desktop");
AFile.WriteLine("Second Line of file in the desktop");

AFile.Close();

You should have now a custom_file.txt in the desktop. As said at the beginning of the article, work with the power of C# writing in JavaScript.

Get returned value from function of JavaScript in C#

In case you need to retrieve some value from JavaScript to your C# code, you can rely on the GetValue method of the engine that expects as first argument the name of the function in JavaScript that returns the value that you need. This in turn return a Jint.Native.JsValue object that should be stored in a variable. To return the value execute the Invoke method of the previously stored variable (you can send values from C# to JavaScript, however is not required so you can simply cast the function with Invoke()):

try
{
    var FunctionAddJavascript = new Engine()
        .Execute(@"
            // This function return the result of the numbers.
            function add(a, b) {
                return a + b; 
            }
        ")
        .GetValue("add")
    ;

    var result = FunctionAddJavascript.Invoke(5, 6) ;

    // 11
    Console.WriteLine(result);
}
catch (Jint.Runtime.JavaScriptException Ex)
{
    Console.WriteLine(Ex.Message);
}

Force engine i18n and l10n

You can change the timezone of the Engine in C# by providing it as argument in the Engine:

TimeZoneInfo PST = TimeZoneInfo.FindSystemTimeZoneById("Pacific Standard Time");
var engine = new Engine(cfg => cfg.LocalTimeZone(PST));

engine.Execute("new Date().toString()"); // Mon Apr 03 2017 06:10:31 GMT-07:00

// Or other LocalTimeZone

TimeZoneInfo PST = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
var engine = new Engine(cfg => cfg.LocalTimeZone(PST));

engine.Execute("new Date().toString()"); // Mon Apr 03 2017 09:10:31 GMT-04:00

Or if you work with the localization:

// Import the Globalization type
using System.Globalization;


CultureInfo FR = CultureInfo.GetCultureInfo("fr-FR");
var engine = new Engine();

engine.Execute("new Number(1.23).toString()"); // 1.23
engine.Execute("new Number(1.23).toLocaleString()"); // 1,23

Happy coding !

Become a more social person