Quantcast
Are you the publisher? Claim or contact us about this channel


Embed this content in your HTML

Search

Report adult content:

click to rate:

Account: (login)

More Channels


Showcase


Channel Catalog



Channel Description:

ClearScript is a library that makes it easy to add scripting to your .NET applications. It currently supports JavaScript (via V8 and JScript) and VBScript.

older | 1 | .... | 3 | 4 | (Page 5) | 6 | 7 | .... | 115 | newer

    0 0

    When trying to enumerator elements by using collection.GetEnumerator(), the script engine cannot find the enumerator's MoveNext() method even though it is public accessible.

    E.g. for List<Foo>, it will produce the following error:
    'System.Collections.Generic.IEnumerator<Foo>' does not contain a definition for 'MoveNext'
    for the following script:
    var enumerator = list.GetEnumerator();
    while (enumerator.MoveNext()) { ... }

    I tried to debug into the source code. It indeed find the public MoveNext() method, but later in binder.Bind() it generates a throw expression.

    0 0

    When trying to enumerator elements by using collection.GetEnumerator(), the script engine cannot find the enumerator's MoveNext() method even though it is public accessible.

    E.g. for List<Foo>, it will produce the following error:
    'System.Collections.Generic.IEnumerator<Foo>' does not contain a definition for 'MoveNext'
    for the following script:
    var enumerator = list.GetEnumerator();
    while (enumerator.MoveNext()) { ... }

    I tried to debug into the source code. It indeed find the public MoveNext() method, but later in binder.Bind() it generates a throw expression.
    Comments: Fixed in [Version 5.3.5](https://clearscript.codeplex.com/SourceControl/changeset/f961ab5a428cd1b6ffa92c9c4c7c35a9f3322a2c).

    0 0

    The V8 build fails apparently because some V8 source files cannot be converted to the Traditional Chinese ANSI code page.

    0 0

    The V8 build fails apparently because some V8 source files cannot be converted to the Traditional Chinese ANSI code page.
    Comments: Fixed in [Version 5.3.5](https://clearscript.codeplex.com/SourceControl/changeset/f961ab5a428cd1b6ffa92c9c4c7c35a9f3322a2c).

    0 0

    We've posted an update that fixes this issue.

    0 0

    Thanks for the detailed explanation.

    IMO, Javascript is a weak/dynamic typing language and that's one of its attracting points as a script language. Casting is natural in C# but strange in Javascript. Enforcing strong typing is not what I'd expect in Javascript. If I've chosen strong typing, I'd take C# as script language and compile dynamically.

    And I'm having another trouble which I think is also related to strong typing: I cannot call a CLR function with single precesion float parameters, because Javascript numbers are double. (Not 100% sure because I don't fully understand those dynamic binder code...)

    For the enum value from keyEventArgs.KeyCode issue, I think there are still some confusion. My debugger shows the object type is System.Windows.Forms.Keys rather than HostObject, while print(Keys.Space) in script gives HostObject rather than "Space". So two differences from what you explained: 1) Enum values are not wrapped in HostObject in all scenarios; 2) Enum member's toString() does not give the enum member name but just [object HostObject].


    I'm a bit frustrated for now. I don't know if these issues are related to my usage style. I'm calling Application.Run() for message loop in script, and scripts are called back though events for UI interaction. This is normal in C# but maybe not so well for script. I know some script engines have issues in such re-entrance usage scenario. I changed from Jint to ClearScript because Jint is really shitty at script error reporting, and Javascript.NET (which wrapps v8 too) does not support callbacks at all. Sorry for the rant...

    0 0

    IMO, Javascript is a weak/dynamic typing language and that's one of its attracting points as a script language. Casting is natural in C# but strange in Javascript.

    We agree 100%. However, ClearScript's job is to bridge JavaScript with a system that relies on strong typing for basic things like method binding. With .NET's heavy use of classes, overloading, generics, and extensions, you really couldn't get very far without strong type information. That's why ClearScript usually avoids conversion and gives script code direct access to .NET objects and types.

    Having said that, some conversion is necessary. It would be a huge pain, for example, if ClearScript didn't convert things like strings and integers into their script form. That's a no-brainer because strings and integers can be converted back and forth without data loss. What to do with enums, however, was less obvious. Enums exist for convenience and code readability, but their status as true .NET types involves them in overload resolution, among other things. That makes the one-way enum-to-integer conversion a serious problem. We were on the fence about enums but decided not to expose them as integers mostly for that reason.

    I cannot call a CLR function with single precesion float parameters, because Javascript numbers are double.

    Right you are, and thanks for finding yet another bug! It is currently not possible for script code to invoke a .NET method with a float parameter in ClearScript. We'll fix that ASAP. Note that the only safe implicit double-to-float conversion is one that is reversible without precision loss, so in most cases you'll have to use an explicit conversion such as Convert.ToSingle() to invoke such a method. Currently doing so doesn't help, and that's what we need to fix.

    My debugger shows the object type is System.Windows.Forms.Keys rather than HostObject, while print(Keys.Space) in script gives HostObject rather than "Space". So two differences from what you explained: 1) Enum values are not wrapped in HostObject in all scenarios;

    The HostObject wrapper is a native V8/JavaScript object that is not visible on the .NET side. These wrappers are required by V8's embedding model and reside in V8's internal heap. When script code passes any .NET object to a .NET method, the wrapper is stripped away; the method wouldn't work otherwise. There might be some confusion because ClearScript has an unrelated internal .NET class called HostObject.

    2) Enum member's toString() does not give the enum member name but just [object HostObject].

    That's correct. ClearScript does not intercept toString(), so you're seeing its default JavaScript behavior as applied to the HostObject wraper. If you want the enum member name, use the similarly named .NET method ToString().

    I'm a bit frustrated for now. I don't know if these issues are related to my usage style. I'm calling Application.Run() for message loop in script, and scripts are called back though events for UI interaction. This is normal in C# but maybe not so well for script. I know some script engines have issues in such re-entrance usage scenario.

    We haven't used ClearScript with Windows Forms, but we're always looking to improve ClearScript, so we'd love to know the specifics of any problems you encounter in that environment. In any case, we'd love for you to keep using ClearScript; you have a knack for finding bugs! :)

    0 0

    I see that we have a design philosophy difference here. You want to keep the .NETish part as much as possible. But when we use scripts, we want to minimize that as much possible. In ideal case, script writers don't need to know .NET at all. The .NET interop layer is only a convenience so that we don't need to go back to C++ to provide objects to script. It is just like a web developer who works with the web page DOM, where the script writer does not need to know C++/COM nor follow C++/COM typing rules. I agree that it is not easy/trouble-free to achieve 100% of that. But I will expect a script writer can feel at home most of the time. If he/she encounters .NET quirks frequently and has to use varies workarounds, it is clearly wrong design (either the language choice or the interop choice).

    Having tried LuaInterface and IronPython, I'd say they do the job very well. You really feel at home when working with them. However, some irrational part of me really want the web language instead. Pity that the road to .NET-Javascript integration is not so easy.

    Anyway, here's more findings:
    1) I finally find out why I was confused on enum values:
    print() is a host method with a string parameter.
    print("Key.Space = " + Key.Space); // result is "Key.Space = [object HostObject]"
    print(Key.Space); // result is "Space"
    You see the different results?

    2) ScriptEngineException.ErrorDetails is null when an error happened inside an event callback function.
    This only happens with JScriptEngine. V8ScriptEngine works fine.

    And 2 feature related questions:
    1) Does ClearScript support or intend to support .NET's dynamic/expendo object? I mean, in natural script syntax.
    2) It is possible to enable V8's harmony features?

    0 0

    Hi qrli!

    You want to keep the .NETish part as much as possible. But when we use scripts, we want to minimize that as much possible. In ideal case, script writers don't need to know .NET at all.

    Agreed, but it isn't ClearScript's goal to provide ideal script APIs. Its goal is to make existing .NET APIs fully scriptable, and to make ideal script APIs easy to implement.

    Consider a typical, non-trivial .NET API, complete with all its ".NETish parts". ClearScript aims to make such an API instantly scriptable, with full access to all its ".NET quirks". Replacing it with an ideal script API is something that (a) requires additional design effort by a human being, and (b) results in an API that is ideal only for the target script language. For these reasons it is outside the scope of the ClearScript project.

    It is just like a web developer who works with the web page DOM, where the script writer does not need to know C++/COM nor follow C++/COM typing rules.

    The DOM is a script API by design; a typical .NET API is not. Nothing stops you from implementing a DOM-like API layer using ClearScript. In fact, making that easy to do is one of ClearScript's goals.

    ClearScript is analogous to COM Interop. That framework allows .NET code to access COM APIs. Does it turn COM APIs into ideal .NET APIs? Of course not. It can't, and it shouldn't. Full access comes with quirks.

    All that having been said, it is absolutely a goal for ClearScript to make .NET scripting as natural as possible.

    print("Key.Space = " + Key.Space); // result is "Key.Space = [object HostObject]"
    print(Key.Space); // result is "Space"
    You see the different results?

    Yes, this makes sense. In the first line, the string concatenation is performed by the JavaScript engine, which calls toString() on each operand. To get the desired result, do this:
    print("Key.Space = " + Key.Space.ToString());
    It might be a good idea for ClearScript to implement toString() and eliminate the ambiguity. We'll take a look. Interestingly, JScript - which doesn't use HostObject wrappers - produces "Key.Space = undefined".

    ScriptEngineException.ErrorDetails is null when an error happened inside an event callback function.
    This only happens with JScriptEngine. V8ScriptEngine works fine.

    Unfortunately Windows Script engines (JScript/VBScript) don't provide error details unless you enable debugging. To do so, pass WindowsScriptEngineFlags.EnableDebugging into the engine constructor.

    Does ClearScript support or intend to support .NET's dynamic/expendo object? I mean, in natural script syntax.

    Yes, we're working on this. Please see here.

    It is possible to enable V8's harmony features?

    Not currently. This is on our long-term to-do list.

    Thanks again for all your input!

    0 0

    ...aaaaaand since the Item syntax is masked by indexers in C# I forgot it was there, so it didn't occur to me to try that in JavaScript. D'OH! Thank you very much for the fast reply. Actually, I admit that I am flabbergasted by the speediness of your reply--I posted my query at 4:53 PM on Friday, not expecting to get a reply until sometime today. Instead, you replied less than an hour later! Reading through some of the other discussions, though, I see that prompt replies are more the norm than the exception, which gives me a measure of confidence about the ClearScript community.

    Just as a quick bit of background, we currently are using the JScript.Vsa.VsaEngine to interpret JavaScript in our C# application. The JavaScript consists of end-user-defined formulas that extend our base system, so it's a core feature we need to protect, and VsaEngine's been marked obsolete for a couple versions of Visual Studio! I've been researching replacement candidates for a few weeks now, and so far ClearScript is shaping up to be the front-runner.

    Again, thanks!

    0 0

    Although I've been told it's highly unlikely I'm gonna ask this anyway: Is it possible to get ClearScript to work on Windows Phone 8 or is the fact (so I've been told) that Reflection is not supported on WP8 a deal breaker?

    Thanks in advance!

    0 0

    Thanks for the positive feedback! Please don't hesitate to let us know about any further issues you encounter.

    0 0

    ClearScript currently supports three script engines - JScript, VBScript, and V8. Unfortunately, none of them appear to support Windows Phone.

    0 0

    I'm trying to wrap my brain around the advantages of compiling a script with V8ScriptEngine.Compile versus dynamically evaluating script code using V8ScriptEngine.Script.

    Suppose I have script code like this:
    string code = @"
        function computeFoo(foo)
        {
            return (foo.inputA * foo.inputB);
        }
    ";
    In my C# code, I have a class Foo defined as follows:
    class Foo
    {
        public double inputA { get; set; }
        public double inputB { get; set; }
    }
    Now, suppose I need to "computeFoo" in a loop over and over again. It seems like I have two choices: dynamic evaluation with the V8ScriptEngine.Script member...
    V8ScriptEngine engine = new V8ScriptEngine();
    engine.Execute("DynamicJS", false, code);
    for (int i = 0; i < 50000; i++)
    {
        Foo foo = getFoo(i); // this function returns an instance of Foo
        var result = engine.Script.computeFoo(foo);
        // do something here with result
    }
    ...or I could compile the script code and re-execute the compiled code over and over. But if I do that, it doesn't seem that I can pass any parameters to the "computeFoo" method in my script code. Instead, it seems that I have to do something like this:
    string code = @"
        var foo = hostFoo;
        function computeFoo()
        {
            return (foo.inputA * foo.inputB);
        }
        computeFoo();
    ";
    V8ScriptEngine engine = new V8ScriptEngine();
    Foo foo = new Foo();
    engine.AddHostObject("hostFoo", foo);
    V8Script compiledCode = engine.Compile(code);
    for (int i = 0; i < 50000; i++)
    {
        foo = getFoo(i);
        var result = engine.Evaluate(compiledCode);
        // do something here with result
    }
    
    I've done some timing tests, and while the compiled approach is faster, it's not as dramatically faster as I had expected (it's more on the order of 20-30% faster). And if I make the "Foo" class a .NET class such as a Dictionary<>, the speed differential between the compiled and dynamic evaluation approach is narrowed even further.

    Considering that parameter passing from C# to the script code is less elegant with the compiled approach vs. using the Script member, I'm almost tempted to ditch compilation. The script code is something that is provided by our customers, and it's much more intuitive to tell them to create a "computeFoo" function that looks something like the first example versus the second one. Or am I missing something fundamental about how to pass parameters to compiled scripts?

    Thanks!

    0 0

    Hello sgammans!

    Your first technique above (the one that goes through ScriptEngine.Script) is the right way to invoke an existing script function multiple times. We'd actually recommend caching a reference to the function:
    V8ScriptEngine engine = new V8ScriptEngine();
    engine.Execute(code);
    dynamic computeFoo = engine.Script.computeFoo;
    for (int i = 0; i < 50000; i++)
    {
        var result = computeFoo(getFoo(i));
        // do something here with result
    }
    Your second code sample executes the same function statement over and over, needlessly redeclaring the function 50000 times. In addition to making it difficult to pass arguments, this could create 50000 copies of the function for the garbage collector to clean up. We say could because V8 might be smart enough to optimize the duplicate functions away.

    Frankly we're surprised that the second technique is faster. Our suspicion is that this is because (a) computeFoo() is trivial, and (b) V8 is very good at avoiding duplicate work.

    By the way, in your second code sample, the line foo = getFoo(i); only reassigns the .NET variable foo; it does not affect the script variable hostFoo. If we're reading your code correctly, this means that computeFoo() will operate on the same Foo instance every time. The code should probably be something like this instead:
    V8ScriptEngine engine = new V8ScriptEngine();
    // Foo foo = new Foo();// engine.AddHostObject("hostFoo", foo);
    V8Script compiledCode = engine.Compile(code);
    for (int i = 0; i < 50000; i++)
    {
        // foo = getFoo(i);
        engine.Script.hostFoo = getFoo(i);
        var result = engine.Evaluate(compiledCode);
        // do something here with result
    }
    But again, the other way is much better. It's simpler and cleaner, and it should be faster and more efficient in real-world situations.

    If you're wondering then what the point of compilation is, consider a scenario where your client provides arbitrary script code (not a single script function) that you must execute many times. In this situation, the following:
    void ExecuteManyTimes(V8ScriptEngine engine, string code, int repeatCount)
    {
        using (var compiledCode = engine.Compile(code))
        {
            for (var i = 0; i < repeatCount; i++)
            {
                engine.Evaluate(compiledCode);
            }
        }
    }
    is much faster than this:
    void ExecuteManyTimes(V8ScriptEngine engine, string code, int repeatCount)
    {
        for (var i = 0; i < repeatCount; i++)
        {
            engine.Evaluate(code);
        }
    }
    In addition, compiled scripts can be shared among multiple V8ScriptEngine instances that share a single V8Runtime.

    Cheers!

    0 0

    Thanks for the response. Too bad.

    0 0

    Wow, I'm glad I asked then, because my test results so far are that re-evaluation of compiled code is faster than dynamic evaluation using the Script object, and coming from a C/C++/C# background I just intuitively started from the position that re-executing "compiled" code would not mean that I was redeclaring that code on each pass. Thanks...

    0 0

    Actually, on second thought, roughly speaking they should be equally fast, as both amount to re-execution of compiled code. The second technique does redeclare the function; that is, it reassigns a global script property. But it probably doesn't duplicate the function, so the redeclaration is effectively a no-op.

    However, note that the first technique correctly passes an argument, whereas the second one doesn't, due to the bug described above. Exporting a .NET object to the script engine is not cost-free. Also, the first technique redundantly imports the function from the script engine, and that also is not cost-free. Together these factors might add up to the discrepancy you're seeing. Would it be possible to make the recommended changes (cache the script function in the first case, and fix the argument passing in the second) and rerun the timing tests?

    We'd like to reiterate that in both cases you're compiling code once and re-executing it many times. The two techniques have minor differences, but both should be much faster than recompiling the code many times.

    0 0

    ClearScript,

    Does your statement "If you don't expose any host objects, JavaScript code can only access built-ins such as Math" only apply when using the V8 Engine? It seems like if you use Microsoft.ClearScript.Windows.JScriptEngine for example, you could use ActiveXObject as an exploit.

    Consider this script method, which is designed to let a user write a script to transform data by executing it over each row as the data is copied someplace. The following code executed just fine with the JScript engine, and row.SomeField had the contents of some-secret-file.txt in it when done.
    function transform(row){ 
        // Intended use
        row.SomeField = row.Foo * row.Bar;  
        
        // Malicious use
        var fso = new ActiveXObject('Scripting.FileSystemObject');
        var f = fso.OpenTextFile('c:\\temp\\some-secret-file.txt');
        row.SomeField = f.ReadAll();
        f.Close();
        fso = null;
    }
    Am I missing something? Is there some way to run completely sandboxed?

    Justin

    0 0

    Hello jusbuc2k!

    Does your statement "If you don't expose any host objects, JavaScript code can only access built-ins such as Math" only apply when using the V8 Engine?

    No, it applies to all supported script engines. ClearScript does not add or remove anything from a script engine at instantiation time. Well, actually, no, that's not 100% true. ClearScript does create an object named EngineInternal for its own use, but it does not remove any built-ins.

    It seems like if you use Microsoft.ClearScript.Windows.JScriptEngine for example, you could use ActiveXObject as an exploit.

    Yes, that's correct. ActiveXObject is a JScript built-in. If that's a concern, you might want to do something like this before running unknown script code:
    engine.Execute("delete ActiveXObject");
    Good luck!

older | 1 | .... | 3 | 4 | (Page 5) | 6 | 7 | .... | 115 | newer