This project is read-only.

It’s important to understand a few things before using V8.NET.  The original premise to creating V8.NET was to create a wrapper that allows the user to control V8 from the managed side – at least to the degree that allows the user to easily integrate their own managed classes. The idea was not to wrap ALL V8 objects with managed ones, but only key ones, such as “ObjectTemplate”, “FunctionTemplate”, “Function”, “Object”, and the V8 handles.  While many methods on the V8 objects also have managed side counterparts (with the same names), many new methods are added to support the managed-side specific implementation.  All that said, the goal does include progressively exposing more and more of the native V8 side to the managed world over time.

The source code comments and this documentation will use the terms “Managed Object” to describe managed ‘IV8NativeObject’ objects, and “Native V8 Object” to describe the objects within the V8 engine.

Note: The source and documentation comments expect you to understand basic V8 concepts, so it is encouraged to read through the Google V8 Embedder’s Guide.  Also, if you see “{V8Engine}” it simply refers to an instance of the engine.


Quick Start

To begin using V8.NET, you must do the following:

  1. First, if using Windows, you may need to unblock the downloaded file (right click, and select properties).  If you don't, you will run into security issues trying to load and run the DLLs.
  2. Add a reference to the V8.Net.dll and V8.Net.SharedTypes.dll to your project, and make sure any other accompanying CLR DLLs are also in the same folder (currently there are only those two CLR DLLs). The x86 and x64 dlls should remain in their respective folders (they are not CLR [except the interface one]).  They will be dynamically loaded depending on the OS architecture.  Those files are (or related to) native compiled DLLS, not C# libraries.  The v8.Net.dll (compiled with "any CPU") will decide which one to load.
  3. In your source file, add “using V8.Net;”
  4. Done. Hot smile

To start using it, just create an instance of “V8Engine” and execute commands within a V8 scope. Here’s a simple “Console” application example.

  1. var v8Engine = newV8Engine();
  2. Handle result = v8Engine.Execute("/* Some JavaScript Code Here */", "My V8.NET Console");
  3. Console.WriteLine(result.AsString); // (or "(string)result")
  4. Console.WriteLine("Press any key to continue ...");
  5. Console.ReadKey();
Another quick start example can be found here:
Command line options for V8 are now supported. You can use '{V8Engine}.SetFlagsFromCommandLine(string flags)' to set one or more flags (space separated).
Definition of options:
Example: {V8Engine}.SetFlagsFromCommandLine("--use_strict")


DLL Files Required For Your Projects

All of these files MUST exist in your "bin\Debug|Release" folders.

  • v8-ia32.dll / v8-x64.dll
    The native Google V8 engine binaries.
  • V8_Net_Proxy_x86.dll / V8_Net_Proxy_x64.dll
    Native libraries use used to support P/Invokes (contains native proxy wrappers). These are pure native wrappers only (no mixed CLR code).
  • V8.Net.Proxy.Interface.x86.dll / V8.Net.Proxy.Interface.x64.dll
    Managed libraries that contain only interface methods for calling into the native proxy libraries.  V8.NET.dll will “decide” which one to load based on the platform bit depth it is running in.
  • V8.Net.SharedTypes.dll
    Managed library that contains only types needed between the various managed libraries.  This is needed if you access certain enum and struct types (such as property type enums).
  • V8.Net.dll
    This is the main V8.NET library, and is usually the only one you need to reference (though it will be a good idea to reference “V8.Net.SharedTypes.dll” as well).

How the libraries load

When V8.NET.dll loads, it is designed to expect “V8.Net.Proxy.Interface.dll”, which will never exist because it is deleted after the source compiles (via a post build step).  This forces a hook into the assembly resolver to locate the file, at which time the correct interface for the platform is loaded.

Tip: Set 'V8Engine.AlternateRootSubPath' to a sub-directory (defaults to 'V8.NET') to act as an alternate sub-folder to check for.  For instance, if using Visual Studio, you could create a "V8.NET" project folder, then dump the V8.NET assemblies there, and set all files under 'x86' and 'x64' folders to "Copy if newer".  This may help when deploying web solutions, as the IDE will know of the files.  The IDE will create 'bin\{Debug|Release}\V8.NET\{x86|x64}' folder paths.  In this case, using the default 'V8.NET' value, the V8.Net interface resolver will consider the nested folder to find the x86 and x64 directories.


