v8.Net Wrapper Usage Sample

Sep 13, 2013 at 7:17 AM
Edited Sep 18, 2013 at 4:14 PM
Hello James Wilkins

Thanks for your excellent work on wrapping the V8 for the .Net world! We are trying to use your wrapper in a scenario where our application Object Model is exposed to the end user. The end users could then Script business use case sencario's using the exposed model. In order to achieve this we are trying to expose a C# object SamplePoint to the JS Engine and trying to identify the steps required to hit the Constructor call, the getters and setters call and a function call back into C# V8Managed object.

The Javascript code is ""var point = new SamplePoint(40,250); point.x=34; point.y=48; print(point.sumcoordinates()); print(point.x, point.y);";

The Print in the above JavaScript is an example for the Global objects that we can expose in the V8 world.

It would be great if you could use the above scenario or similar example of your own and demonstrate how we could achieve our goal. :-)

with best regards
Karthikeyan Karuppanan
Coordinator
Sep 13, 2013 at 4:43 PM
Edited Sep 13, 2013 at 4:53 PM
Hi Karthikeyan,

This is fairly easy actually. There are many ways you could do this. If you derive from V8NativeObject or V8ManagedObject you will have more control over the calls from JavaScript (and it can be faster execution wise). That said, it's also easier to just let V8.NET bind your classes the best it can automatically, but at the cost of a little (not much) performance (but it does speed up development time not having to worry about such things).
public class SamplePoint
{
    public int x;
    public int y;
}
// ... or ...
public class SamplePoint
{
    [ScriptMember("x")]
    public int X;
    [ScriptMember("y")]
    public int Y;
}
... then ...
jsServer = new V8Engine();
jsServer.WithContextScope = () =>
{
    jsServer.RegisterType(typeof(SamplePoint), null, true, ScriptMemberSecurity.DontDelete);
    jsServer.GlobalObject.SetProperty(typeof(SamplePoint));
    jsServer.GlobalObject.SetAccessor("print", YourPrintGetter, null, V8PropertyAttributes.Locked);
};
The second method for the class is like so:
public class SamplePoint : V8NativeObject
{
    public int x;
    public int y;

    public InternalHandle XGetter(InternalHandle _this, string propertyName)
    {
        return Engine.CreateValue(x);
    }

    public InternalHandle XSetter(InternalHandle _this, string propertyName, InternalHandle value)
    {
        return Engine.CreateValue(y);
    }

    public override void Initialize()
    {
        Handle.SetAccessor("x", XGetter, XSetter, V8PropertyAttributes.DontDelete);
    }
}

jsServer.WithContextScope = () =>
{
   var obj = jsServer.CreateObject<SamplePoint>();
    jsServer.GlobalObject.SetProperty("SamplePoint", obj, V8PropertyAttributes.DontDelete);
    jsServer.GlobalObject.SetAccessor("print", YourPrintGetter, null, V8PropertyAttributes.Locked);
};
... and the third method ...
public class SamplePoint : V8ManagedObject
{
    public Handle x = InternalHandle.Empty; // (or 'V8.Net.Handle.Empty')
    public Handle y = InternalHandle.Empty; // (or 'V8.Net.Handle.Empty')

    public override InternalHandle NamedPropertyGetter(ref string propertyName)
    {
        if (propertyName == "x") return x;
        else if (propertyName == "y") return y;
        else return InternalHandle.Empty;
    }
    public override InternalHandle NamedPropertySetter(ref string propertyName, InternalHandle value, V8PropertyAttributes attributes = V8PropertyAttributes.Undefined)
    {
        if (propertyName == "x") return x = value;
        else if (propertyName == "y") return y = value;
        return InternalHandle.Empty;
    }
    public override bool? NamedPropertyDeleter(ref string propertyName)
    {
        return false;
    }

    public override V8PropertyAttributes? NamedPropertyQuery(ref string propertyName)
    {
        if (propertyName == "x" || propertyName == "y") return V8PropertyAttributes.DontDelete;
        else return null;
    }

