Quantcast
Channel: ClearScript
Viewing all 2297 articles
Browse latest View live

Updated Wiki: Home

$
0
0

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.

Features

  • Simple usage; create a script engine, add your objects and/or types, run scripts
  • Support for several script engines: Google's V8, Microsoft's JScript and VBScript
  • Exposed resources require no modification, decoration, or special coding of any kind
  • Scripts get simple access to most of the features of exposed objects and types:
    • Methods, properties, fields, events
    • (Objects) Indexers, extension methods, conversion operators, explicitly implemented interfaces
    • (Types) Constructors, nested types
  • Full support for generic types and methods, including C#-like type inference and explicit type arguments
  • Scripts can invoke methods with output parameters, optional parameters, and parameter arrays
  • Script delegates enable callbacks into script code
  • Support for exposing all the types defined in one or more assemblies in one step
  • Optional support for importing types and assemblies from script code
  • The host can invoke script functions and access script objects directly
  • Full support for script debugging

Examples

using System;
using Microsoft.ClearScript;
using Microsoft.ClearScript.V8;

// create a script engineusing (var engine = new V8ScriptEngine())
{
    // expose a host type
    engine.AddHostType("Console", typeof(Console));
    engine.Execute("Console.WriteLine('{0} is an interesting number.', Math.PI)");

    // expose a host object
    engine.AddHostObject("random", new Random());
    engine.Execute("Console.WriteLine(random.NextDouble())");

    // expose entire assemblies
    engine.AddHostObject("lib", new HostTypeCollection("mscorlib", "System.Core"));
    engine.Execute("Console.WriteLine(lib.System.DateTime.Now)");

    // create a host object from script
    engine.Execute(@"
        birthday = new lib.System.DateTime(2007, 5, 22);
        Console.WriteLine(birthday.ToLongDateString());
    ");

    // use a generic class from script
    engine.Execute(@"
        Dictionary = lib.System.Collections.Generic.Dictionary;
        dict = new Dictionary(lib.System.String, lib.System.Int32);
        dict.Add('foo', 123);
    ");

    // call a host method with an output parameter
    engine.AddHostObject("host", new HostFunctions());
    engine.Execute(@"
        intVar = host.newVar(lib.System.Int32);
        found = dict.TryGetValue('foo', intVar.out);
        Console.WriteLine('{0} {1}', found, intVar);
    ");

    // create and populate a host array
    engine.Execute(@"
        numbers = host.newArr(lib.System.Int32, 20);
        for (var i = 0; i < numbers.Length; i++) { numbers[i] = i; }
        Console.WriteLine(lib.System.String.Join(', ', numbers));
    ");

    // create a script delegate
    engine.Execute(@"
        Filter = lib.System.Func(lib.System.Int32, lib.System.Boolean);
        oddFilter = new Filter(function(value) {
            return (value & 1) ? true : false;
        });
    ");

    // use LINQ from script
    engine.Execute(@"
        oddNumbers = numbers.Where(oddFilter);
        Console.WriteLine(lib.System.String.Join(', ', oddNumbers));
    ");

    // use a dynamic host object
    engine.Execute(@"
        expando = new lib.System.Dynamic.ExpandoObject();
        expando.foo = 123;
        expando.bar = 'qux';
        delete expando.foo;
    ");

    // call a script function
    engine.Execute("function print(x) { Console.WriteLine(x); }");
    engine.Script.print(DateTime.Now.DayOfWeek);

    // examine a script object
    engine.Execute("person = { name: 'Fred', age: 5 }");
    Console.WriteLine(engine.Script.person.name);
}

New Post: Is it possible to expose a JavaScript style function with a callback in clearscript

$
0
0
I would like to expose an open method on my c# object that I am exposing to ClearScript. The open method signature would look like this
    public void open(string address, Action<dynamic> callback)
    {
        if (callback != null)
        {
            callback("success");
        }
    }
And calling it from script like this
page.open('http://www.cnn.com', function(status) { 
    // do somthing here with status
});

New Post: Is it possible to expose a JavaScript style function with a callback in clearscript

$
0
0
Hello!

On the .NET side you can access JavaScript objects, including functions, using the dynamic keyword. For example, you can define your class like this:
publicclass Page {
    publicvoid open(string address, dynamic callback) {
        if (callback != null) {
            callback("success");
        }
    }
}
and then use it like this:
engine.AddHostObject("page", new Page());
engine.AddHostType("Console", typeof(Console));
engine.Execute(@"
    page.open('http://www.cnn.com', function(status) {
        Console.WriteLine(status);
    });
");
You can also set up a .NET delegate that calls a script function. This makes it possible to plug script code into an existing API that doesn't use dynamic. For example, if your class is already defined like this:
publicclass Page {
    publicvoid open(string address, Action<string> callback) {
        if (callback != null) {
            callback("success");
        }
    }
}
you can use it from script code like this:
engine.AddHostObject("page", new Page());
engine.AddHostType("Console", typeof(Console));
engine.AddHostType("OpenCallback", typeof(Action<string>));
engine.Execute(@"
    page.open('http://www.cnn.com', new OpenCallback(function(status) {
        Console.WriteLine(status);
    }));
");
Thanks for your question, and good luck!

New Post: Is it possible to expose a JavaScript style function with a callback in clearscript

$
0
0
Perfect. That did the trick. Thanks

New Post: Possible to get string content of passed in function?

$
0
0
We are building a bridge between CEF and C#. The C# console app is driven by javascript code. Used to basically drive a headless browser. So far clerscript has been a great tool. I was wondering if it is possible to pull the string content of a passed in JavaScript function...so I can then inject that back into the headless browser.

For example in my C# class I would have this code
    public void execute(dynamic function)
    {
        //Parse function into string and inject back into CEF Browser frame
    }
And the script driving all this looks like this
...
...
    page.open(address, function(status) { 

      if(status != "success")
      {
        console.log("Load failed");
        chromejs.exit(2);
      }

      // TRYING TO MAKE THIS PART WORK
      page.execute(function() {
        return document.title;
      });

      page.render("test.png");
      chromejs.exit();  
    });

Commented Issue: Problems using WindowsScriptEngineFlags.EnableDebugging [36]

$
0
0
I have code that executes fine on my machine with Visual Studio installed but have passed the code (compiled) including ClearScript.DLL to someone else who is getting an error when the script runs. I have tracked it down that if I remove the EnableDebugging I do not see the crash. But I need this option to get Column and Line numbers for errors in user scripts.

Is this crash caused by a lack of VS on the other machine? If so how do I work around this? I ONLY have the debug option enabled for line and column numbers (running v5.3.9 - not yet tried v5.3.11 as I cannot reproduce so need my colleague to run with latest DLL!)

Stack Trace Info below
at System.Activator.CreateInstance(Type type, Boolean nonPublic)
at Microsoft.ClearScript.Windows.ProcessDebugManagerWrapper32..ctor()
at Microsoft.ClearScript.Windows.ProcessDebugManagerWrapper.Create()
at Microsoft.ClearScript.Windows.WindowsScriptEngine.<>c__DisplayClass2.<.ctor>b__0()
at Microsoft.ClearScript.ScriptEngine.ScriptInvoke[T](Func`1 func)
at Microsoft.ClearScript.Windows.WindowsScriptEngine..ctor(String progID, String name, WindowsScriptEngineFlags flags)
at Microsoft.ClearScript.Windows.VBScriptEngine..ctor(String progID, String name, WindowsScriptEngineFlags flags)
at Microsoft.ClearScript.Windows.VBScriptEngine..ctor(String name, WindowsScriptEngineFlags flags)
MY ENTRY POINT -> at Configurator.ScriptProcessor.EnableAPI(API api)


Comments: I ran into this today, too. > We do feel that ClearScript should transition gracefully into non-debug mode when a debugger is not present Agreed. But figuring out a way to get error information (line number, etc) without a debugger present would be better. Even some information (not necessarily stack info) would be nice.

New Post: Possible to get string content of passed in function?

$
0
0
Greetings!

I was wondering if it is possible to pull the string content of a passed in JavaScript function

Do you mean the function's JavaScript source code? If so, then you can use JavaScript's Function.prototype.toString():
publicvoid execute(dynamic function) {
    string sourceCode = function.toString();
    Console.WriteLine(sourceCode);
}
Cheers!

New Post: Is there a way to access the script frame stack?


Commented Issue: Problems using WindowsScriptEngineFlags.EnableDebugging [36]

$
0
0
I have code that executes fine on my machine with Visual Studio installed but have passed the code (compiled) including ClearScript.DLL to someone else who is getting an error when the script runs. I have tracked it down that if I remove the EnableDebugging I do not see the crash. But I need this option to get Column and Line numbers for errors in user scripts.

Is this crash caused by a lack of VS on the other machine? If so how do I work around this? I ONLY have the debug option enabled for line and column numbers (running v5.3.9 - not yet tried v5.3.11 as I cannot reproduce so need my colleague to run with latest DLL!)

Stack Trace Info below
at System.Activator.CreateInstance(Type type, Boolean nonPublic)
at Microsoft.ClearScript.Windows.ProcessDebugManagerWrapper32..ctor()
at Microsoft.ClearScript.Windows.ProcessDebugManagerWrapper.Create()
at Microsoft.ClearScript.Windows.WindowsScriptEngine.<>c__DisplayClass2.<.ctor>b__0()
at Microsoft.ClearScript.ScriptEngine.ScriptInvoke[T](Func`1 func)
at Microsoft.ClearScript.Windows.WindowsScriptEngine..ctor(String progID, String name, WindowsScriptEngineFlags flags)
at Microsoft.ClearScript.Windows.VBScriptEngine..ctor(String progID, String name, WindowsScriptEngineFlags flags)
at Microsoft.ClearScript.Windows.VBScriptEngine..ctor(String name, WindowsScriptEngineFlags flags)
MY ENTRY POINT -> at Configurator.ScriptProcessor.EnableAPI(API api)


Comments: Unfortunately, as far as we can tell, JScript and VBScript report only error messages when debugging is disabled. They report no further details, and the stack collection APIs simply fail. We'll keep looking, but if the only solution is to develop a script debugger, then it would make little sense for us to do so, since mature and powerful freeware debuggers are available.

New Post: Is there a way to access the script frame stack?

$
0
0
Hi joshrmt,

This is currently not possible and is rather unlikely as V8 has no public APIs that would enable it (the code on StackOverflow uses internal interfaces), but just in case, can you describe your scenario? Are you developing a debugger?

Thanks!

New Post: Cannot set a string as host object?

$
0
0
Hi,

I may be missing something obvious, but this call fails on a V8ScriptEngine:
engine.AddHostObject("test", "hello");
Feeling like a noob... :)
Thanks for your help!

New Post: Cannot set a string as host object?

$
0
0
Hello!

That's correct; ScriptEngine.AddHostObject() does not work with simple values like strings and numbers.

Instead, you can do any of the following:
engine.Script.test = "hello";
engine.Script["test"] = "hello";
engine.Execute("test = 'hello'");
Cheers!

New Post: Date marshalling

$
0
0
Hi again,

Based on my tests, it seems that the Date type, which is one of the few core JS types, is not marshalled across the JS/.NET boundary.
It would be very convenient if ClearScript could marshal it from & to the DateTime .NET type. Is this something you would consider?

Thanks
Thomas

New Post: Is there a way to access the script frame stack?

$
0
0
Im sure this will sound strange, but I wanted to be able to capture the current 'state' in order to transfer the closure/context to a different scripting environment. The alternate context is not necessarily a v8 engine, but a running browser. I am using this technique to 'sandbox' certain code in a secondary process but then 'inject' code into the browser.

New Post: Date marshalling

$
0
0
Hi Thomas,

In general, ClearScript favors seamless access over data conversion. We believe that this approach maximizes flexibility. There are exceptions, of course. If ClearScript didn't convert strings and numbers, for example, using it would be very painful :)

Instead of converting JavaScript dates to DateTime structures, ClearScript makes it easy for hosts to use JavaScript dates directly and convert them to DateTime structures if necessary:
dynamic date = engine.Evaluate("new Date()");
Console.WriteLine(date.toString());

var dateTime = new DateTime(
    date.getFullYear(),
    date.getMonth() + 1,
    date.getDate(),
    date.getHours(),
    date.getMinutes(),
    date.getSeconds(),
    date.getMilliseconds()
);
Console.WriteLine(dateTime);
ClearScript also makes it easy to deal with DateTime structures in script code:
engine.AddHostType("DateTime", typeof(DateTime));
engine.AddHostType("Console", typeof(Console));
engine.Execute(@"
    var dateTime = DateTime.Now;
    Console.WriteLine(dateTime);

    var date = new Date(0);
    date.setFullYear(dateTime.Year, dateTime.Month - 1, dateTime.Day);
    date.setHours(dateTime.Hour, dateTime.Minute, dateTime.Second, dateTime.Millisecond);
    Console.WriteLine(date.toString());
");
You could of course come up with more efficient conversion routines, but this is just an example.

Good luck!

New Post: Date marshalling

$
0
0
Thanks for your reply.
I kind of forgot that it was indeed possible to call methods of JS objects from the .NET side.

Cheers
Thomas

New Post: Long/Int64 .NET Data types

$
0
0
I'm having some trouble passing large numbers from .NET to the JScriptEngine. Here is what I'm trying to do:
        JScriptEngine engine = new JScriptEngine();

        engine.AddHostObject( "bigNumber", (long)1400000000000 );
        var result = engine.Evaluate( "'BigNumber: ' + bigNumber" );

        Console.WriteLine( "Result: " + result.ToString() );
I'm getting an error on the AddHostObject call. Is it possible to pass long/Int64 data types from .NET to the JScript engine?

Thanks,

Jamin

New Post: Date marshalling

$
0
0
I'm having some trouble with date marshaling as well. In my scenario I'm using JavaScript as a hook into how the application performs certain actions. I would like to expose a clean interface that leverages the native functionality in JavaScript including Date. This is important because I'm prioritizing the JavaScript syntax over the work it would take to accomplish it on the .NET side.

Here is my ideal script:
        JScriptEngine engine = new JScriptEngine();

        DateTime yesterday = DateTime.Now.AddDays( -1 );
        DateTime tomorrow = DateTime.Now.AddDays( 1 );

        engine.AddHostObject( "yesterday", yesterday );
        engine.AddHostObject( "tomorrow", tomorrow );

        StringBuilder scriptBuilder = new StringBuilder();
        scriptBuilder.AppendLine( "var now = new Date();" );
        scriptBuilder.AppendLine( "var todayAfterYesterday = now > yesterday;" );
        scriptBuilder.AppendLine( "var todayAfterTomorrow = now > tomorrow;" );

        engine.Execute( scriptBuilder.ToString() );

        Console.WriteLine( "TodayAfterYesterday: " + engine.Script.todayAfterYesterday );
        Console.WriteLine( "TodayAfterTomorrow: " + engine.Script.todayAfterTomorrow );
This example returns false for both outputs.

Even if I use a .NET DateTime.Now to compare my DateTime variables I still get false on both outputs.
        JScriptEngine engine = new JScriptEngine();

        DateTime yesterday = DateTime.Now.AddDays( -1 );
        DateTime tomorrow = DateTime.Now.AddDays( 1 );

        engine.AddHostObject( "yesterday", yesterday );
        engine.AddHostObject( "tomorrow", tomorrow );
        engine.AddHostObject( "now", DateTime.Now );

        StringBuilder scriptBuilder = new StringBuilder();
        scriptBuilder.AppendLine( "var todayAfterYesterday = now > yesterday;" );
        scriptBuilder.AppendLine( "var todayAfterTomorrow = now > tomorrow;" );

        engine.Execute( scriptBuilder.ToString() );

        Console.WriteLine( "TodayAfterYesterday: " + engine.Script.todayAfterYesterday );
        Console.WriteLine( "TodayAfterTomorrow: " + engine.Script.todayAfterTomorrow );
This returns false to both outputs as well.

The only solution I've found is to use method to compare the dates.
        JScriptEngine engine = new JScriptEngine();

        DateTime yesterday = DateTime.Now.AddDays( -1 );
        DateTime tomorrow = DateTime.Now.AddDays( 1 );

        engine.AddHostObject( "DateTimeComparer", new DateTimeComparer() );

        engine.AddHostObject( "yesterday", yesterday );
        engine.AddHostObject( "tomorrow", tomorrow );
        engine.AddHostObject( "now", DateTime.Now );

        StringBuilder scriptBuilder = new StringBuilder();
        scriptBuilder.AppendLine( "var todayAfterYesterday = DateTimeComparer.DifferenceInDays( now, yesterday );" );
        scriptBuilder.AppendLine( "var todayAfterTomorrow = DateTimeComparer.DifferenceInDays( now, tomorrow );" );

        engine.Execute( scriptBuilder.ToString() );

        Console.WriteLine( "TodayAfterYesterday: " + engine.Script.todayAfterYesterday );
        Console.WriteLine( "TodayAfterTomorrow: " + engine.Script.todayAfterTomorrow );
This example does return 1 and -1.

Has anyone else run into this? Why doesn't the compare operations work with both objects are .NET DateTime objects? Any better solutions? Any ideas, thoughts, insights would be much appreciated.

Regards,

Jamin

New Post: Long/Int64 .NET Data types

$
0
0
Hi Jamin,

I'm getting an error on the AddHostObject call.

That's correct. That method can't be used with simple values that are automatically converted to native script language datatypes, such as strings and numbers.

I also tried replacing the engine.AddHostObject() with engine.Script reference

That's the correct approach, but you've found an odd case. JavaScript (the language) doesn't support 64-bit integers; its only numeric datatype is 64-bit floating point. On the other hand, JScript (the engine) is implemented as a COM automation component and should therefore be able to handle 64-bit integer arguments.

This is where JScript appears to have a bug; instead of converting 64-bit integers to floating point, it imports them directly and treats them as "unrecognized data". In your example, typeof bigNumber evaluates to "unknown", which isn't even legal JavaScript. Very strange!

For now all we can recommend is that you avoid this situation. Convert 64-bit integers to double before passing them to JScript. We'll investigate this issue and consider making this conversion automatic in a future release.

Thanks for bringing this to our attention!

New Post: Date marshalling

$
0
0
Greetings Jamin!

I would like to expose a clean interface that leverages the native functionality in JavaScript including Date. This is important because I'm prioritizing the JavaScript syntax over the work it would take to accomplish it on the .NET side.

That makes a lot of sense, and as we demonstrated above, ClearScript makes it easy to expose an interface that directly supports JavaScript dates. Your implementation can use them directly or convert them internally to DateTime structures if necessary.

Regarding your code examples, the first two can't be made to work because JavaScript comparisons can't be redefined or overloaded to operate meaningfully on host objects.

Your third example can be simplified because DateTime already has a comparison method:
// JavaScriptvar todayAfterYesterday = now.CompareTo(yesterday) > 0;
var todayAfterTomorrow = now.CompareTo(tomorrow) > 0;
Cheers!
Viewing all 2297 articles
Browse latest View live


Latest Images

<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>
<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596344.js" async> </script>