Introduction
NScript is a tool similar to WScript except that it allows scripts to be written
in .NET languages such as C#, VB.NET and JScript.NET. NScript automatically
compiles the code into an assembly in memory and executes the assembly. The
NScript setup application associates NScript with ".ncs" (for C# scripts),
".nvb" (for VB.NET scripts) and ".njs" (for JScript .NET scripts) file
extensions. This enables any code written in these files to be
executed directly by double clicking on these files in windows explorer. I
wrote this tool when I needed to write a script for automating builds. A
simple batch file was not sufficient for the task and I preferred to write code
in C# as opposed to VBScript or JScript. This tool came in handy as I could
modify the scripts easily and execute them by double clicking on the files
in windows explorer.
Using NScript
- Download and unzip the setup
- Run the setup file NScript.msi. You need to have windows installer as well as
the .NET framework installed on the machine before running the .msi file
- The setup automatically associates the file extensions ".ncs", ".nvb" and
".njs" with NScript.
- Write some code in C# like
using System.Windows.Forms;
class Test
{
static void Main(string[] args)
{
MessageBox.Show("Hello World!", "NScript");
}
};
- Save the file and give it an extension of
.ncs
You can execute the code in the file in any of the following ways:-
- Double click on the file in windows explorer in that case the
script is launched using NScriptW
- At the command prompt type
NScript MessageBox.ncs
- At the command prompt type
NScriptw MessageBox.ncs
- You can execute code written in VB.NET or JScript.NET too. You need to save
VB.NET files with the extension ".nvb" and JScript.NET files with extension
".njs"
- To cancel the execution when running in console mode press Ctrl+C or
Ctrl+Break. When running under windows mode (i.e. NScriptW) an animating icon
is shown in system tray. Double clicking on the icon cancels the
execution.
The requirements for the code to be executed by NScript are:-
- The code should have a class defined.
- The class should have the Main method which takes single argument of type array
of strings.
- You can refer to any assemblies listed in a file named
NScript.nrf if it exists in the
same directory as the NScript.Exe. Here is a sample content of NScript.nrf file
System.Web.dll
System.Web.RegularExpressions.dll
System.Web.Services.dll
System.Windows.Forms.Dll
System.XML.dll
It just has list of assembly names on each line.
How it Works?
The NScript solution has three projects:-
- NScript - a C# console application
- NScriptW - a C# windows application
- NScriptLib - a C# class library
NScript and NScriptW are very much similar to each other; the former can be used
to run scripts that can output to console. NScript shows error messages in
console where as NSCriptW shows error messages using message boxes. It is
NScriptW which is associated with file extensions. Since there is lot of code
that is shared by the two executables the common code is compiled in NScriptLib
and both the executables refer to this class library.
The code behind NScript is pretty simple :-
-
NScript creates an asynchronous delegate that does
the compilation and execution asynchronously.
CompileAndExecuteRoutine asyncDelegate = new
CompileAndExecuteRoutine(this.CompileAndExecute);
IAsyncResult result = asyncDelegate.BeginInvoke(fileName,
newargs, this, null, null);
ExecutionLoop(result);
asyncDelegate.EndInvoke(result);
- The compilation and execution routine creates a
separate
AppDomain
where it does the main compilation and execution. This is
done because the user may require to cancel the execution of he script, in
that case the AppDomain
can simply be unloaded.
executionDomain = AppDomain.CreateDomain("ExecutionDomain");
IScriptManager manager = (IScriptManager)
executionDomain.CreateInstanceFromAndUnwrap(
typeof(BaseApp).Assembly.Location,
typeof(ScriptManager).FullName);
manager.CompileAndExecuteFile(file, args, this);
IScriptManager
interface is implemented by the type ScriptManager
. Since any object has to be marshaled in order for it to be referenced
from a separate AppDomain
, we need the interface IScriptManager
(as opposed to directly using the
ScriptManager
object). The ScriptManager
type extends the MarshalByRefObject
as it is marshaled by reference.
public class ScriptManager : MarshalByRefObject, IScriptManager
- The main compilation and execution is carried out by the
ScriptManager
object's
CompileAndExecute
method. It used CodeDOM to
carry out the compilation. It first figures out the CodeDomProvider
to use based on the extension of the input script file
CodeDomProvider provider;
string extension = Path.GetExtension(file);
switch(extension)
{
case ".cs":
case ".ncs":
provider = new Microsoft.CSharp.CSharpCodeProvider();
break;
case ".vb":
case ".nvb":
provider = new Microsoft.VisualBasic.VBCodeProvider();
break;
case ".njs":
case ".js":
provider = (CodeDomProvider)Activator.CreateInstance(
"Microsoft.JScript",
"Microsoft.JScript.JScriptCodeProvider").Unwrap();
break;
default:
throw new UnsupportedLanguageExecption(extension);
}
- Once we have a
CodeDomProvider
we can compile the file into a temporary assembly using the
ICodeCompiler
interface
System.CodeDom.Compiler.ICodeCompiler compiler =
provider.CreateCompiler();
System.CodeDom.Compiler.CompilerParameters compilerparams =
new System.CodeDom.Compiler.CompilerParameters();
compilerparams.GenerateInMemory = true;
compilerparams.GenerateExecutable = true;
System.CodeDom.Compiler.CompilerResults results =
compiler.CompileAssemblyFromFile(compilerparams, file);
- And finally the entry point method of the just compiled assembly is invoked.
results.CompiledAssembly.EntryPoint.Invoke(
null, BindingFlags.Static, null, new object[]{args}, null);
Conclusion
This is a very simple tool and I must confess that this is in no way an original idea. Don Box wrote a similar tool
long time back but I could not locate it. As a result I decided to write my own. In future I hope to enhance it by allowing
to compile and execute XML files similar to ".wsh" files. As usual any suggestions are welcome.
History
- November 18, 2002 - Initial posting