    public override InternalHandle NamedPropertyEnumerator()
    {
        return Engine.CreateValue(new string[] { "x", "y" });
    }
}
... now you need a template object for this, so ....
jsServer.WithContextScope = () =>
{
    var objTemplate = jsServer.CreateObjectTemplate();
    var obj = objTemplate.CreateObject<SamplePoint>();
    jsServer.GlobalObject.SetProperty("SamplePoint", obj, V8PropertyAttributes.DontDelete);
    jsServer.GlobalObject.SetAccessor("print", YourPrintGetter, null, V8PropertyAttributes.Locked);
};
(a TemplateObject is required for the interceptor callbacks [the methods overrided above])

Hope that helps. :)
Coordinator
Sep 13, 2013 at 5:05 PM
Edited Sep 13, 2013 at 5:05 PM
Extra note on "YourPrintGetter": There are multiple ways for this as well...
  1. 'YourPrintGetter' is simply a call back (like a lambda expression) that must return a V8Function (i.e. "var jsFunc = jsEngine.CreateFunctionTemplate().GetFunction(printMethodCallBack);").
  2. It's easier to let V8.NET bind it for you in a class: Just create a class called "GlobalUtilities" (or whatever) and call "jsEngine.SetPRoperty("GlobalUtilities", new GlobalUtilities())", then simply set "jsEngine.DynamicGlobalObject.print = jsEngine.DynamicGlobalObject.GlobalUtilities.print;".
TIP: When setting the "GlobalUtilities" property, you can use "V8PropertyAttributes.DontEnum" to hide it from object property enumerations. :)
Coordinator
Sep 13, 2013 at 5:20 PM
Edited Sep 14, 2013 at 4:22 AM
Just thought of something else (V8.NET is very flexible ;) ). You don't have to register the global object at all. Actually, if all you need to do is "merge" your own GlobalObject methods, you don't need to set a 'GlobalObject' property at all:
class GlobalObject { public print(...) { ... } }
jsServer.WithContextScope = () =>
{
    var typeBinder = jsServer.RegisterType(typeof(GlobalObject));
    _GlobalObjectBinder = typeBinder.CreateObject(new GlobalObject());
    jsEngine.DynamicGlobalObject.print = _GlobalObjectBinder.AsDynamic.print;
};
Sep 16, 2013 at 12:10 PM
Edited Sep 18, 2013 at 4:14 PM
Hello James Wilkins

Thanks for your inputs. I tried your suggestion and was successful in mapping the Javascript Print function back to a CallBack function in C#. However i am finding it little dificult to complete the SamplePoint exercise completely,

The following is a C++ code snippet of a SamplePoint example in C++ using the V8 Engine library,
                source =  String::New("var point = new SamplePoint(40,250); point.x=34; point.y=48; print(point.sumcoordinates()); print(point.x, point.y);");

    Handle<Object> global = context->Global();
    global->Set(v8::String::New("print"), v8::FunctionTemplate::New(Print)->GetFunction());
    point_template  = FunctionTemplate::New(constructPoint);
    Local<ObjectTemplate> point_instance_template = point_template->InstanceTemplate();
    point_instance_template->SetInternalFieldCount(1);

    point_instance_template->SetAccessor(String::New("x"), GetPointX, SetPointX);
    point_instance_template->SetAccessor(String::New("y"), GetPointY, SetPointY);
    point_template->PrototypeTemplate()->Set(v8::String::New("sumcoordinates"), v8::FunctionTemplate::New(SumCoOrdinates)->GetFunction());
    global->Set(String::New("SamplePoint"), point_template->GetFunction());
    script = Script::Compile(source);
    result = script->Run(); 
