-
Notifications
You must be signed in to change notification settings - Fork 35
Integrate with .net program
ReoScript provides the ability to execute JavaScript-like script in your application. It usually can be used in the following cases:
-
Application with script execution
Software with Macro or Script execution is required to be available for end-user. (like VBA in Excel)
-
Script to be ran under a native library that is provided by your Application
You have a library written in .NET Application, and you want to your end-user can use them by writing script.
-
Console Script Execution
Some batch process program, Daily build, File publish or something else. You are able to make extensions for ReoScript in .NET Application, and writing and running the script in console.
-
Download ReoScript binary or build source file. Add the following DLLs into reference list of your project.
Antlr3.Runtime.dll Unvell.ReoScript.dll
-
Import the following namespace
using Unvell.ReoScript;
-
Create ScriptRunningMachine and keep the instance
ScriptRunningMachine srm = new ScriptRunningMachine();
-
Run script from different source
-
Run script in text
srm.Run("console.log('hello world');");
-
Run script from internal resource
using(MemoryStream ms = new MemoryStream(Resources.script)) { srm.Load(ms); }
-
Run script from specified file
srm.Load("C:\\scripts\\main.rs");
-
Run script from specified stream (could be a network, or unzipped stream etc.)
srm.Load(new NetworkStream(...));
See ScriptRunningMachine.
-
There are two practices to integrate ReoScript into your application.
- Manual Mode (writing wrapper objects, properties or methods)
- Automatic Mode (using DirectAccess)
To connect the two worlds between script and .NET, the wrapper objects, properties and methods may be necessary to write.
+-----------------------------------------------------+
| Script |
| +-------------------------------------------+ |
+--- | Wrapper objects, properties and methods | ---+ <--- You may have to do
| +-------------------------------------------+ |
| .NET Application |
+-----------------------------------------------------+
I called this as 'Manual Mode' because anything you want to provide for script are all controllable precisely. Your end-user can only uses the functions that you want to be used. This practice is more safer and stable than Automatic Mode, it is also recommended usage if you are planning to make script execution is available to your end-user.
To write wrapper objects, properties and methods, the following classes you may need to use in .NET Application.
- ObjectValue - Make your own customized object type
- ExternalProperty - Make any external property for an object which used in script
- NativeFunctionObject - Make native method extension for an object which used in script
Once the script execution context(ScriptRunningMachine) is created, ReoScript keeps an global object until the context is destroyed. Global object can be understood as a root object in the context, all objects to be used in script should be added into global object firstly. Once the object(even a function) has been added into global object, it will be available to all scopes of functions in a context. (See GlobalObject)
If you want to add a function for script, you may create a NativeFunctionObject instance and add it into global object. For example:
ScriptRunningMachine srm = new ScriptRunningMachine();
srm["myfunc"] = new NativeFunctionObject("myfunc", (ctx, owner, args) => {
Console.WriteLine('myfunc called!');
});
Now use this function in script:
myfunc();
The text will be printed out in console:
myfunc called!
In ReoScript, everything even a function are objects, and one object can be added into another object as its property by a given name. For example:
var obj = new Object(); // create an object instance
var func = function() { }; // create an anonymous function
obj.myfunc = func; // set func into obj as its property (now it more likes a method)
See NativeFunctionObject.
All the objects, types, properties and methods which requested to use in script are all mapped to .NET Runtime automatically by ReoScript engine. In this Automatic Mode, the intermediate wrapper objects is unnecessary.
+-----------------------------------------------------+
| Script |
| +-------------------------------------------+ |
+--- | .NET Reflection / ReoScript Engine | ---+ <--- You don't have to do
| +-------------------------------------------+ |
| .NET Application |
+-----------------------------------------------------+
DirectAccess allows script to access the property of .NET object by .NET Reflection Technology. Although this feature can be a very simple way to integrate ReoScript, but it may also became a potential risk at script run-time. Unless you uses script inside your application, please consider about the Manual Mode as 'My Suggestion'.
(See more DirectAccess)
Although ReoScript provides DirectAccess mechanism to access .NET object directly, it is recommended that writing wrapper objects, properties and methods if you are planning to make script execution to be available for your end-user.
For example, assuming there is a .NET object with one method and property:
public class Application
{
public void Start() { ... }
public string Name { get; set; }
}
With DirectAccess, you would be able to call 'Start' method from script directly:
var app = new Application();
app.start();
Or access its property like:
app.name = 'stuff';
But if you reformed your .NET Application, like renaming method, the script will be unavailable. For usability it is recommended that writing wrapper method for your application and script.
-
Create wrapper object - create a class inheriting from ObjectValue, keep an instance of original object. And add methods that you want to provide for script.
public class ApplicationObject : ObjectValue { public Application Application { get; set; } public ApplicationObject() { // keep original instance this.Application = new Application(); // add wrapper method this["start"] = new NativeFunctionObject("start", (ctx, owner, args)=> { this.Application.Start(); }); } }
About function extension please see NativeFunctionObject.
-
Import this wrapper object type into script context
// prepare srm ScriptRunningMachine srm = new ScriptRunningMachine(); // import .Net type into srm srm.ImportType(typeof(ApplicationObject), "Application");
Then the Application class will be available to script.
var app = new Application();
app.start();
ReoScript supports many JavaScript features like showing message box using 'alert' function, perform an async-call using setTimeout or setInterval function. Sometimes you may want to decide what features can be available to your end-user, you are able to enable or disable ReoScript's built-in features by setting CoreFeatures enum. (See CoreFeatures)
The following example shows how to disable the built-in 'alert' function. There are two methods available as blow:
-
Modify CoreFeatures, minus the 'Alert'.
CoreFeatures features = CoreFeatures.StandardFeatures; features &= ~(CoreFeatures.Alert); ScriptRunningMachine srm = new ScriptRunningMachine(features); srm.Run("alert('hello,world')");
Then try to run script containing 'alert' function call, the exception will be thrown.
Function is not defined: alert
-
Override the built-in 'alert' function
Set global variable 'alert' to a new function that overriding the built-in one.
ScriptRunningMachine srm = new ScriptRunningMachine(); srm.Run("alert = function() { };");
Then try to run the script:
srm.Run("alert('hello,world')");
Nothing happened.
Overriding a built-in function is more safer because no exception will be thrown, and you would able to do something instead of the built-in feature. The following code overrides the 'alert' function and forwards message to [Standard I/O interface](Standard IO Interface).
srm.Run("alert = function(msg) { console.log(msg); };");