JurassicTools

Update

I released the first version, check out the blog post!

 

Intro

I’m developing a helper library for the awesome .Net JavaScript engine Jurassic. This will make it easier to control exactly what .Net classes you want to expose to JavaScript, just add some custom attributes, no need to inherit from ObjectInstance or similar. Types are converted automatically (e.g. a DateTime in C# becomes a Date in JS and Lists/Collections/etc. in C# become Arrays/Objects in JS). You can even expose members of third-party / framework stuff.

I felt the need to clearly define what gets exposed and what not. Although Jurassic has EnableExposedClrTypes, that didn’t give me control over what gets exposed, e.g. I think it would be possible to call any method or do some other nasty stuff from JS via GetType() and some Reflection magic. Also, it still was a bit tedious and the other cool features were missing. :)

Another thing that is important to me, is to write code that can not only be used from JS but also via .Net. That means write code once, use it via .Net or JS, your choice. No need to worry about ScriptEngine in your code, but if you want it, there’s HasEngineParameter (see Statics). That will be really helpful for some other projects I’m currently working on!

Check out some of the features and examples below (and compare them to the original way). No modifications were made to the Jurassic code, everything is done by the JurassicTools themselves!

 

Prerequisite

Just reference the library. For the examples I assume the following skeleton:

For this purpose, Logger just has one method named Info which prints to the console. EnableDebugging and ForceStrictMode are optional, but they are useful to have. In some examples a printObject function is used, this one is just defined at the top of script.js, as the following:

 

Cross-Platform

Everything should work not only on Windows with .Net, but also on Linux/Mac with Mono (tested on Mono 2.10.8.1). However a small hack to set 2 private fields of the ScriptEngine is necessary to put right above the skeleton:

 

Statics

Exposing your (public) members is as easy as adding a custom attribute to them. Non-Public members aren’t exposed, even if they have a correct custom attribute.

Objects:

Exposing:

Script:

Output:

All tagged members are ready to be used from JS, as printObject shows. The Invisible method doesn’t show up, because it’s not tagged with [JSFunction], also the Name property is read-only, because the setter is declared as private.

It is also possible to rename members, per the standard Jurassic attributes, of course. Even the HasEngineParameter JSFunctionFlag is supported. Default values for parameters are supported, too (had to put a little workaround into that).

You can instantiate StaticTest via JS, but your instance won’t have any members, because we didn’t expose any instance-level members. As these are all standard JS objects, you can toy with them, e.g. adding more properties (although these changes won’t carry over to .Net, obviously).

 

Instances / Constructors

Non-static stuff is easy, too. Just define some constructors or leave the default one.

Objects:

Exposing:

Script:

Output:

Several awesome things here. Objects you expose can be renamed for JS. Only the static members show up on the object itself and only the instance members show up on the instance. Thanks to renaming, the ToString() method can be used for both .Net and JS (this is a standard Jurassic feature, just to show it also works with the ‘easy-exposed’ objects).

You may have noticed that every public constructor can be called from JS, just like you can do from .Net! Oh, and if you just want to expose an instance of a class, there’s also an ExposeInstance method for you. :)

 

Enums

Enums are exposed the same way classes are.

Objects:

Exposing:

Script:

Output:

Normal enums and flag-enums are supported. And btw, if you run into a static class or only have a Type, there’s a non-generic ExposeClass overload, that accepts a Type (static classes can’t be used as generic arguments, the generic overload is really only there to save some typing and look cool ;) ).

 

Varargs

Your methods can include the params keyword to accept a variable number of arguments (again, a standard Jurassic feature, just to show it works here, too).

Objects:

Exposing:

Script:

Output:

 

DateTime <-> Date, Collections

Some objects are converted automatically, here is an example that passes and modifies a Date/DateTime between JS and .Net:

Objects:

Exposing:

Script:

Output:

As you can see, in .Net you can work on it as a normal DateTime and in JS you have a standard Date instance. But wait, there’s more! Let’s see some examples with arrays/collections (if you wonder about lines 8-10, read about Collection Initializers):

Objects:

Exposing:

Script:

Output:

Awesome, you say? Why yes, indeed! :)

 

Transparent Objects

Every instance that is exposed to JS is wrapped in a dynamic proxy, which holds a reference to the original object. This makes it possible to pass any object to JS. When that same instance returns from JS to .Net, it will unwrap as the original object!