In the above example the constructor is also mapped to a callback function and where we create new SamplePoint instance, set it as a external object back into the V8 Engine and then on we are able to access the the properties, invoke a member function etc.
void constructPoint(const FunctionCallbackInfo<Value>& functionArgs){
    // Enter new scope
    HandleScope scope;


    if ( functionArgs.Length() == 0 ) {
        SamplePoint p( 0, 0 );
        functionArgs.This()->SetInternalField( 0, External::New( &p ) );
    }
    // new Point(##, ##)
    else if ( functionArgs.Length() == 2 ) {
    // Ensure params are numbers
        if ( !functionArgs[ 0 ]->IsNumber() || !functionArgs[ 1 ]->IsNumber() ) {
            functionArgs.GetReturnValue().Set( Undefined() );
        }
        else {
            int x = functionArgs[ 0 ]->NumberValue();
            int y = functionArgs[ 1 ]->NumberValue();
            SamplePoint *p = new SamplePoint( x, y );
            functionArgs.This()->SetInternalField( 0, External::New( p ) );
        }
    }
    // Invalid constructor
    else
        functionArgs.GetReturnValue().Set( Undefined( functionArgs.GetIsolate() ) );
}
In case of C++ the javascript example of creating a new instance of SamplePoint, changing the values of the co-ordinates, invoking a member function on SamplePoint that simply returns the sum of the co-ordinates and the global print function works well hitting the corresponding call backs functions respectively.
"var source =  String::New("var point = new SamplePoint(40,250); point.x=34; point.y=48; print(point.sumcoordinates()); print(point.x, point.y);");" 
However i am having trouble achieving the same using the V8.Net wrapper simply because i probably haven't understood interfaces and the concept very well. The C# code snippet that i am using is as follows,
            var v8Engine = new V8Engine();
            v8Engine.WithContextScope = () =>
                {
                    const string source = "var point = new SamplePoint(40,250); point.x=34; point.y=48; print(point.sumcoordinates()); print(point.x, point.y);";
                    
                    FunctionTemplate funcTemplate = v8Engine.CreateFunctionTemplate("SamplePoint");
                    ObjectTemplate objectTemplate = funcTemplate.InstanceTemplate;
                    V8Function samplePointConstructionFunction = funcTemplate.GetFunctionObject(p.SamplePointConstructorCallBack);
                    objectTemplate.SetProperty("SamplePoint", samplePointConstructionFunction.AsInternalHandle, V8PropertyAttributes.Locked);

                    objectTemplate.SetAccessor("x", p.XGetter, p.XSetter, V8PropertyAttributes.Locked);
                    objectTemplate.SetAccessor("y", p.YGetter, p.YSetter, V8PropertyAttributes.Locked);

                    V8Function sumCoOrdiantesFunction = funcTemplate.GetFunctionObject(p.SumCoOrdiantesCallBack);
                    objectTemplate.SetProperty("sumcoordinates", sumCoOrdiantesFunction.AsInternalHandle,V8PropertyAttributes.Locked);
                    v8Engine.GlobalObject.SetProperty(typeof (SamplePoint), "SamplePoint", false,
                                                      V8PropertyAttributes.DontDelete);

                    V8Function jsPrintFunc = v8Engine.CreateFunctionTemplate().GetFunctionObject(GlobalUtilities.Print);
                    v8Engine.GlobalObject.SetProperty("print", jsPrintFunc.AsInternalHandle, V8PropertyAttributes.Locked);

                    Handle result = v8Engine.Execute(source, "My V8.NET Console");
                    string resultValue = result.AsString;
                    Console.WriteLine(resultValue);
                    Console.WriteLine("Press any key to continue ...");
                    Console.ReadKey();
I have referred your examples and have tried my best to solve the exercise. I have been partially uccessful in validating the Print Callback. Also the execution of the JSstring indeed calls the constructor of SamplePoint successfully with the value of x=40 and y=250. However i am getting exception of "object not set" when try to access the co-ordinates back which is understable because i have not fed the instance back into the V8.Net engine in some form. It would be great if you could throw somelight on where i am going wrong and how to achieve my full goal.

with best regards
Karthikeyan Karuppanan
Coordinator
Sep 16, 2013 at 2:15 PM
HI,

Just wondering: Is there a reason you need to do it that way? As stated earlier, it would be easier to just register the type:
jsServer = new V8Engine();
jsServer.WithContextScope = () =>
{
    jsServer.RegisterType(typeof(SamplePoint), null, true, ScriptMemberSecurity.DontDelete);
    jsServer.GlobalObject.SetProperty(typeof(SamplePoint));
    jsServer.GlobalObject.SetAccessor("print", YourPrintGetter, null, V8PropertyAttributes.Locked);
};
Done! :)
Coordinator
Sep 16, 2013 at 2:28 PM
Edited Sep 16, 2013 at 2:32 PM
FYI: "SetProperty(typeof (SamplePoint), ..." in your code above will only register your CLR type "SamplePoint" as a global function (which is want you want ultimately). It will not register the code you created above it - there's no connection between to two processes (they are unrelated). All that code above it effectively does nothing. In fact, if you had a "SamplePoint" global script function, calling "SetProperty(typeof (SamplePoint), ..." would overwrite it.