Thread Safety and Scopes

While the Google V8 engine is not thread safe, it does have "isolates" to block calls while another is in progress (so many threads can use it, but only one thread can call in at a time). The "scopes" have also been abstracted, which makes everything a bit easier on the CLR side.

The Global Object

The global object is the root executing environment where global properties are stored.  This can be found on the managed side in two ways:

  •  {V8Engine}.GlobalObject – This is a reference of type IV8NativeObject, which provides methods for editing properties.  This is a simple wrapper around the native V8 context object. 
  • {V8Engine}.DynamicGlobalObject – This is the same reference as the first one, EXCEPT it is type-cast to “dynamic” for you!  You can simply store properties on it like “{V8Engine}.DynamicGlobalObject.x = 0”.
    Note: When accessing dynamic properties, they will usually be of type “InternalHandle”;  however, if the handle represents a managed object, the managed object will be returned instead.  If you know this in advance, you can simply type cast directly to the managed object type.  If not, then no worries, since the manage types implemented by V8.NET implicitly convert to “InternalHandle” types anyhow.


Handles wrap native V8 handles and are used to keep track of them.  V8 handles are never disposed (cached) until they are no longer in use, so it is important to make sure to dispose of handles when they are no longer needed.  Fortunately, you can use the “Handle” type and let the garbage collector take care of it for you, or call “Dispose()” yourself if you’d like to release it back more quickly.  There are two types of handles (thought they both function nearly the same):

  • InternalHandle 

    This is a value type that is used internally for wrapping marshalled handle proxies.  This is done so a proxy can quickly be wrapped by a stack created value instead of creating objects within the heap for the GC to have to deal with.  This has great speed advantages when V8 interceptors call back into the managed side via a large loops executed in script.  While this provides a huge performance boost, it comes at the cost of requiring its users to ensure “Dispose()” is called on it in order to reduce reference counts.  It is safe to use the “using(){}” statement, or wrap code in “try..finally” blocks.  For most cases, where speed is not an issue, it is recommended to use the “Handle” type.

    If using this type, you should never use the “=” operator to set a value.  Since C# doesn’t support copy constructors, you have to call “{InternalHandle}.Set()” instead.  If you use the “=” operator to copy this handle type, the system will not be aware of the  copy, and the native handle may become disposed before it gets used.  As well, when calling “Set()” to set a handle value, failing to call “Dispose()” on the old handle, if not needed, will result in memory leaks.

    Exception: Internal handles used in callback parameters are disposed AUTOMATICALLY upon return from the callback method.  Because of this, you can simply and safely initially use "=" to set either Handle or ObjectHandle (only) with this internal one.

    If you pass a "first" internal handle (for example, the first one returned by calling “{V8Engine}.CreateInteger()”) directly as an argument to another V8Engine method, it will be detected and dispose automatically, so upon return that handle will no longer be valid.  To prevent this, simply make a copy of the handle value using “Set()” or “Clone()” as needed.

  •  Handle / ObjectHandle

    This is an InternalHandle wrapper (“InternalHandle” is a value type), and is the type most developers should be using, unless speed is an issue.  If at any time you get an “InternalHandle“ type returned, you should either type-cast it to “Handle” or "ObjectHandle" to create a variable of type “Handle” instead (use "ObjectHandle" to represent script objects - it has object-related methods).  This allows developers to use the garbage collector to clean up handles automatically when no longer needed.

    Tip: You don’t have to keep creating these objects – instead, feel free to create them only once and call “Set()” instead (same rule of thumb for “InternalHandle” values).

    If using this type, you should never use the “=” operator to make copies of the handle, unless you know what you are doing.  Since C# doesn’t support copy constructors, you have to call “{Handle}.Set()” instead.   If you use the “=” operator to copy this handle type you will be copying only the reference to the handle object, and V8.NET will not be aware of it.  If many references point to the same handle instance, calling “Dispose()” on ANY one of them will dispose all of them.

