RemObjects Script for .NET

February 23, 2010 in .NET, Data Abstract, Mac, Mono, Prism, Visual Studio

A while ago, I started planning a new Data Abstract feature: we wanted to support scripting in the .NET parts of the product, for validating business rules on both the client and the server, and for writing server logic, like we already have in Data Abstract for Delphi. There were several options we considered to us to use:

  • IronPython/Ruby
  • JScript.NET
  • Active Scripting JScript COM objects
  • CodeDom (C#, VB.NET)

But each came with it’s own problems. CodeDom, IronPython & IronRuby wouldn’t work for the Delphi and OS X side of things, and we wanted the new solution to be compatible across platforms. JScript.NET was deprecated a while ago and isn’t updated anymore, and the JScript COM objects aren’t very easy to manage from .NET, and wouldn’t work on Mono.

So what we did instead was write our own JavaScript (or as it’s properly called ECMAScript) engine. Microsoft had just introduced the new DLR, so we decided to base it on that, to have a good framework that would let us have an implementation with good performance and interoperability with other DLR and non-DLR based languages.

Initially, the development of this went rather slow, as the DLR at the time was very new, not even a 1.0 version was available, there were few docs and the samples online were hopelessly out of date. Adding to that was the problem that every update of the DLR code changed something. But now the DLR is becoming quite stable and parts of it will be in the soon-to-be released .NET 4.0 framework.

Introducing Script for .NET

Script for .NET is the end result of this work, and it’s a free-with-source implementation of ECMAScript (edition 3). It has all the features expected from JavaScript and the default (non-browser) objects like Object, Array, Function, Math, Number, Date, String, Boolean and RegExp. As mentioned above, the engine is based on the Dynamic Language Runtime, but it works on version 2.0 and later of .NET, as well as on Mono.

Debugging Support

The engine includes support for in-process debugging by the host, allowing to step through, step into and step out of the current function, and inspect all the locals and their current state. The following screenshot of one of the included sample applications shows this i action:

Usage

To make the engine easier to use, the class library includes an EcmaScriptComponent class which wraps the DLR and Scripting engine, lets the application run and debug arbitrary scripts, as can be seen below.

 
private void ShowMsg(string s)
{
  MessageBox.Show(s);
}
 
 
  ScriptEngine = new EcmaScriptComponent();
  ScriptEngine.Globals.SetVariable("ShowMessage", new Action<string>(MessageBox.Show));
  ScriptEngine.Source = @"
    var pi = Math.PI;
    ShowMessage('Todays value of PI is : '+pi);";
  ScriptEngine.Run();

It is also possible to and expose classes or complete .NET assemblies to the engine for use from within the script:

  ScriptEngine.ExposeAssembly(typeof(System.Object).Assembly); 
  // exposes all namespaces in mscorlib.

Where to get it

You can read more about RemObjects Script on its product homepage. The project itself is maintained on our code.remobjects.com open source repository, with full access to the SVN and bug tracker. The Spring 2010 release is available for download, now.

With the script engine itself out of the way, we are now working o the integration with Data Abstract, for our Summer releases.

15 responses to RemObjects Script for .NET

  1. Nice work. Did you consider any of the existing open source implementations of javascript like IronJS (http://github.com/fholm/IronJS) or Jint (http://jint.codeplex.com/). Thanks.

    • script for .NET was started around 2009-05-15, as a personal project, so it predates IronJS (it’s been complete for a while, we just didn’t get around to turning it into a full product yet). I didn’t notice Jint at the time but it seems it’s also fairly new.

      • I tried the example in oxygene. The line will not accept self.showmessage. How is the syntax for parameters?

        ScriptEngine.Globals.SetVariable( ‘ShowMessage’, Self.ShowMessage );

        • if ShowMessage is a method you need to wrap it in a delegate first, SetVariable takes an Object, something like:

          ScriptEngine.Globals.SetVariable( ‘ShowMessage’, new Action(Self.ShowMessage));

  2. That looks nice! Your code snippet does not work because MessageBox has an invalid return type (not sure how to change that in the action, but seperate method returning void does the trick).
    Also .Text property must be .Source

    My solution:

    private void ShowMsg(string s)
    {
    MessageBox.Show(s);
    }

    private void button1_Click(object sender, EventArgs e)
    {
    EcmaScriptComponent ScriptEngine = new EcmaScriptComponent();
    ScriptEngine.Globals.SetVariable(“ShowMessage”, new Action(ShowMsg));
    ScriptEngine.Source = @”
    var pi = Math.PI;
    ShowMessage(‘Todays value of PI is : ‘+pi);”;
    ScriptEngine.Run();
    }

  3. great work & thank you for making this free. :)

    question:
    if two types with the same name but in different namespaces are exposed to the scripter, can you distinguish between them in script by prefixing the type name with the namespace?

  4. Love the idea of Javascript engine for .NET, is it possible to get the source code as a ZIP file?

    I cant run the .EXE on Linux.

  5. Can we run this components for WPF application?

  6. I was excited to see this! I’ve been looking for a fully working javascript DLR engine for a while.
    However, my first a simple experiment failed.

    Javascript, loaded into engine via a basic console app:
    function Test(x) { this.x = x; }
    Test.prototype.hello = function() { Console.WriteLine(‘x = ‘ + this.x); };
    var t = new Test(42);
    t.hello();

    Outputs to console:
    Hello = undefined

    instead of “Hello 42″

    Any ideas why this doesn’t work?

  7. Is this gonna go into the nuget feed ;)? http://nuget.codeplex.com/