Also, your call to "objectTemplate.SetProperty("SamplePoint", ..." doesn't make sense, because you are creating a function template of class "SamplePoint", then creating the property "SamplePoint" for all instances created from it. Any "var obj = new SamplePoint()" in script would yield "obj.SamplePoint" properties. ;)
Sep 18, 2013 at 8:39 AM
Edited Sep 18, 2013 at 4:14 PM
Hello James Wilkins

My Goal is to acheive,
const string source = "var point = new SamplePoint(40,250); point.x=30; point.y=50; print(point.sumcoordinates()); print(point.x, point.y);";
What i have been able to achieve so far is,
const string source = "SamplePoint.x=40; SamplePoint.y = 240; print(SamplePoint.sumcoordinates); print(SamplePoint.x,SamplePoint.y);";
The C# code that i have is as follows,
           TypeBinder binder = v8Engine.RegisterType(typeof(SamplePoint), null, true, ScriptMemberSecurity.Permanent);
           var obj = v8Engine.CreateObject<SamplePoint>();
           v8Engine.GlobalObject.SetProperty("SamplePoint", obj, V8PropertyAttributes.DontDelete);

           V8Function jsPrintFunc = v8Engine.CreateFunctionTemplate().GetFunctionObject(GlobalUtilities.Print);
           v8Engine.GlobalObject.SetProperty("print", jsPrintFunc.AsInternalHandle, V8PropertyAttributes.Locked);
My SamplePoint c# object is derived from the V8NativeObject. The SamplePoint class override the initialize() method,
 public override void Initialize()
        {
            Handle.SetAccessor("x", XGetter, XSetter, V8PropertyAttributes.DontDelete);
            Handle.SetAccessor("y", YGetter, YSetter, V8PropertyAttributes.DontDelete);
            Handle.SetAccessor("sumcoordinates", SumCoOrdinatesPropertyCallBack, null, V8PropertyAttributes.Locked);
            PostInitialize(Handle);
        }

 private void PostInitialize(ObjectHandle handle)
        {
            FunctionTemplate funcTemplate = handle.Engine.CreateFunctionTemplate("SamplePoint");
            V8Function samplePointConstructionFunction = funcTemplate.GetFunctionObject(SamplePointConstructorCallBack);
            handle.SetProperty("SamplePoint", samplePointConstructionFunction.AsInternalHandle, V8PropertyAttributes.Locked);
            //handle.Set(samplePointConstructionFunction.AsHandle());
            V8Function sumCoOrdiantesFunction = funcTemplate.GetFunctionObject(SumCoOrdinatesFunctionCallBack);
            handle.SetProperty("SumCoordinates", sumCoOrdiantesFunction.AsInternalHandle, V8PropertyAttributes.Locked);
            //handle.Set(sumCoOrdiantesFunction.AsHandle());
        }