Callbacks: Callback functions support using handles as parameters to prevent the system trying to convert them to CLR types (and are required if you wish to receive JS-specific types, such as JS function references).  In this special case, “InternalHandle” parameter values don’t need to be disposed.  Anytime a callback is invoked, the internal handle arguments passed to the method are automatically disposed when the method returns.  If you need to persist the value, make a copy of it. 


The following are two examples of how to use handles.

  1. Handle handle = v8Engine.CreateInteger(0);
  2.  var handle = (Handle)v8Engine.CreateInteger(0);

In both cases, the “InternalHandle” value returned is converted to a handle object so that the native handles can be disposed when they are no longer needed.   This is the recommended way to use handles.  That said, if speed is important, or there’s a need to create an enormous number of handles, you can use the stack created handles “InternalHandle” which will prevent creating objects for the garbage collector to deal with; however, they have to be manually disposed.

  1. var handle = v8Engine.CreateInteger(0);

In the case above, the handle is of type “InternalHandle”.  There are two main things to keep in mind: 1. The handle must be manually disposed, and 2. The handle is marked as a “first” handle, which means it will be destroyed automatically if passed directly into another V8Engine method that accepts those handle types. There are three main ways to dispose handles (of any type):

  1. var handle = v8Engine.CreateInteger(0);
  2. // (... do something with it ...)
  3. handle.Dispose();
  5. // ... OR ...
  7. using (var handle = v8Engine.CreateInteger(0))
  8. {
  9.     // (... do something with it ...)
  10. }
  12. // ... OR ...
  14. InternalHandle handle = InternalHandle.Empty; (optional to initialize)
  15. try
  16. {
  17.     handle = v8Engine.CreateInteger(0);
  18.     // (... do something with it ...)
  19. }
  20. finally { handle.Dispose(); }

If a copy of a handle is needed, then you must “set” it, and not “assign” it.

  1. handle.Set(anotherHandle);
  2. // ... OR ...
  3. var handle = anotherHandle.Clone(); // (note: this is only valid when initializing a variable)

In both these cases, a proper copy of the handle is made.  A counter on the native side keeps track of the number of handles, and is only released when all handles on the managed side are disposed.  As long as one handle copy exists, disposing one will not release the native handle.

Note: On line 1, when “Set()” is called, if “anotherHandle” is a value directly returned from a V8Engine method (such as “CreateInteger()”), making a copy of it will immediately dispose the returned handle value.

The following is an example of what NOT to do:

  1. var handle = v8Engine.CreateInteger(0);
  2. var handle2 = handle;

This example makes a copy of the handle (an “InternalHandle” type); however, because “Set()” was not used, disposing one will immediately invalidate the other as well, and the native handle will no longer be valid. As a rule of thumb, never use the “=” operator on ANY handle type, unless this behaviour is desired. The same issue will occur for “Handle” types as well for the same reason.

In regards to “InternalHandle” types, here’s another example of what NOT to do:

  1. handle.Set(anotherHandle.Clone());

`Clone()` creates a new copy of “anotherHandle” (incrementing an internal handle counter in the process) and passes the new copy to the “Set()” method.  At this point there are now two handles (the original and the copy).  The “Set()” method will first dispose of any existing handle reference in “handle”, and then make another copy of the copy passed in, effectively resulting in 2 copies (besides the original one).  The first copy of the original is never disposed, causing a memory leak.  It’s important to use either one or the other as needed, but not both.


Garbage Collection

