V8Ception | How to implement V8 into your .NET applications.
Tags: tutorial, v8, javascript, csharp
Published: 2018-01-07 21:45:15

---
title: V8Ception | How to implement V8 into your .NET applications. 
published: true
description: How to implement Google's V8 JavaScript Interpreter into your C# .NET application.
tags: tutorial, v8, javascript, csharp
---

_This article is based on my old V8 article published on 23 august 2015._

V8 is the JavaScript execution engine built for Google Chrome and open-sourced by Google in 2008. Written in C++, V8 compiles JavaScript source code to native machine code instead of interpreting it in real time.

In this post I will explain how to 
* install the required dependencies from NuGet
* create instances of V8 script engine inside your C# .NET application.
* evaluate JavaScript input
* expose a host type to the V8 interpreter context
* expose a host object to the V8 interpreter context
* expose entire assemblies to your script context
* create a host object and call methods from script

Provide examples (with gists) that show how to
* write a super simple REPL application
* create an easy way to load JavaScript files
* let V8 reference itself (both type and instance)

![Google V8 Engine](https://thepracticaldev.s3.amazonaws.com/i/xg2j2tvjv95ighvvh6dl.png)

> This post is written with n00bs in mind but assumes that you have some basic idea of what you're doing. I have simplified the concepts introduced in this article to the best of my ability and I have made all the code snippets available on [my GitHub gists](https://gist.github.com/jochemstoel/).

### Project
Start Microsoft Visual Studio and create a new C# application. (Console or Winforms does not matter) Right click the project references and click Manage nuGet packages. Enable/install Clearscript.V8 and then close the window.

![Add NuGet package](https://thepracticaldev.s3.amazonaws.com/i/r1012l2bmgyya5l4dq0a.png)

Make sure to select the right package (ClearScript.V8).

![Microsoft.ClearScript.V8](https://thepracticaldev.s3.amazonaws.com/i/ynihvcb1miuaa1vy4egr.png)

[ClearScript](https://clearscript.codeplex.com/) is a library that makes it easy to add scripting to your .NET applications. It currently supports JavaScript (via V8 and JScript) and VBScript. Basically, ClearScript assigns application objects such as Console, File and even Winforms components to Javascript objects. You can assign both _object instances_ and _object types_ to a script _context_.

Add reference to Microsoft.Clearscript.v8

```csharp
using Microsoft.ClearScript.V8 
```

You can create a new instance of V8 like this

```csharp
V8ScriptEngine v8 = new V8ScriptEngine();
```

Adding an _object instance_ allows you to control (an already created) object instance from your script. If you assign the system Console (System.Console) to _myConsole_, you will be able to access the console like this

```csharp
myConsole.ReadKey(); /* Read single key input from user */
myConsole.WriteLine(); /* Write something to the console */
```

So. If your Winforms application has a Button, lets say _Button1_ then you assign it to the V8 context like this

```csharp
v8.AddHostObject("btn1", Button1); // variable btn1 reflects Button1
```

and then from your script you can change the value of the button simply by doing

```csharp
btn1.Text = "exit now"; /* The button text is now changed to "exit now" */
```

An object type is (obviously) a reference to the type of application object (in other words, the class) rather than an instance of it. An object type is not instantiated yet.

```csharp
/* Inside your application */
v8.AddHostType("Button", typeof(Button));
```

and

```csharp
/* Inside your script you create multiple instances of Button */
var button1 = new Button();
var button2 = new Button();
var button3 = new Button();
```

*If the difference between host object and object types is not clear by now then you are not ready to be using v8 in your applications.*

The ClearScript package also allows you to expose an entire namespace all at once. The *HostTypeCollection* constructor takes 1 or more namespace (string) arguments. HostTypeCollection is located in _Microsoft.ClearScript_ so besides _Microsoft.ClearScript.V8_ you need to also reference _Microsoft.ClearScript_. This can be useful if you want to import/access a lot of different stuff that you don't want to add manually but can also be used when you are dynamically/programatically loading .DLL files.



```csharp 
v8.AddHostObject(identifier, new HostTypeCollection(namespaces[]));
```

```csharp
/* expose entire assemblies */
    engine.AddHostObject("lib", new HostTypeCollection("mscorlib", "System.Core"));
    engine.Execute("console.log(lib.System.DateTime.Now)");
// of course assuming console.log is already implemented
```


### Example 1 | A simple REPL using V8
Similar to Node, a super simple REPL reads input from process stdin and evaluates it. 

```csharp
using System;
using Microsoft.ClearScript.V8;

namespace v8repl
{
    class Program
    {
        static void Main(string[] args)
        {
            /* create instance of V8 */
            V8ScriptEngine v8 = new V8ScriptEngine();
            /* assign System.Console to Javascript variable myConsole */
            v8.AddHostType("myConsole", typeof(Console));

            /* */
            bool kill = false; 

            /* keep doing the following while kill = false */
            while(!kill)
            {
                /* get input string from process stdin */
                string input = Console.ReadLine();

                /* using a string literal for simplicity sake */
                if(input == "exit")
                {
                    Environment.Exit(0); /* exit code 0 means no error */
                }

                /* safely evaluate input in a try/catch block */
                try
                {
                    v8.Evaluate(input); /* run the code */
                } catch (Exception e)
                {
                    /* something went wrong, show us the exception */
                    Console.WriteLine(e.Message);
                }
            }
        }
    }
}
```
#### Gist
* [Super Simple REPL](https://gist.github.com/jochemstoel/99784b307d275be41316092b55bf112b)

### Example 2 | REPL 'wrapper' Class / load files
Simple class that wraps V8 and adds a method to load a file from the disk. This is not the ultimate way to design a REPL but is fine for this example.

```csharp 
using System;
using Microsoft.ClearScript;
using Microsoft.ClearScript.V8;

namespace v8repl
{
    class REPL
    {
        /* v8 engine outside main loop */
        private V8ScriptEngine v8 = new V8ScriptEngine();
        private bool running = false; /* */

        /* keep reading input from stdin until running = false */
        public void Start()
        {
            running = true;
            while (running)
            {
                string line = Console.ReadLine();

                if (line.Equals("kill"))
                {
                    running = false; /* causes this while loop to stop */
                }
                else {
                    Run(line);
                }
            }
        }

        /* method to read and evaluate JavaScript file */
        public void LoadFile(string inputFile)
        {
            v8.Evaluate(
                System.IO.File.ReadAllText(inputFile)
            );
        }
        
        /* safely evaluate code like we did before */
        public void Run(string line)
        {
            try
            {
                v8.Evaluate(line);
            }
            catch (System.Exception e)
            {
                Console.Error.WriteLine(e.Message);
            }
        }

        /* this allows us to get current instance */
        public V8ScriptEngine GetInstance()
        {
            return v8;
        }
    }
}
```

#### Gist
* [REPL Class](https://gist.github.com/jochemstoel/d3f878fa20bbe2bbc5ee9d32aca9d263)

### Example 3 | initialization script
Using the REPL class above, we load this file _init.js_ that contains a simple console object to sort of mimic the standarized JavaScript console object.

##### Application
```csharp 
using System;
using Microsoft.ClearScript.V8;
using Microsoft.ClearScript;

namespace v8repl
{
    class Program
    {
        static void Main(string[] args)
        {
            var repl = new REPL();
            var v8 = repl.GetInstance(); // shortcut 

            /* assign the whole .NET core library to mscorlib */
            v8.AddHostObject("mscorlib", new HostTypeCollection("mscorlib"));

            /* reference full namespace, for example:
             * mscorlib.System.Console.WriteLine()
             * mscorlib.System.IO.File.WriteAllText()
             */

            /* expose the V8ScriptEngine type to the V8 context */
            v8.AddHostType("V8ScriptEngine", typeof(V8ScriptEngine));

            /* we can now do:
             * var context1 = new V8ScriptEngine()
             */

            repl.LoadFile("init.js"); /* evaluate our file init.js */
            repl.Start();
        }
    }
}
```

##### The JavaScript file init.js being loaded
```js
/* imitate standarized console object */
var console = {
    log: string => {
        mscorlib.System.Console.WriteLine(string)
    },
    error: string => {
        mscorlib.System.Console.Error.WriteLine(string)
    }
}

/* 
Mental note:

In JavaScript we can pass multiple variables to console.log doing console.log('string', someVariable, 1234, { a: 1 })
This will not work here because Console.WriteLine expects a string.
You need some logic that will Array.join() the function arguments.
*/
```
#### Gist
* [Program.cs](https://gist.github.com/jochemstoel/ead8d90613c7d51aeaeddce5902e18ca)
* [Init.js](https://gist.github.com/jochemstoel/e0a1674725dcba96a2b7e932c49c23b0)

### V8ception | V8 inside V8
You can even assign the V8ScriptEngine itself to a Javascript object.

```csharp
v8.AddHostType("V8Engine", typeof(V8ScriptEngine));
```

Now you can create a new instance of V8 from your application input script (JavaScript). This allows you to create a new (sub)context. A new subcontext means a new scope / execution environment without any inherited variables.

```js
/* Javascript */
var v8 = new V8Engine();
v8.Execute('var x = 3; var y = 5; var z = x+y;');
```

Note that this V8 instance will also need its own console if you want to print its values to your process stdout.

### Self reference

You can create a reference to the V8 instance itself. This is a terrible idea no matter what the circumstances. :P

```csharp
V8ScriptEngine v8 = new V8ScriptEngine();
v8.AddHostObject("self", v8);
```

```js
self.Evaluate("var name = 'Jochem'")
console.log(name) // this will work
```

```js
var myConsole = { 
   log: function() {
      // 
   }
}

self.AddHostObject('parentConsole', myConsole) // sketchy but works
```

### One More Thing
It is important to understand that V8 is only the interpreter. A lot of standard and very common objects/apis that you know *do not exist* yet. This includes the _console_ object like we have discussed in this article but also the _Event_ class and its children. 

<hr>
To learn more about ClearScript, I highly recommend checking out the [official documentation](https://clearscript.codeplex.com/) on CodePlex, this is where I started too.

![V8Ception](https://thepracticaldev.s3.amazonaws.com/i/0mt7aenqb62ouhoc96lt.png)