The good news is the JavaSript source string exeuction results is callback to the Properties (x, y) Getters and Setters. Also if the sumcoordinates is mapped as property then the call back is hit. However if I try to expose the SumCordinates as a member function to the SamplePoint then the call back function is not hit. Similarly the call back function for the constructor is also not hit.

Because of these reasons i am unable to reach my set out target of exposing a complete Object to JavaScript Engine from the managed world. I am precisely unable to achieve the following two points from my set out goal,
var point = new SamplePoint(40,250);   /* creation of object instance in JS */
point.sumcoordinates());   /* invoking a member function of the exposed class */
Yes, i need to achieve this target with out compromise. My eventual goal is that to execute the sampe piece of JavaScript using the V8 Javascript engine in C++ and as well as in the Managed world with out any change in the source script. The Script could either generated by our application or could be hand written by our application users. We can't have a situation where we suggest our users to tweek the script across different environments[Managed world users and Native world users].

I am sure there should be a way out to achieve the above goal. Yours inputs to achieve this would be greatly helpful.

Additionally, we also tried the other two options as well,
jsServer = new V8Engine();
jsServer.WithContextScope = () =>
{
    jsServer.RegisterType(typeof(SamplePoint), null, true, ScriptMemberSecurity.DontDelete);
    jsServer.GlobalObject.SetProperty(typeof(SamplePoint));
    jsServer.GlobalObject.SetAccessor("print", YourPrintGetter, null, V8PropertyAttributes.Locked);
};
the above choice with the following Javascript source results in an error,
source = "var point = new SamplePoint(40,250); ";
Error: Failed to invoke constructor: => Message: Unable to cast object of type 'System.Reflection.RuntimeConstructorInfo' to type 'System.Reflection.MethodInfo'

with best regards
Karthikeyan Karuppanan
Coordinator
Sep 18, 2013 at 3:08 PM
jsServer = new V8Engine();
jsServer.WithContextScope = () =>
{
    jsServer.RegisterType(typeof(SamplePoint), null, true, ScriptMemberSecurity.DontDelete);
    jsServer.GlobalObject.SetProperty(typeof(SamplePoint));
    jsServer.GlobalObject.SetAccessor("print", YourPrintGetter, null, V8PropertyAttributes.Locked);
};
The above is exactly what you need; however, there's a bug I just found and I'm fixing it right now. I'll have the new binaries uploaded once fixed, and will let you know.

Note: "Handle." is not needed inside of the Initialize() method.
Coordinator
Sep 18, 2013 at 3:36 PM
Edited Sep 18, 2013 at 3:37 PM
Note: You cannot invoke constructors using what you have above. All you are doing is creating an object instance. What you want to do is simply create a global function, that is all:
FunctionTemplate funcTemplate = v8Engine.CreateFunctionTemplate("SamplePoint");
V8Function samplePointConstructionFunction = funcTemplate.GetFunctionObject(SamplePointConstructorCallBack);
v8Engine.GlobalObject.SetProperty("SamplePoint", samplePointConstructionFunction.AsInternalHandle, V8PropertyAttributes.Locked);
Then, simply look for the "isConstructCall" flag on your callback, THEN you construct and return your object; that said, why do all that when there's a shorter method I just mentioned. ;) (once I fix it).
Sep 18, 2013 at 4:06 PM
Edited Sep 18, 2013 at 4:07 PM
Hello James,

Precisely I had done the same and was glad that the constructor call back function was hit. I ran into a object reference not set exception. I am hopeful that you are looking at the same issue as well,
public static InternalHandle SamplePointConstructorCallBack(V8Engine engine, bool isConstructCall, InternalHandle _this, params InternalHandle[] args)
        {
            if (isConstructCall)
            {
                SamplePoint samplePoint = new SamplePoint(args[0].AsInt32, args[1].AsInt32);
                return samplePoint.AsInternalHandle;
            }
            return _this;
        }
I couldn't figure out how to return the handle or set the SamplePoint instance back into the v8Engine. The handle turns out to empty and tried several ways couldn't find a way to return the handle back.