Garbage collection is a challenge to deal with, as normally you try never touch the GC and work around it.  However, exposing managed objects to the native side means the managed side GC has no idea about native side V8 handles.  V8 does have a GC itself, but as well, it also has no idea about managed objects.  To make this work it is necessary to hook into the GC finalization process on both sides in order to coordinate the disposal of objects.  One rule of thumb is that the managed side owns ALL wrappers to native proxy data, so disposal must start on the manage side.  These are the usual steps:

  1. All active handles have an internal proxy field 'Disposed' set to 0.  The '{V8Engine}.Handles_Active' property will return a list of these handles (no need to dispose the handles returned from this list).
  2. An 'IV8Disposable' object that loses all references will call 'this.Finalizing();' to have itself added to a disposal queue (only if necessary, otherwise nothing happens [eg. 'Handle' objects always finalize immediately, and add an InternalHandle value to the disposal queue instead]). This is required, as calling into V8 from the finalizer thread to dispose native side V8 handles can cause deadlocks (Google V8 does not support multiple threads at the same time). Once in the disposal queue, an internal proxy field 'Disposed' is set to 1, which indicates that the managed side is now ready to dispose of the managed object. These handles can be inspected through '{V8Engine}.Handles_ManagedSideDisposeReady'.
  3. The worker thread reads from the disposal queue and checks the '{IV8Disposable}.CanDispose' property.  If true, it will call '{IV8Disposable}.Dispose()' on the object (in essence, acting like a finalizer).  If false, then it is assumed that the object is still needed by the native V8 side.  In such case it is assumed that the object was "abandoned" on the manage side (no more CLR references), and is then added to an "abandoned" queue.  If this is found to be a 'V8NativeObject', then the native V8 handle is marked as "weak", and the proxy ''Disposed' value is set to 2, which means that the native V8 engine will call back to dispose the object later on when no other V8 handle exists (note: just because there's no JavaScript reference doesn't mean V8 or a native side proxy object doesn't still have a reference for some reason).  These handles can be inspected through '{V8Engine}.Handles_NativeSideWeak'. Items that dispose successfully (usually InternalHandle values) can be inspected through '{V8Engine}.Handles_DisposedAndCached'.
  4. Abandoned objects are scanned continually to see if they can be disposed by checking the '{IV8Disposable}.CanDispose' property; however, this is done much more more slowly.  Most objects that make it here are 'ObjectTemplate' and 'FunctionTemplate' objects (though others are possible).  Those template objects must remain as long as any objects created from them still exists. As template created objects are disposed, a reference counter is updated on the template object. When this is 0, the template object will then dispose successfully.


More Help

There is much more documentation on all classes and methods throughout the assemblies (and source).  As well, please open the program.cs file of the Console project and review it for examples.  I encourage you to also run the console app and watch what it outputs to the screen, then take a look at the source behind the outputs.  It will show examples, and allow you to play around with the environment to get a "handle" on it. ;) If you still need more help, feel free to start a discussion.

 If you need help/examples on wrapping/binding CLR types, see this discussion:

In addition, there are example projects under a solution folder called "Test Projects":

  • V8.Net-Console: A demo console I use mainly for unit-testing, but contains may examples as well.
  • V8.NET-Console-ObjectExamples: Examples on how to integrate your own types.
  • ASPNetTest: Example ASP.NET project.
  • WCFServiceTest: Example WCF service project.

Last edited May 28, 2015 at 5:40 AM by jamesnw, version 69


jamesnw Mar 31, 2017 at 8:52 PM 
Sorry for the late late late reply, I never get emails on these comments. :/ I'll be moving to Github, since Codeplex is going into the archives this year, so that should help things. Yes, you can easily expose .net objects in the JS environment, and also have JS functions call .net delegates.

kshashikant15 May 17, 2016 at 10:54 AM 
Looks really great platform! I need confirmation on my case,
we have application written in node.js (ofcourse having base functions in javascript). What I am looking for is add those javascripts in my .net service and call those directly in my .net code. Does V8.NET helps me in this case?

jamesnw Oct 8, 2013 at 6:41 PM 
Hi @neurospeech, I didn't see your comment until now (never got any notices for some reason). There's a discussion on this now that should help clarify things a bit. I'll update the doc asap. :) (please feel free to open a discussion and ask me how to do a specific thing, and I'll type out some example code for you. :) )

neurospeech Sep 8, 2013 at 6:50 AM 
How about accessing & calling CLR objects & methods?

dvela1 Jul 1, 2013 at 2:21 AM 

jamesnw Jun 19, 2013 at 5:47 AM 
Ok, I've added some more handle examples with more detailed explanations.

jamesnw Jun 17, 2013 at 7:07 PM 
Sure thing. Was going to do it last night but ran out of time. ;)

dvela1 Jun 17, 2013 at 2:25 PM 
Can we get some example code. Maybe different ways on how to use the Handles?