Noob question: how to use C# objects from JavaScript?

Jan 29, 2012 at 3:05 PM
Edited Jan 29, 2012 at 8:05 PM

Hello, I haven't found answer for my question. How to use C# objects from JavaScript?

I have class packet. It has constructor and some methods - addShort, addByte, addString, send etc. How to construct packet and invoke its functions from JavaScript? I tried many ways but it still doesn't work.

Thank you for answer and sorry if it is stupid.

 

Jan 30, 2012 at 7:15 AM

So you mean to use classes from C# into JS? To use objects from your C# I guess you already found the jintEngine.SetParameter right?

Just trying to help clarifying the question. If you are asking what I understood (using C# classes in JS, then instantiating JS objects from it within the JS), then I don't know the answer. I don't think it's possible out of the box.

Jan 30, 2012 at 11:23 AM
Edited Jan 30, 2012 at 11:32 AM

I could ask more definitely.

I have packet class. I want to construct an object of this class in javascript and use its methods and variables. Is it possible? (I hope yes.)

So it should be similar to this:

var p = new packet();

p.addByte(1);

p.send()

Jan 31, 2012 at 9:46 PM

 

Have you looked at the AllowClr property?  If you set that to true and perhaps fully qualify the namespace to your packet class it should work:

e.g.

Script.AllowClr = true;

Script.Run("var p = new Your.Namespace.packet(); p.addByte(1); p.send();");

 

You might be able to get around setting the CLR flag by registering your own custom constructor with the global object.

e.g.

((JsGlobal)Script.Global)["packet"] = new JsPacketConstructor(Script.Global as JsGlobal)

(Where JsPacketConstructor is a custom implementation of the JsConstructor class).  I haven't tried it myself but it would seem possible.

Jan 31, 2012 at 10:43 PM
Edited Jan 31, 2012 at 10:44 PM

I had to try it out and my implementation probably has issues, but...

    public class JsPacketConstructor : JsConstructor
    {
        public JsPacketConstructor(IGlobal global)
            : base(global) {
            Name = "packet";
            DefineOwnProperty(PROTOTYPE, global.ObjectClass.New(this), PropertyAttributes.ReadOnly | PropertyAttributes.DontEnum | PropertyAttributes.DontDelete);
        }

        public override JsObject Construct(JsInstance[] parameters, Type[] genericArgs, Jint.Expressions.IJintVisitor visitor)
        {
            return Global.WrapClr(new packet());
        }

        public override void InitPrototype(IGlobal global)
        {
            var Prototype = PrototypeProperty;
        }

}

Then, before running any script:

((JsGlobal)Script.Global)["packet"] = new JsPacketConstructor(Script.Global);

 

I was then able to run the following Javascript:

 

var p = new packet();

p.addByte(1);

p.send();

Feb 1, 2012 at 8:18 AM

Hi. Thank you very much, krisoye.

But I still have other question. My packet class constructor now accepts two arguments - short and bool. I tried this way but it throws an exception (InvalidCastException):

public override JsObject Construct(JsInstance[] parameters, Type[] genericArgs, Jint.Expressions.IJintVisitor visitor)
{
return Global.WrapClr(new packet((short)parameters[0].Value, (bool)parameters[1].Value));

How to make it working? Thanks again.

Feb 2, 2012 at 12:22 PM
Edited Feb 3, 2012 at 4:37 PM

Hello again. I tried this:

private packet Create(int id, bool old)
{
return new packet(Convert.ToInt16(id), old);
}

public override JsObject Construct(JsInstance[] parameters, Type[] genericArgs, Jint.Expressions.IJintVisitor visitor)
{
return Global.WrapClr(Create(parameters[0].ToInteger(), parameters[1].ToBoolean()));

But then I get an exception when I try to use var test = new packet(0x0405, false); test.send()):

Method "DynamicClass.jsWrapper(Jint.Native.IGlobal, Jint.Native.JsInstance, Jint.Native.JsInstance[])" can't access method "Jint.Marshaller.MarshalJsValue<uhehebot.bot+packet>(Jint.Native.JsInstance)".
Line: 17 Char: 20
 No source code available.

What should I do?

 P.S. Maybe you could even give me example of correct working class that supports arguments? Because I googled but found nothing useful.

 

Feb 3, 2012 at 9:44 PM

I am not an expert on Jint (yet).  I wish I was.  I am having a few issues of my own.

I'd look at other classes in Jint's native namespace.  JsRegExpConstructor is a constructor that supports multiple arguments:

It overrides Execute instead of Construct and calls a constructor method depending on the number of args.  Perhaps you can do something similar?

In JsPacketConstructor class:

       public override JsInstance Execute(IJintVisitor visitor, JsDictionaryObject that, JsInstance[] parameters) {
            if (parameters.Length == 0) {
                return visitor.Return(New());
            }
            return visitor.Return(New(Convert.ToInt16(parameters[0].ToString()), Convert.ToBoolean(parameters[1].ToString())));
        }

...

        public JsObject New() {  return New(0, false);    }

        public JsObject New(short p, bool f) {    Global.WrapClr(new packet(p, f));    }

Anyway... not sure this works but I would look at the other constructor types in Jint's Native namespace if not.

Feb 4, 2012 at 8:27 AM
Edited Feb 4, 2012 at 8:28 AM

Thank you. This works.

And how to add methods? It seems that I have to declare them and make wrappers (?). How to do that? (Maybe I am real noob if I even can't understand how to...)

For example I have send method, but it throws exception when trying to call it. I should redirect these calls to packet class. How?