When you are done with your fix. Kindly just let me know what code should go inside my constructor call back as well.

Thank you!
Karthikeyan Karuppanan
Coordinator
Sep 18, 2013 at 4:20 PM
Edited Sep 18, 2013 at 4:23 PM
You can't create and return objects that way. You have to either bind it, or create it from the engine.
  1. Binding method (if you go this route, don't inherit from 'V8NativeObject', but just implement 'IV8NativeObject' instead if you need to (not required):
    {
        if (isConstructCall)
        {
            var samplePointBinder = engine.GetTypeBinder(typeof(SamplePoint)); // (assumes you already registered the type by calling v8Engine.RegisterType())
            SamplePoint samplePoint = new SamplePoint(args[0].AsInt32, args[1].AsInt32);
            var obj = samplePointBinder.CreateObject(samplePoint); // (creates an object wrapper for your instance using the registered type information)
            return obj;
        }
        return engine.CreateError("You cannot call this function - use 'new' instead.", JSValueType.ExecutionError);
    }
    
  2. Inheriting from V8NativeObject:
     {
        if (isConstructCall)
        {
            var samplePoint = engine.CreateObject<SamplePoint>();  // (assumes "SamplePoint" inherits from V8NativeObject)
            samplePoint.x = args[0];
            samplePoint.y = args[1];
            return samplePoint;
        }
        return engine.CreateError("You cannot call this function - use 'new' instead.", JSValueType.ExecutionError);
    }
Coordinator
Sep 18, 2013 at 4:25 PM
BTW: My apologies on the lack of documentation. I'm the only developer, so time gets limited. I plan to update it properly with good examples as soon as possible, In the mean time, the program.cs file in the console demo has examples (see "SealedObject" example, and others below it).
Coordinator
Sep 18, 2013 at 5:26 PM
Ok, the new files are committed to the development branch. Download the development files from the source (there's a download link at the top), and find them in the "Release" folder. If using Windows remember to right-click the downloaded ZIP file, select properties, and unblock the ZIP, otherwise all your binaries will have the block flag.
Coordinator
Sep 18, 2013 at 10:15 PM
If you still have problems, please feel free to zip and send your source and I'll get it working for you. :)
Sep 19, 2013 at 2:19 AM
Thanks James. The dev release works great, I was able to expose my class and constructor to javascript with the simple code that you posted earlier, but with one minor change shown below.
jsServer = new V8Engine();
jsServer.WithContextScope = () =>
{
    // Changed from ScriptMemberSecurity.DontDelete.
    jsServer.RegisterType(typeof(SamplePoint), null, true, ScriptMemberSecurity.Locked);
    jsServer.GlobalObject.SetProperty(typeof(SamplePoint));
    jsServer.GlobalObject.SetAccessor("print", YourPrintGetter, null, V8PropertyAttributes.Locked);
};
Coordinator
Sep 19, 2013 at 3:47 AM
Edited Sep 19, 2013 at 3:51 AM
Actually, you may not want that. Locking of a type means you cannot delete or overwrite the members. You can create instances of the point, but will not be able to modify the properties - was this the intention?
jsServer.RegisterType(typeof(SamplePoint), null, true, ScriptMemberSecurity.Locked);
should be
jsServer.RegisterType(typeof(SamplePoint), null, true, ScriptMemberSecurity.DontDelete);
and
jsServer.GlobalObject.SetProperty(typeof(SamplePoint));
should be
jsServer.GlobalObject.SetProperty(typeof(SamplePoint), V8PropertyAttributes.Locked);
/* (this is now fixed in the development binaries) */
That said, I noticed I forgot to include the property attributes, so I just uploaded the new binaries for the code changed above.
Sep 19, 2013 at 5:58 AM
Edited Sep 19, 2013 at 6:40 AM
Hello James Wilkins,

It worked perfectly! I am glad to say that we have achieved our set out target of executing the following Javascript successfully with V8 and also with V8.Net.
const string source = "var point = new SamplePoint(40,250); point.x=30; point.y=50; print(point.SumCoordinates()); print(point.x, point.y);print(point.sumcoordinates);";
We have validated the Constructor call back, the property Getters and Setters call back and accessing the member functions through it's call back using V8.Net.

Yahoo!, Thanks for your excellent help and support! I am waiting for your next release binaries...

with best regards
Karthikeyan.
Coordinator
Sep 19, 2013 at 6:53 AM
Sounds great! 8)

What is your project if I may ask? Just curious. :)
Sep 19, 2013 at 10:10 AM
Edited Sep 19, 2013 at 1:43 PM
My project is about exposing our Application Object Model to the JavaScript world so that our end users could Script the applicaiton workflows. Unfortunately i am constrained by our organization policy and therefore can't reveal the project name.