from .Net and back again

Objects:

Exposing:

Script:

Output:

Note that the Token class wasn’t exposed, though a Token is returned from GetToken() and stored in the token JS variable. From JS it looks like token is an empty object, but when passed to PrintToken() it’s the same old object!

Non-exposed members of the Token instance can’t be altered, as tried by setting Value from the script. Although printObject shows the new property, it won’t alter the original Value, because it wasn’t exposed, so the script has no access to it (comparable to OO-JS with private members).

The Token class is completely transparent and JS has no clue about it, as the last line shows. :)

from JS and back again

With delegate support (see Delegates below for more details) it’s as simple as possible to write routines that call back into JS and pass along a previously-provided object.

Objects:

Exposing:

Script:

Output:

Again, the cool thing is, you can use CallbackTest/ BeginStuff either from JS or .Net code.

 

Exposing 3rd party stuff

So what about classes in the .Net framework or other assemblies, can they be used from JS? You bet!

With RegisterInfos you can provide custom attributes like JSFunction and JSProperty for members in classes you don’t have the source code for. When exposing objects, JurassicTools will first search for registered infos and then use explicitly provided attributes (overriding stuff from RegisterInfos).

Objects:

None, everything is already in the .Net framework! Check the docs of Environment, XmlNodeType and XmlNode.

Exposing:

(ok, I added a small helper function to easily get a XmlDocument ;) see Delegates below for more info)

Script:

Output:

Alright, try to contain your excitement! :) As you can see, it’s pretty easy to make use of third party classes in JS, just register the Type’s infos before it get’s exposed (either manually through ExposeClass/ExposeInstance or automatically because it’s returned somewhere). Good thing custom attributes are classes you can instantiate in .Net, eh? (suck it, Java and your ugly annotations!)

Of course you can also set properties like Name, IsConfigurable etc. on the infos. Notice that XmlNode wasn’t explicitly exposed through ExposeClass, yet every XmlNode instance returned by SelectSingleNode automatically has its members exposed, according to the infos. The //color[@name='red'] part is a XPath expression, if you aren’t familiar with XPath, check MSDN.

You may have noticed that there weren’t any infos registered for XmlDocument, but doc still had NodeType and the other members. That is because XmlDocument inherits from XmlNode. The exposer will check the registered infos for base types and apply their attributes, too. This also works for interfaces, btw, e.g. you can register suitable infos for ICloneable and make use of Clone in every object that implements the interface. :)

Also, because XmlNode implements IEnumerable to iterate through the child nodes, the object in JS is array-like and can be stepped through with indices.

 

Timers

Simple implementations of setTimeout, clearTimeout, setInterval, clearInterval and sleep (yes, this is just Thread.Sleep()). The set functions support additional parameters, but don’t accept a string as the first parameter, because that’s lame.

Exposing:

Script:

Output:

There needs to be some busy-loop throughout the whole duration of the execution, of course.

 

Delegates

JS functions can be passed as callbacks to .Net methods which expect a Delegate. A dynamic proxy with the right parameters and return value is created, which in turn calls the original JS function.

Objects:

Exposing:

Script:

Output:

One callback to rule them all! If you only want to expose a single delegate or lambda function as a global JS function, check this out:

Exposing:

Script:

Output:

 

Events

One use-case of delegates are events. With JurassicTools it’s possible to subscribe/unsubscribe to/from events.

Objects:

Exposing:

Script:

Output:

JSEvent is a custom attribute that ships with JurassicTools. Also note that the MyEventArgs class wasn’t exposed explicitly, but because an instance of this class is passed to the delegates, the members of that instance (not the whole class) with the correct JS* attributes get exposed automatically (standard exposing rules apply, think ExposeInstance). No need to write a huge expose-list if the JS code shouldn’t be able to instantiate certain classes, but be able to handle them, sweet!

 

Source / Future

JurassicTools is still pretty rough around the edges, although the above examples do work. I’ll make the source code public (probably on GitHub) once I tested it a bit more, cleaned the project up and added some comments. ;) It needs work to be more stable and it needs many, many unit-tests!