Sorry :-(
Coordinator
Sep 19, 2013 at 2:25 PM
No worries, sounds great though. :)
Sep 19, 2013 at 4:59 PM
Edited Sep 19, 2013 at 5:02 PM
James, I don't see a ScriptMemberSecurity.DontDelete in the dev build that I downloaded last night. Here is what I have:
[Flags]
public enum ScriptMemberSecurity
{
    NoAcccess = -1,
    ReadWrite = 0,
    ReadOnly = 1,
    Hidden = 2,
    Permanent = 4,
    Locked = 5,
}
I just looked in the latest dev branch and I do see V8PropertyAttributes.DontDelete, but not ScriptMemberSecurity.DontDelete.
Coordinator
Sep 19, 2013 at 7:51 PM
Edited Sep 19, 2013 at 7:52 PM
Sorry, it's "Permanent". Actually, inside tip, the flags are all the same. LOL. ;) "V8PropertyAttributes" directly map to "ScriptMemberSecurity". I just didn't want to use V8 names with my own script member security attributes.

Internally, V8PropertyAttributes.DontDelete, == ScriptMemberSecurity.Permanent.
Oct 8, 2013 at 5:49 AM
James,

I just thought of sharing the good news that we have now validated our Proof of concept with V8.Net (so far so good). I have to admit that V8.Net is cool and we have been able to achieve our set out target smoothly with out any major hurdles so far :-).

Thanks for your support!

with best regards
Karthikeyan
Coordinator
Oct 8, 2013 at 6:31 AM
Awesome! :D Glad it all worked out. I"m working on a POC of sorts myself to help iron out V8.NET so it can be ready for the real world. I"m glad it's on target! :) I'm also grateful to users such as yourself who, with feedback, help advance the design in a more practical direction.

FYI: The current development-branch release builds are very stable (and contain a few more bug fixes) and I plan to create a new release post with them soon, so feel free to use those as the new release binaries if you need to until I get around to it. :)
Coordinator
Oct 8, 2013 at 6:37 AM
Also: If and when you do go public, please feel free to post a link here. I'd love to see it. :)
Coordinator
Oct 8, 2013 at 5:27 PM
Edited Oct 8, 2013 at 5:29 PM
Sorry, just a note on the newer release binaries: The "{engine}.WithContextScope" (and similar) usage is removed and no longer required, which is the only major breaking change, but also brings more pleasant development experience, and a slight speed boost (due to not having to call back into the managed side (and also prevents issues debugging code when native calls are on the stack). There's more details on the home page.
Oct 9, 2013 at 3:35 AM
Thank you James!, Sure shall leave a lote when we reach our mission.
Nov 7, 2013 at 12:21 PM
James, Is there a way we could instruct the V8.Net wrapper to remove an object as the scope of the object is over. We tried to see if there is a removeobject interface on the Engine object and there isn't any? Is there any other way through which we could instruct the V8.Net wrapper and the V8 engine to remove an object. We have a situation in our implementation where we want to force a delete of an object as it's scope is over. Kindly throw some light.
Coordinator
Nov 7, 2013 at 3:21 PM
You have to simply force the disposal of the handle (by calling dispose()) associated with the CLR object, then the worker thread should do the rest. :)