I mentioned in the intro that I’m using JurassicTools in other projects I’m working on. Those projects are developed for WebPlatform.org where I’m an admin (go check it out if you want to help building the best centralized resource for web developers!). The first project is a MediaWiki API library/bot (you can either add the assembly as a reference in your .Net project or run it as a bot that is controlled via JS scripts) and the other one is an IRC bot (also available to be used as a library or controlled via JS scripts).

So yeah, I hope you liked what you saw, hopefully I can get the code out next month (Jan ’13). :)

19 Responses to JurassicTools

  1. Hey, frozenice! What you’ve created here is pure awesome!
    I have a project “JuraScript” where I’ve added ActiveXObject to Jurassic.
    I’d really like to include/integrate your JurassicTools library. JuraScript is licensed under Ms-Pl.
    Is this possible? It would be fun to chat! Your comment thing should have my e-mail but I’ll try to check here too.
    -aikeru (Michael)

    • Hi aikeru, Thanks! :)

      Once I release the library/code you are free to use it! It will be under CC-BY (like everything on this blog), so there should be no problems.

      -fro

  2. So where’s the download and source? I could care less if it’s rough around the edges, there are folks who would have an immediate need for these features.

    • Hi Andrew,

      Sorry it’s taking so long, my day job and WebPlatform.org keep me pretty busy at the moment. Not much stuff left to do, but I still need to factor the project out of the solution. Currently there’s one solution for all projects (JurassicTools, MW API, IRC Bot, Tests).

      -fro

  3. When will it be ready????

  4. Can’t wait. Are you on GitHub?

  5. Will it be ready soon?

  6. Good job! I will wait release!

  7. FYI, I’m currently evaluating VS2012 / .Net 4.5 / Mono 3! I’d like to build on the newest stuff, I’ll need to run some tests first, though.

  8. Couldn’t you provide what you do have?Sorry if I seem impatient, but I’d really appreciate if I could have what you’ve got.Thanks

    • I get you. I’ll just need to test if there are major errors when compiling for.Net 4.5 or running under Mono 3 when I get home. Hopefully I can get the 3 projects (JurassicTools, MWAPI, IrcBot) up today!

      edit: sticking to VS2012, .Net 4.0 and Mono 2.10 for now!

  9. Excellent Job!This makes me to feel like to use  Jurrasic as Javascript inteptor for my browser.I recommend you to be a next project leader of jurassic project :-) .

  10. Excellent & Awesome!   I’ve been trying to find a viable, full Javascript capability for .NET for quite a while.  What you’ve done proves many aspects of such an integration work and is quite an improvement in usablility.  I have a Smalltalk background, which feels like writing with a word-processor, versus going back to C#, which feels like reverting to writing with a typewriter.  Although C# is nice, it takes a lot more time & is not as productive. Javascript is ubiquitous and has many language features of Smalltalk (minus the great IDE).  I hope to implement much of the domain model aspect of my current project using Javascript (Jurrasic).  Your JurassicTools are awesome. Thanks.Some questions:a. How does Jurrasic, using JurrasicTools perform vs C#?b. In your example, you have a dictionary with several different types of values.  Seems that would be a problem for C#.  Where are such issues caught? (compile time? runtime?)c. What’s the performance and limitations of collections, arrays, dictionaries on the Javascript side?d. Currently, I need to work in a .NET 3.5 (C# language version 3.0) environment.  Does Jurassic & JurassicTools work in this environment without issue?e. In your experience, what are the limitations of Jurassic for developing and deploying critical business applications?I took a look at http://www.webplatform.org/  Good stuff.  It would be great to build out such a resource and to integrate all those web-centric technologies (over time).  I believe the the opportunities and value-add is to encapsulate complexity by integrating technologies, like you’ve done with JurassicTools.  Thanks again.Petr

    • Hi Petr,

      Glad you like it. :)

      a) “vs C#”? I don’t know what you mean there, but I haven’t done any benchmarks.

      b) Why would that be a problem? Everything is an Object!

      c) Can’t think of any limitations.

      d) I don’t know, it could work. I’m currently compiling against .Net 4.0.

      e) I haven’t used Jurassic for any production applications yet.

      Sorry to not have all the answers, but I don’t have the time right now to do further research.

      It’s good you visited WebPlatform.org, but just to be clear, it doesn’t have anything to do with JurassicTools, except I’m involved in both. :)

      Cheers!
      - fro

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">