Click here to Skip to main content
Click here to Skip to main content

C# Script: The Missing Puzzle Piece

By , 30 Sep 2009
 

Summary

This article describes a script engine for the C# language. Here are some key features of the presented scripting system:

  • Based on full-featured C#
  • Full access to CLR and CTS
  • Can be run with any version of CLR (.NET 1.1/2.0-3.5), even potentially with future releases
  • Possibility of extending the functionality of any CLR application with "scripting" by hosting the script engine in this application
  • Integration with common IDEs and debuggers
  • Integration with OS
  • Availability of comprehensive documentation, i.e. local and online Help, Tutorials, Samples

Introduction

There are very specific programming tasks that require significant effort to accomplish in the traditional development scenario:

design -> coding-> compiling -> application

On the other hand, they can be achieved quite successfully by using scripting languages. Scripting can be very useful when:

  • The development environment is changeable: frequent code changes are expected
  • Application logic is simple: the application is needed for a very specific isolated task
  • Intellectual property protection is not an issue: source code is open
  • Maintenance and deployment requirements are very strict: software solution ideally resides in a single file and is deployed by simple copying of a minimal number of files
  • Development speed is expected to be faster than usual: code is composed of relatively heavy chunks

This article presents a scripting engine for the C# language, which I have implemented to simplify such tasks as configuring development, testing the environment, automating a build procedure, automating testing and collecting test results. These are all tasks that I, as an active C#/C++ programmer, do not normally like to do.

Latest Updates

The C# Script project (product name CS-Script) has already grown past the scale of a single article. It has its audience and it has found its way into a number of commercial and non-commercial products. For example MediaPortalFlashDevelop, K2 API or "WinTin" and "C# Script" projects on sourceforge.net. The version of CS-Script described in this article is v1.1.0. However, the currently available CS-Script version (v2.5.0) has some features that I could not have foreseen at the time of writing this article. Many of these features are the result of CS-Script user feedback. Some of them have changed the shape of CS-Script dramatically:

  • Ability to generate Runtime callable wrappers, WebService, Remoting and WCF proxies dynamically on-the-fly, without developer involvement. This makes CS-Script a very dynamic runtime environment while maintaining its statically typed nature
  • Extremely simple way of debugging C# scripts with any CLR debugger available on the target system
  • Support for other programming languages such as C++/CLI, VB.NET, J# and classless C#
  • Very simple script hosting model (hosting script engine from any CLR application)
  • True DuckTyping allowing aligning the scripted class to the interface defined in the host application.
  • In hosting scenarios ability to emit extremely fast delegates based on scripts containing method definition only

Anyway, I would encourage you to read the article because it explains C# Script's purpose and internals. I would also suggest that you download the binaries from the CS-Script home page. Below is a list of some of the latest release changes and features that are not in the article downloads, but are present in the current release:

  • Support for custom CLR compilers. VB.NET and JScript compilers are installed as part of the default CS-Script installation (v1.3.0)
  • Configuration console which simplifies the following tasks (v1.3.0-1.3.1):
    • enabling a particular IDE/debugger (Visual Studio 2003/5/8, Visual Studio 2005/8 Express, CLRDebugger, SharpDevelop)
    • selecting the target CLR version installed on the system
    • enabling CS-Script shell extensions
    • checking for updates, sending feedback, and accessing local and online documentation
  • Support for classless C# scripts (v1.5)
  • Ability to execute pre/post execution scripts (v1.5)
  • "Single-line access" for COM and Web Services (no importing type library or running wsdl.exe is required) (v1.5)
  • Conversion of C# script into Web Service (v1.5)
  • CS-Script automatic update (v1.5)
  • Command line switch //x (similar to the one used for VBScript) for executing C# scripts under any CLR debugger available on the target system (v1.6)
  • Script engine launcher css.exe, which allows running console scripts without displaying the console window, in case the script does not do any console output(v1.6)
  • Limited support for Compact Framework (v1.7)
  • Configurable (batch file based) Advanced Shell Extensions (v1.8):
    • Open script file in Visual Studio
    • Run script
    • Start script under debugger
    • Check script file for syntax errors
    • Start configuration console
    • Convert script to a Visual Studio 2005 project
    • Convert script to a Visual Studio 2008 project
    • Create shortcut to the script file for running it by double-clicking
    • Compile script into an executable
    • Compile script into a class library
  • Support for C++/CLI syntax (v1.9)
  • Support for WPF/XAML scripts (v1.9)
  • Sample scripts (Remoting, WCF, WPF, WWF) to the Script Library (v1.9-2.1):
  • Support for script probing directories SearchDirs. This functionality is similar to the system environment variable PATH. Also implemented SearchDirs console for simple management of the SearchDirs items (v1.9-2.0)
  • Vista support. Implemented process elevation for the script execution (v2.0)
  • Script caching algorithm for hosting the script engine (CSScriptLibrary.dll) from the applications (v2.0)
  • Concept of "script alias". Script alias is a "script like" file which links to the actual script file. Script alias is a logical equivalent of a file shortcut in Windows (v2.0)
  • Simplified Hosting Model: unrestricted 2-way communication between Script and Host without any setup cost (v2.1)
  • Support for C++ style Macros. CS-Script extends its ability to dynamically generate code at runtime and allows defining C++ style macros in C# code (v2.1)
  • Complete Visual Studio Integration with toolbar buttons/commands and code snippets library (v2.1)
  • Support for loading method definitions only (classless scripts) when hosting the script engine from managed applications (v2.2)
  • Remarkable performance (when hosting the script engine) due to the usage of emitted dynamic delegates (v2.2)
  • Simplified syntax for calling methods of dynamically loaded assemblies. Similar to C# 4.0 dynamics(v2.2)
  • Added interactive environment CSI (v2.3)
  • Support for specifying probing directories from the script and/or command line(v2.3)
  • Support for extendable environment variables in all import/include script directives (v2.3)
  • Added verbose execution mode which allows analysis of runtime information during the script execution (v2.3)
  • Added native support for classless script files with /autoclass directive (v2.4)
  • Implemented Interface Alignment (DuckTyping) for classes defined in script and instantiated in the hosta aplication (v2.4)
  • Added CS-Script launcher for Linux (v2.4)New.gif
  • Added integration with NAnt (v2.5)New.gif
  • Added Silverlight Player for viewing XAP files and converting Silverlight Web applications into self-sufficient desktop applications (v2.5)New.gif
  • Updated Linux related implementation modules. Now C# and VB.NET scripts can be run on Linux with simple double-click (v2.5)New.gif

Background

Microsoft has not provided many adequate scripting solutions. VBScript was the language that they expected to be used for scripting. Despite the fact that VB functionality can be extended with medium effort by creating COM components, its native functionality is extremely limited and the syntactic concept is badly designed. I believe a lot of people know that terrible aftertaste when working with VBScript. When .NET arrived, I expected that a script engine for the C# language would solve this problem. However, that did not happen. Microsoft did not provide a C# engine for WSH. Here is a reason given in MSDN:

Scripting has very little to do with .NET for two good reasons. First and foremost, WSH relies completely on COM. Second, the advantages you get from .NET languages over scripting languages are substantial in terms of performance and programming ease.

Microsoft provided only three scripting engines with .NET: old VBScript, old JScript and .NET intermediate language (IL). I do not know why C# is not there. A lot of developers need a powerful scripting language not because it does or doesn't fit some existing software concept, but because of all of the reasons I mentioned earlier. To recap, these are the need for simple and rapid development, frequent changes, effortless maintenance and deployment. I consider the absence of a script engine for C# as a Microsoft marketing mistake.

I was very excited when I saw Python for the first time. Finally, there was a powerful and flexible scripting solution. Here are some of the "hard to match" Python features:

  • Language is very rich
  • Possibility to pre-compile and avoid using compiling "on the fly"
  • Ability to do GUI development
  • Possibility to create objects (yes, it is an OO language)
  • Extensible by developing the modules in the same language
  • Portable

The more I worked with Python, the more I wanted to have something similar for C#. The idea was in the air. Browsing the Web, I came across a few attempts to tackle this problem. Some of them were reasonably successful (there are a few CodeProject articles on the subject), however every C# scripting solution I have seen was either based on the usage of some non-C# syntactical elements in the code or required an additional custom format file with some extra information (e.g. referenced assemblies). But I wanted to have a script engine capable of executing "plain vanilla" C# code.

All the time, I felt it was possible to use pure C# as a script language. One of the reasons for this is that running an application under CLR is very similar to running a script under a script engine. In both cases, execution happens under the runtime system and, in both cases, language interpretation takes place. Another interesting thing about the .NET Framework is that the C# compiler can be hosted by an application. All this eventually allowed me to implement a C# scripting engine. The engine application has nothing to do with WSH, despite some interface resemblance.

CS-Script Engine

I wouldn't like to spend too much time describing the script engine application. Its code is available, so help yourself. However, I still have to say a few words about it. The design of such an application is straightforward. Script execution consists of two steps: compilation and execution. The compilation part is trivial and some sample code can be found here.

The more challenging task was to implement loading of all of the referenced assemblies. The general problem with referenced assemblies is that it is not possible to determine what assemblies they are by just analyzing the code. Microsoft decided to handle this problem the easy way: the user explicitly nominates such assemblies by adding them into a special XML file, *.csprj. I could not use such an approach, as I decided to use a plain vanilla *.cs file as the only input file for running the script.

My approach was based on the fact that in real life there is a strong correlation between the assembly name and the root namespace. For example, the namespace System.Windows.Forms is implemented in the assembly System.Windows.Forms. Similarly, the namespace System.XML is implemented in the assembly System.XML. This is also applicable to the assembly file name, which is usually a DLL file with the same name as the assembly name.

[assembly file name] = [assembly name] + .dll

Thus, I can resolve the namespaces from the script into assemblies. I do this for both global (GAC) and local assemblies.

[namespace] -> [assembly name] -> [assembly file name]

In order to find the location of the global assemblies, it is necessary to browse GAC. Unfortunately, there is no .NET API available for navigating in the GAC, only the COM one. After some research, the problem was solved. I'd like to thank atoenne (CodeProject), John Renaud (CodeProject) and Junfeng Zhang for their very interesting articles regarding working with the GAC. They helped me a lot.

Dealing with the local assemblies is as challenging as with the global ones. I use the predicting assembly file name algorithm, based on the namespace, as a starting point. However, as I mentioned before, there is only the correlation between the namespace and the assembly name but no true relationship. Things can get even more complicated if the assembly file name is different from the assembly name. On top of this, the assembly root namespace can have no resemblance to any of those names. Thus, it is not possible to reliably predict what assembly is referenced. The only way out of this is to apply Reflection to the assemblies found in the script directory (current directory).

However, there is still no guarantee that all of the namespaces from the script can be resolved. That is why I provided a "back door": the assembly can be explicitly specified as a command-line argument. I have never had to use this feature as, so far, all of the namespaces in my scripts were always resolved. The only restriction I have to impose is that any assembly which is referenced in the script must reside either in the GAC or in the same folder where the script is.

Basically, the script execution looks like this: The user runs the script engine application and specifies a script file as an argument. The script file is just a *.cs file with a defined static method Main(...). The engine compiles the script into an assembly and executes a well-known entry point in this assembly: Main(). The advantages of such a scripting system are obvious and I will illustrate them by stating some of the features of this new scripting system:

  • Simple deployment approach: just bring both the script and engine files (about 30 K size) on a system that has the .NET runtime installed, and the script can be run
  • Portability: scripts can be run on any system that has the CLR installed
  • Base language is a truly OO language: full-featured C# is used. I call it "C# Script" but actually it is "C#". "C# Script" slightly better represents the execution nature
  • All .NET functionalities are available (FCL, COM Interop, Remoting)
  • Easily available debugger and rich IDE (Microsoft .NET Studio, CLR Debugger)
  • Execution model within the script is the same as any .NET application: static void Main()
  • Any script can be easily converted into an application and vice versa
  • Optimized interpretation: interpretation of any statement in the script is done only once, even if the statement is frequently used throughout the code
  • Script language is type safe: strong typing is a luxury not available in most of the scripting languages
  • Dynamic typing is also available for "die hard" VB lovers. Just go with Object as a default type and do boxing/unboxing all the time
  • All of the software development tasks can be done in the same language
  • GUI development for script applications becomes easy
  • Extensibility: it can be extended by using new assemblies written in any .NET language or COM components

Using C# Script

I have already done some development with CS-Script and found the system to be stable and reliable. Here are some of the features of the script engine application:

  • Comes with two interfaces: WinForms and console applications
  • Can execute a standard *.cs file that has the Main() method defined
  • Can store the compiled assembly file in the same location as a script file; can execute it next time instead of compiling the script again if the script was not changed since the last execution
  • Can generate a template script file as a starting point for further development
  • Can generate an executable from the script. Thus, no script engine is required to run it again
  • Can generate an assembly from the script, so it can be used as any other class library
  • Script engine is not sensitive to script file extensions. The user can specify any file or a file name without an extension. In this case, *.cs will be assumed
  • Script engine looks for the script file in the directories specified as the PATH environment variable, if it is not found in the current directory

Features added on user demand:

  • Script engine can be hosted by any CLR application. An assembly that implements the script engine as a Class Library is available as part of the downloadable package
  • Script engine can load multiple scripts. This is useful when a script uses the functionality of another one
  • Explicitly referenced assemblies can be added not only from the command-line but also directly from the code

The script engine application is named cscscript.exe, or cswscript.exe for the WinForms mode. The simplest way to prepare any script is to execute it from a command prompt:

cscscript /s > Sample.cs

This will generate the Sample.cs file in the current directory. Sample.cs is a C# source file. You will need to add valid C# code to this file to do your specific tasks. After that, it can be compiled and executed by the script engine via the command: cscscript.exe sample.cs

Sample.cs

using System;
using System.Windows.Forms;
class Script
{
 static public void Main(string[] args)
 {
 MessageBox.Show("Just a test!");
 for (int i = 0; i < args.Length; i++)
 {
 Console.WriteLine(args[i]);
 }
 }
}

Script execution:

ScreenSh.JPG

Once again, the script file contains ordinary C# code. There is not a single language statement that would be understood only by the script engine but not by any C# compiler (Microsoft .NET Studio). This is one of the strongest points of CS-Script:

C# Script is not another flavor of C#. It is C#, which is compiled and executed differently.

Any script file can also be opened, compiled, and debugged with .NET Studio because it is nothing but C#. I have to say that I got more than I had anticipated at the start of this whole exercise. The script engine is just an application and relatively a primitive one at that. However, its functionality can be extended with scripts. The system's main purpose is to execute scripts that can be improved by other scripts. It may sound odd, but that is exactly what is happening. Such scripts can:

  • Install the script engine (publish in EnvVar PATH)
  • Insert any script file into a predefined C# project and open it in .NET Studio. Thus, it is ready to be run under the debugger
  • Create shell extensions to run or open any script file in .NET Studio with just a right-click of the mouse. As you can see, the same script engine application is much more capable now
  • Compose a C# script on the fly from a code fragment and execute it, e.g. cscscript code MessageBox.Show("Just a test!") will pop up the message "Just a test!"

As you can see, the same script engine application is much more capable now.

CS-Script Package

You can download -- from the top of this page or from my Web page -- the whole CS-Script package, which contains the script engine, useful scripts and the samples. To install, you will need to extract everything from the ZIP file and execute install.bat. Of course, .NET Framework has to be installed first. After the installation, you will have the Environment variables updated and all of the shell extensions created. Strictly speaking, no installation is required. The script engine application is self-sufficient and can be run immediately after downloading. The only action performed during the installation is an adjustment to the OS environment in order to make scripting as convenient as possible. Here is the list of some very simple scripts that I have created and added to the package:

  • NKill.cs - Kills processes specified as command-line parameters
  • GetUrl.cs - Gets the URL content and saves it in a file. Can handle proxy authentication
  • Debug.cs - Opens a script with a temporary C# project for running it under the debugger
  • Install.cs - Installs/uninstalls the CS-Script shell extensions that will permit running/debugging of any script with a mouse right-click
  • ImportData.cs - Imports data from the specified file to an SQL Server table
  • ExportData.cs - Exports data to the specified file from an SQL Server table
  • RunScript.cs - Script that runs another script in the background with redirection of the output to the parent script
  • Tick.cs - Simple script that counts a specified number of seconds; used as demo for RunScript
  • SynTime.cs - Gets time from here and synchronizes the PC system time
  • MailTo.cs - Sends an e-mail to the specified address
  • Reflect.cs - Prints the assembly reflection information
  • Creditentials.cs - Prompts and collects user login information
  • GetOptusUsage.cs - Retrieves monthly data usage. This is applicable only for "Optus Australia" customers
  • Interop.cs - Creates and accesses COM and CLR objects
  • ImportTickScript.cs - Imports -- with the import directive -- and executes the tick.cs script
  • Client.cs Script.cs Common.cs - Example of extending any application with CS-Script scripting
  • And others...

Points of Interest

Previously, I had about a hundred C# projects on my hard drive. In most cases, these projects contained about 100-200 lines of code, just to test some algorithm or code sample from MSDN. Now, I have only a single *.cs file for any coding exercise. I just right-click on it and it is in the .NET Studio and ready to go. It is so convenient! There is another thing that I really like about scripting. Development and testing can now be done in the same programming language. Here is a simple example:

You need to test your assembly that does, for example, printing. Under runtime conditions, the assembly is used by the main application. However, you need to do printing a thousand times to get some statistics. To do it from the main application would mean contaminating the main application with the testing code. What you can do is copy the main application code that invokes the assembly into the *.cs file and run it with the script engine. In this case, the assembly is tested under the same conditions as at run-time and the design of the test is more elegant.

Therefore the script engine combined with the scripts becomes a small development system.

Conclusion

C# scripting is not supposed to compete with traditional C# development. They serve completely different purposes. C# scripting is simply something that was missing in the .NET family, the "missing puzzle piece" in the title of this article. I am interested in knowing what other people think and would appreciate any feedback.

Feedback

I would like to thank all of the people who sent me their suggestions and ideas. Some of them have been implemented in the current version of the script engine. One of the most-asked questions is about hosting the script engine. Just by accident, I found a forum where I was criticized for underestimating the importance of script hosting. I guess they are right. Despite the technical possibility of hosting the script engine from the very early versions (Math.cs and MathClient.cs samples), a lot of users wanted hosting to be simpler and more straightforward. Following users' requests, I have implemented full-scale script engine hosting. All possible hosting scenarios are described here. Briefly, hosting would involve:

  • Compiling the script into assembly, i.e. script assembly by script engine
  • Loading the script assembly into the appropriate AppDomain
  • Exercising objects implemented in the script assembly

I have added two methods to the CSScript class (CSScriptLibrary.dll):

  • Load - Compiles the script into assembly and loads it into the current AppDomain. Returns the loaded assembly object
  • Compile - Compiles the script into assembly and returns the assembly file name. Thus, the assembly can be loaded in any AppDomain

All this allows simple script hosting with unrestricted data exchange between the host and the script, with just a few extra lines in code. See the Client.cs, Script.cs, and Common.cs samples.

There were a few very interesting suggestions that I have not implemented in the way in which they were proposed. I will explain it by an example. There was a proposal to have the script engine take a C# statement and execute it without having the actual script written. The idea was good, but I did not want to put such functionality into the script engine. I see the engine as a simple, reliable and self-contained application that is not overloaded with functionality. Only in this way can it be robust and stable. I do not want to modify it each time I decide to execute scripts differently. I see the presented scripting system extensible by other scripts and assemblies, rather than by re-implementing the engine. This way, the script engine will be protected from any changes in the system. That is why I implemented the proposed feature as a script (code.cs). Thus, the purpose is achieved without any changes in the script engine. The following is an example of how to use this script:

cscscript code MessageBox.Show("Just a test!")

The script Samples.cs is implemented in a similar manner:

  • cscscript samples: Prints a list of available samples
  • cscscript samples mailto myMailto.cs: Saves the content of the "mailto" sample into the myMailto.cs file
  • cscscript samples 1 myScript.cs: Saves the content of sample #1 into the myScript.cs file

There was another proposal to have the script running within a specified security context. This can be implemented using the same approach. For example...

cscscript runas sa:sysadmin myScript

...runs myScript as a user sa with password sysadmin. Also, many people have asked me about running multiple script files. In such a scenario, one script would execute another one to do some job. I have implemented this (5th Feb 2005 update) and the downloads are available. I have to say that I consider this feature as something outside the original scope of the script engine. This is because, as I mentioned before, a complex application that requires more than one file can be implemented as a traditional C# application. So, there is no real need to use CS-Script. However, from users' feedback I see that many people want to see that feature in the script engine.

It is implemented in a manner similar to the C++ #import. The Import directive will merge script files together at run time. Thus, all of the code from one is available for another and vice versa. The syntax is available in a help message ("cscscrip.exe /?"). To avoid naming conflicts, importing can do optional namespace renaming. See the provided sample file importTickScript.cs for details.

I recently added support for a new directive called reference. It can be used to reference assemblies directly from the code. The syntax is available from the help. You can also see the TeeChartForm.cs sample. As I mentioned earlier, in some circumstances the namespace cannot be resolved into an assembly name. It is a really rare case, but it can happen. For example, if the Steema.TeeChart namespace is implemented in the teechart.lite.dll assembly. To solve this problem, such an assembly can be provided as a command-line argument. In some cases it can be inconvenient, so I implemented the reference directive to reference an assembly directly from the code. The syntax for both the import and reference directives are designed in a way that keeps the script code 100% CLS compliant.

Thanks again to all of the people who showed interest in this project. If you are interested in hot fixes between the article updates, you will be able to download them from CS-Script home page (www.csscript.net).

History

  • 26th Oct, 2004
    • Initial post
  • 29th Oct, 2004
    • Script file (install.cs) updated to fix an installation problem
  • 12th Nov, 2004
    • Added to the article:
      • Description of assembly resolving algorithm
      • Description of new features
      • Feedback section
    • Changes in the downloadable items:
      • Added support for local assemblies
      • Implemented compiling script into an EXE file
      • Added the CSScriptLibrary assembly (CSScriptLibrary.dll) for hosting the script engine by CLR applications
      • Script engine applications are mirrored now, cscscript.exe/csc.exe and cswscript.exe/csw.exe
  • 5th Feb, 2005
    • Added to the article:
      • Updated list of keywords and feedback section
    • Changes in the downloadable items:
      • Added support for running multiple script files
    • Updated the debug.cs script. It is now able to resolve all the referenced namespaces, or references to other scripts from the code and generate the appropriate Visual Studio project
  • 10th Jun, 2005
    • Added to the article:
      • Updated feedback section
    • Changes in the downloadable items:
      • Added support for referencing assemblies from the code
      • Updated the debug.cs script. It is now able to add assemblies referenced from the code to the appropriate Visual Studio project
  • 20th Jul, 2005
    • Added to the article:
      • Updated feedback section
    • Changes in the downloadable items:
      • Added support for the .NET 2.0 Framework
      • Improved support for script hosting
      • Added support for Visual Studio 8.0, SharpDevelop, and the Microsoft CLR Debugger
  • 16th Aug, 2005
    • Changes in the downloadable items:
      • Fixed bug that prevented installation of shell extensions for Visual Studio 2005
      • Added support for [STAThread] and [MTAThread] attributes in the script
      • Added some new sample scripts
  • 27th Oct, 2005
    • Added update description (v 1.2) at the start of the article
  • 25th May, 2007
    • Article updated
  • 19th July, 2007
    • Article and downloads updated
  • 8th April, 2008
    • Article updated
  • 28th Feb, 2009
    • Article updated
  • 22nd Jun, 2009
    • Article updated
  • 29th Sep, 2009
    • Article updated

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Oleg Shilo
Technical Lead
Australia Australia
I was born in Ukraine. After completing the university degree worked there as a chemist. Last 16 years I live in Australia where I've got my second qualification as a programmer.
 
"I am the lucky one: I do enjoy what I am doing!"

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralMy vote of 5memberdzmuh31-Jan-13 21:06 
Cool project. Thanks!
GeneralBug in version 3.0.0.0memberOctopod17-Jun-11 5:06 
I found a bug when running css_config.exe, at first time configuration. I'm under Windows Seven. I unpacked the archive in my download directory, after unblocking its content. I ran css_config.exe, then I exit it clicking Close button, choosing No when the dialog asked me to save or not the configuration. I move the folder in my Program File, then ran again the css_config.exe which throw an ApplicationException : Cannot use alternative compiler...
You can reproduce the same exception by renaming or moving the installation folder then running again css_config.exe.
To solve it, I unpacked again the .zip, then ran again css_config.exe which this time was able to give me a normal message explaining me that a previous installation already exists somewhere else, giving me the ability to replace it.
 
Nice work, keep up !
Cheers.
GeneralRe: Bug in version 3.0.0.0memberOleg Shilo18-Jun-11 1:37 
Thank you for letting me know.
 
I tested it and indeed the recovery algorithm is not as comprehensive as one would want.
 
While the error message gives some ideas on how to fix the problem "adjusting CSSCRIPT_DIR Env Var" but it is confusing and even misleading nevertheless.
 
There are two problems:
1 - The error notification is inadequate.
2 - The script engine should be more proactive and try to make a repairing decision on behalf user when it is appropriate (when old installation does not exist any more).
 
The fixes will be available with the next release (most likely next week).
 
If you want to be notified on the releases please click the "add to mailing list" on the user feedback page:http://www.csscript.net/Feedback.html[^]
 
And for the quicker response please report the problems through "report bug" on the same page.
 
Thank you again for the info.
 
Cheers,
Oleg
GeneralRe: Bug in version 3.0.0.0memberOleg Shilo20-Jun-11 1:40 
The fix for this defect just has been released. You can download it from here http://www.csscript.net/CurrentRelease.html[^]
QuestionWhats the difference with microsoft script engine?membermalfaro27-Feb-11 12:50 
Microsoft script engine handle vbscript and jscript languages in a com technology way.
Can this engine be handle in visual c++ applications...
Can you publish a sample of how to do this???
Mauricio Alfaro

AnswerRe: Whats the difference with microsoft script engine?memberOleg Shilo27-Feb-11 13:28 
Hi malfaro,
 
Yes CS-Script engine can be hosted in the unmanaged applications through callable wrappers. I have no ready to go example but you can google for it "how to call managed code from unmanaged application". CS-Script assembly is signed so you will have no problems hosting it.
 
I can tell you more. CS-Script is commercially used for one of the CAD add-ins. This add-in is an unmanaged application, which hosts CLR based CS-Script engine. Unfortunately I am not at liberty to name this product.
 
Cheers,
Oleg
General"Failed to grant permission to execute."memberJaromir Matysek31-Jan-11 2:20 
Hello,
I'm trying to run CSScript under SharePoint, and I'm getting the "Failed to grant permission to execute" error - I'm guessing it's because SharePoint only allows assemblies that are written in web.config etc.
 
Any ideas how to deal with this?
 
Thanks!
GeneralRe: "Failed to grant permission to execute."memberOleg Shilo31-Jan-11 3:46 
Hi Jaromir,
 
I am no expert in SharePoint configuration. Thus it is hard for me to give you an educated advise.
 
However your problem can be related to the assembly locking issue when the latest Windows versions (Win7 and Server2008) do not treat downloaded assemblies as "tratsted".
 
Have a look at section #28 (http://www.csscript.net/FAQ.html#_winServ2008[^]). May be it is the solution.
 
Cheers,
Oleg
GeneralRe: "Failed to grant permission to execute."memberJaromir Matysek31-Jan-11 5:01 
Thanks for quick answer
 
However, that wasn't the issue.
 
AFAIK in order to run in SharePoint, the generated assemblies would have to be strongly named (PublicKeyToken), and probably also located in SharePoint's Program Files/.../14/Bin
 
Would this be possible?
 
Thanks
GeneralRe: "Failed to grant permission to execute."memberOleg Shilo31-Jan-11 11:08 
Hi Jaromir,
 
Actually CSScriptLibrary.dll is a strongly named assembly (make sure you are using the uptodate release). But it does not make any difference until you register it with GAC. And as far as GAC concerns the actual location of the assembly does not make any difference.
 
Cheers
GeneralRe: "Failed to grant permission to execute."memberJaromir Matysek1-Feb-11 5:37 
Yep, CSScriptLibrary.dll is, I've got it referenced in my SharePoint project and I'm able to use it. However, the assemblies it generates are not, and I couldn't find a way to change the output directory. So I was asking whether it would be possible to somehow sign the temporary assemblies a store them in a chosen directory. I can imagine then I could persuade SharePoint to load them.
 
Thanks Smile | :)
GeneralRe: "Failed to grant permission to execute."memberOleg Shilo1-Feb-11 21:43 
OK. I see your point.
 
Signing of the temp assemblies is indeed possible. There are a few options for available:
 
1. The simplest way is to specify the key file for signing the script as a "compiler option" when loading the script. Note that it is an optional parameter for the MS C# compiler (csc.exe), which the script engine just passes through. Have a look at the code sample E:\cs-script\Samples\Hosting\ConditionalCompilation.cs. This should work though I have never tried it.
 
2. CS-Script allows post-processing of the freshly compiled script before its execution. CS-Script comes with the example for the aspect injection (AOP) with PostSharp. This is where you will find the details: http://www.csscript.net/help/scriptPostProcessing.html[^].
 
You can run some sort of relinking utility/routine which would sign the assembly during linking. Th approach is very similar to the way PostSharp does the injection.
 
---------------------------------------
The approach #1 is the simplest and cleanest. #2 is rather exotic but it may be the way if #1 is not working for what ever reason.
 
I still beleive that the location of the assembly is irrelevant but you can specify where CS-Script should create the temporary assembly when you call CSScript.Load() or CSScript.Compile().
GeneralMy vote of 5memberManfred R. Bihy19-Jan-11 11:59 
A must have! 5
GeneralGreat workmembernenfa10-Jan-11 4:41 
thanks for your great workThumbs Up | :thumbsup:
GeneralRe: Great workmemberOleg Shilo11-Jan-11 12:00 
Not a problem. I am glad you found CS-Script useful.
Oleg
Generalwsdl errormembermtone22-Apr-10 16:54 
I am playing with the WCF samples and I get this error
 
Error: Specified file could not be executed.
 
Script C:\Projects\Tools\cs-script\Lib\wsdl.cs cannot be executed.
 
Since I am new to this code I am not sure what t olook for. Can you give me some help.
GeneralRe: wsdl errormemberOleg Shilo23-Apr-10 0:04 
Hi mtone,
 
wsdl.cs is the script responsible for running Microsoft wsdl.exe utility. It needs to be executed in order to produce a proxy cs file for consuming by WCF client application.
 
In your case wsdl.exe for some reason cannot generate the proxy file. I would suggest that you remove the proxy generating instructions in the WCF client script (e.g. //css_prescript wsdl(http://localhost/hello?wsdl, HelloService, /new)) and try to generate the proxy file manually.
 
In order to do so run wsdl from command prompt with the same parameters as in the client script. This will show where the problem is.
 
If you cannot solve the problem send the request to the csscript.support@gmail.com address and I will have a closer look at your problem.
 
Cheers,
Oleg
GeneralRe: wsdl errormembermtone23-Apr-10 4:16 
Thanks
 
I got it to work, I had a typo in the URL path.
 
One other thing while I am here.
 
The Sample is listed under WCF but the sample only specifies an HTTP call. How about other binding types? do you have any samples for using cs-script for them?
GeneralRe: wsdl errormemberOleg Shilo23-Apr-10 4:56 
The sample in the WCF folder was intended to give developers an idea on how to use WCF in C# scripts with auto-generating proxy class with wsdl.exe. Demonstration of all binding flavors of WCF is well beyond the scope of CS-Script documentation.
 
If your client script/application does not use proxy the code is absolutely the same as for the standalone non-scripted application.
 
Saying that, I have prepared for you the sample of using named pipes with WCF: http://dl.dropbox.com/u/956512/mtone/SimplePipe%2BHTTP.zip[^]
 
Cheers,
Oleg
GeneralErrors from concurrent use in from different AppDomains [modified]membericyvisor12-Mar-10 4:20 
First of all, let me state that that to me the ease at which cs-script allows implementing type-shared hosted pattern is breakthrough.
Not only it is a missing piece but the silver bullet. It allows dealing with the fundamental problem of wild variation when you can't throw enough data models and expert systems at the problem domain to have good coverage. If you have a good object model and API for you problem domain don't look further than cs-script when the real world is laughing in your face and you understand that your models only cover the tip of the iceberg.   Yo have the ultimate weapon right here.
 
That said, I am starting to see a compilation issue when multiple appdomains of the same application are entering same compilation calls, like this for example:
 
error CS0016: Could not write to output file 'c:\WINDOWS\Temp\CSSCRIPT\Cache\949632885\2CE2.dll' -- 'The process cannot access the file because it is being used by another process. '
 
The application is done in ClickOnce with only the CSScriptLibrary.dll being distributed. The global settings are initialized in a static class as follows:
 
CSScript.CacheEnabled = false;
CSScript.GlobalSettings.InMemoryAsssembly = true;
CSScript.GlobalSettings.TargetFramework = "v3.5";
CSScript.ShareHostRefAssemblies = true;
 
Can this error be somehow guarded against?
 
Want to say thanks again for saving me and my small team. We have a great system with all the pieces but variation was killing us. Please accept my small token of appreciation.
 

-- Modified Friday, March 12, 2010 10:29 AM
GeneralRe: Errors from concurrent use in from different AppDomainsmemberOleg Shilo13-Mar-10 0:02 
Hello icyvisor,

I am glad you found CS-Script useful. And you are absolutely right: variations it is where CS-Script works the best. You can "promote" your scripts (addressing the variations) to the "static" code, if you wish, by including them in your compiled codebase. Or you can move any "too static" code from your application to scripts. And all this can be done with very little effort.
 
Now about your problem.
 
Usually such symptoms indicate problems with concurrent compilation/execution of the same script file by multiple code routines. Have a look at "<cs-script>\Samples\Hosting\Modifying script without restart" sample in the distributable package. If it is not relevant to your problem contact me by this email: csscript.support@gmail.com. Provide a bit more details and I think I will be able to help.
 
Regards,
Oleg
GeneralRe: Errors from concurrent use in from different AppDomainsmembericyvisor16-Mar-10 3:13 
Thanks, turns out we were using it slightly differently,
 
example:
 
new AsmHelper(CSScript.Compile(<String>, null, true));
 
we have:
 
new AsmHelper(CSScript.LoadCode(<String>));
 
would you think this could account for the file collision effect?
 
Thanks
GeneralRe: Errors from concurrent use in from different AppDomainsmemberOleg Shilo16-Mar-10 22:33 
Yes it could, but I cannot say for sure it did.
 
Nevertheless I would appreciate if you can send me HelloWorld style replica of your application. I would like to see if I can implement some safeguard against this problem.
 
Thanks,
Oleg
GeneralRuntime recompilingmemberMember 75523920-Sep-09 10:19 
Hi, I'm trying to implement runtime recompiling of code. I have a game engine which I want external .cs scripts to be able to be altered without stopping the main program.
The way I want to try to do it is by using another AppDomain for each script. So when a .cs file is modified I unload it's AppDomain, compile the new .cs file and create the assembly again (and possibly restore as many variables as possible)
Is this what csscript is doing? Can I unload and update the scripts in place? Thanks!
GeneralRe: Runtime recompilingmemberOleg Shilo25-Sep-09 19:38 
Hello 755239,
 
Sorry for the late rsponse: I was away the last week.
 
You need to have a look at the TextProcessor tutorial (http://csscript.net/help/Text_processor.html[^]).
 
I also composed for you extremely simple example here: http://dl.getdropbox.com/u/956512/755239/755239.7z[^]
 
Cheers,
Oleg
GeneralUsing a script to write to the Hosts richtextbox.memberG Murray7-Sep-09 5:21 
Hi Oleg
 
Thanks for creating C# Script.
I'm basically trying get it to do the job of LabView. I've used LabView a lot
I'm trying to attach the script engine in to a logging application that I've had running for a couple of years.
I'v emanaged to get it to interact with public variables in my class but I'm unable to have it pass data to a rich text box and a MessageBox.
For both MessageBox.Show and LogToScreen calls I get :
error CS0103 : The name MessageBox does not exist in the current context.
error CS0103 : The name LogToScreen does not exist in the current context.
 
Here is an example I've created to illustrate my problem.
Form 1 has a single button and a single richtextbox.
 
I'd be very grateful if you could tell me where I'm going wrong.
 
Thanks in advance
 
Gerry Murray
Glasgow
Scotland
 
code :
 
using System;
using System.Windows.Forms;
using System.Windows;
using CSScriptLibrary;
 
namespace ScriptEngineTest
{
 
public partial class Form1 : Form
{
static public uint a = 5;
static public uint b = 7;
 

public Form1()
{
InitializeComponent();
}
 
private void button1_Click(object sender, EventArgs e)
{
LogToScreen("richtextbox1 visible from here!\n");
 
var code = @"using System;
using System.Windows;
using ScriptEngineTest;
 
public class Script : MarshalByRefObject
{
public void RunActions(string passtring)
{
MessageBox.Show((Form1.a * Form1.b).ToString());
LogToScreen(Form1.a.ToString() + Form1.b.ToString());
}
}";
try
{
var script = CSScript.LoadCode(code)
.CreateInstance("Script")
.AlignToInterface<IScript>();
script.RunActions("Hello RichTextBox1");
 
}
catch (Exception ex)
{
MessageBox.Show(ex.Message.Trim());
}
 

}
 
public interface IScript
{
void RunActions(string passtring);
}
 
public void LogToScreen(string msg)
{
richTextBox1.AppendText(msg);
}
 
}
 
static class Program
{
 
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
 
}
GeneralRe: Using a script to write to the Hosts richtextbox.memberOleg Shilo7-Sep-09 14:56 
Hi Gerry,
 
There are a few tiny mistakes in your code that prevent it from working.
- In your script code you are using MessageBox but there is no using statement for System.Windows.Forms
- You are trying to call LogToScreen without specifying object instance (LogToScreen is an instance method). Also you are not passing that instance from the host.
- IScript interface should not be a nested class.
 
The working code looks like this:
 
public interface IScript
{
    void RunActions(string passtring, Form1 f);
}

namespace ScriptEngineTest
{
    public partial class Form1 : Form
    {
        public uint a = 5;
        public uint b = 7;

        public void LogToScreen(string msg)
        {
            instance.richTextBox1.AppendText(msg);
        }

        private void button1_Click_1(object sender, EventArgs e)
        {
            LogToScreen("richtextbox1 visible from here!\n");

            var code = @"using System;
                         using System.Windows.Forms;
                         using ScriptEngineTest;

                         public class Script
                         {
                             public void RunActions(string passtring, Form1 f)
                             {
                                 MessageBox.Show((f.a * f.b).ToString());
                                 f.LogToScreen(f.a.ToString() + f.b.ToString());
                             }
                         }"
;
            try
            {
                var script = CSScriptLibrary.CSScript.LoadCode(code)
                                            .CreateInstance("Script")
                                            .AlignToInterface<IScript>(true);

                script.RunActions("Hello RichTextBox1"this);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message.Trim());
            }
        }

        

 
Please note that I removed MarshalByRefObject as it is not needed within current context and also added true to the AlignToInterface to allow the script and the host application to share the same assembly set.
 
Let me know if you still experience problems and I will send you the whole Form1.cs file.
 
Cheers,
Oleg
GeneralRe: Using a script to write to the Hosts richtextbox.memberG Murray8-Sep-09 0:45 
Hi Oleg
 
Thank you for the quick reply.
You're right about the MessageBox. I missed that one.
 
Unfortunately, there are still a couple of issues. Mainly brought about by my lack of C# knowledge and how to use CS-Script in my context.
I'm not a newbie by any means but passing around object references is a struggle for me, similar to the problems I had getting my head around pointers in 'C' 15 years ago.
 
The problems I'm still having are :
 
1.
My richtextbox is designed and placed on the form designer rather than instantiated explicitly in Form1 at runtime so I'm not sure how I would get a reference to it to pass to my script.
 
2.
The 'instance' object reference you use in the line : 'instance.richTextBox1.AppendText(msg);', I'm not sure how that instance is declared and where since it's not referred to anywhere else in your reply.
This means that I can't call 'LogToScreen' from the script.
 
3.
Placing the ISCript interface outside of 'namespace ScriptEngineTest' means that it doesn't have visibility of 'Form1' and so the program doesn't compile.
 
Changing it to 'void RunActions(string passtring, Form f);' allows it to compile but then the script call to 'MessageBox.Show((f.a * f.b).ToString());' results in :
error CS1061 : System.Windows.Forms.Form' doesn't contain a definition for 'a'. I understand why this is, it's because I'm referring to a generic form rather than my specific 'Form1'
 
When I change my script call to refer to 'Form1' specifically, I get error CS0176: Member 'ScriptEngineTest.Form1.a' cannot be accessed with an instance reference; qualify it with a type name instead.
Giving it a type name takes me back to CS1061.
 
Yes, I'd readily admit that I may be missing something obvious.
 
Bottom line is: yes please, can you send me Form1.cs? Wink | ;-)
 
Thanks in advance.
 
Gerry Murray
GeneralRe: Using a script to write to the Hosts richtextbox.memberOleg Shilo8-Sep-09 1:48 
Hi Gerry,
 
>1. My richtextbox is designed and placed on the form designer rather than instantiated explicitly in Form1 at runtime so I'm not sure how I would get a reference to it to pass to my script.
Put //css_include Form1.designer.cs; at the top of your Form1.cs.
 
>2. The 'instance' object reference you use in the line : 'instance.richTextBox1.AppendText(msg);', I'm not sure how that instance is declared and where since it's not referred to anywhere else in your reply.
It was a typo please remove 'instance' and the dot after it.
 
>3.Placing the ISCript interface outside of 'namespace ScriptEngineTest' means that it doesn't have visibility of 'Form1' and so the program doesn't compile.
It does not have to be outside of namespase (though it can). It just has to be plain not nested type.
 
However the best way of handling this is to work with the original code. Please respond to this post with direct email with attached not working script(s) and I will fix it up for you and send back.
 
Cheers,
Oleg
GeneralDebugging when invoked from the libmemberkittelmann24-Aug-09 23:10 
I'm using the CSScriptLibrary.dll assembly, version 2.5.2 from cs-script\Lib\Bin\NET 3.5\
 
I invoke CS-Script as you suggested with
using CSScriptLibrary;
 
...
 
                CSScript.ShareHostRefAssemblies = false;
                var masterScript = new StringBuilder();
 
                var scripts = Directory.GetFiles(scriptDir,
                                                 "*.cs",
                                                 SearchOption.AllDirectories);
 
                foreach (var file in scripts)
                    masterScript.AppendFormat("//css_import {0};\n", file);
 
                string asmFileTypedTableBase = Assembly.GetAssembly(typeof(System.Data.TypedTableBase<DataRow>)).Location;
                string[] assemblies = { ".\\CSScriptLibrary.dll", ".\\MyClient.exe", asmFileTypedTableBase };
 
                MzExportInterface exportObj = CSScript.LoadCode(masterScript.ToString(), assemblies)
                                                        .CreateObject("MyClient.ExportTemplates." + exportTemplateName + "." + exportTemplateName)
                                                        .AlignToInterface<MzExportInterface>();
 
                exportObj.StartExport(scriptDir, exportDir);
 
However, I fail to debug my scripts. When I set breakpoints in the code, it never stops there. I've read http://csscript.net/help/Debugging.html, but it seems focused on debugging scripts that are launched standalone with cscs.exe (eg. use these command line switches)
 
And I don't quite get the debug samples...
 
Do you have any specific hints how to make the debugging work? I don't have any other process to attach to since CS-Script is loaded in process, and it's not CS-Script I want to debug but the script it executes.
GeneralRe: Debugging when invoked from the libmemberOleg Shilo25-Aug-09 0:40 
LoadCode has another overloaded signature which accepts bool flag indicating if debug simbols for the script should be generated.
 
The code appropriate for debugging should look like following:
 MzExportInterface exportObj = CSScript.LoadCode(masterScript.ToString(), null, true, assemblies)<br/>                                       .CreateObject("MyClient.ExportTemplates." + exportTemplateName + "." + exportTemplateName)<br/>                                       .AlignToInterface<MzExportInterface>();
Cheers,
Oleg
GeneralRe: Debugging when invoked from the libmemberkittelmann25-Aug-09 11:51 
Thanks!
 
And for others reading this: Remember to put the breakpoint in the correct script file if you, just like me, have the script being copied to the bin folder. Having a System.Diagnostics.Debug.Assert(false); in the code works fairly well as well.
GeneralRe: Debugging when invoked from the libmemberCoolSpin29-Aug-09 6:34 
You can also use Debugger.Break()[^] in System.Diagnostics. No need to check the IsAttached[^] property, as the Break() checks this itself.
GeneralSigned assembliesmemberkittelmann16-Aug-09 9:58 
Hello again!
 
My work is going forward with a good pace, and CS-Script is working excellently!
 
However, I was wondering if you could please sign the assemblies (CSScriptLibrary.dll) that come as part of the binary package, so that I can sign my application.
 
I could download the source and compile/sign it myself, but I feel that that is undesirable since I'd rather not handle the CS-Script source code myself just to sign it.
 
I'm not in any hurry, but perhaps something to consider for the next release.
GeneralRe: Signed assembliesmemberOleg Shilo16-Aug-09 13:43 
kittelmann wrote:
I was wondering if you could please sign the assemblies (CSScriptLibrary.dll)

 

Certainly.
QuestionDynamic typing - how does it work actually?memberMember 88171915-Aug-09 10:38 
Hi, How do i use the dynamic typing feature in cs-script?
Documentation describes about using the Object as the default type and box/unbox it. Can you give me an example for it?
 
Thanks.
AnswerRe: Dynamic typing - how does it work actually?memberOleg Shilo15-Aug-09 18:30 
Hi there,
 
Yes, this is what documentation says:
 
Script language is type safe:
strong typing is a luxury not available in most of the scripting languages. Dynamic typing is also available: use Object as a default type and do boxing/unboxing all the time.
 
This sort of dynamic typing is (and always was) available in C# and as such this feature has no relation to the scripting nature of CS-Script.
 
This is a pseudo code example:
static public void Main()
{
    object result = Add(1,2);
 
    Console.WriteLine(result);
}
 
static object Add(object a, object b)
{
    return (int)a + (int)b;
}
But honestly, why would any one do anything like that? Strong typing offers not only safer but also more readable/maintainable code.
 
Of course with C# 4.0 actualy dynamic typing can be really useful:
dynamic calc = GetCalculator();
int sum = calc.Add(10, 20);
instead of reflection based equivalent in C# 3.0:
object calc = GetCalculator();
object res = calc.GetType().InvokeMember("Add",
                                         BindingFlags.InvokeMethod, null,
                                         new object[] { 10, 20 });
int sum = Convert.ToInt32(res);
Cheers,
Oleg
GeneralRe: Dynamic typing - how does it work actually?memberMember 88171915-Aug-09 22:48 
Thanks for the info. The documentation suggested that it really added functionality to support dynamic typing. But it is default c# behavior, but that is not what i needed.
GeneralRe: Dynamic typing - how does it work actually?memberOleg Shilo16-Aug-09 1:30 
>The documentation suggested that it really added functionality to support dynamic typing.
 
Initially I disagreed. Documentation never suggested that neither strong nor dynamic typing is a feature of the CS-Script engine. That is why I quoted the documentation in my previous post. In fact that quote was taken from the CS-Script Help section describing the advantages of any scripting system based on C#, not only CS-Script.
 
However...
 
On the CS-Script home page the very same documentation statement was splet into two separate sentences, what indeed made an impression that CS-Script has its own feature associated with dynamic typing.
 
I apologise for any confusing. To avoid any further misinterpretation this statement about dynamic typing has been already completely removed from the CS-Script home page.
 
This statement will be reinstated only when MS releases its dynamic typing support for C# 4.0. And an appropriate explanation will be supplied.
 
------------------------------------------------
 
However there is a real CS-Script specific feature associated with dynamic typing - DuckTyping.
 
It is not what you asked about (boxing/unboxing) but it is about generating strong types dynamically from the script.
 
It offers dynamic typing but without complitelly surrendering the type safty (as in case of C# 4.0). You can find details here: http://csscript.net/help/Script_hosting_guideline_.html#_interfaceAlignment[^]
 
Regards,
Oleg
GeneralRe: Dynamic typing - how does it work actually?memberMember 88171916-Aug-09 2:41 
No problem. I really like CS-script as it is now. Great tooling. Wondering when Microsoft is going to release C# 4.0.
 
Thanks for the link about ducktyping. Maybe it can help me to get to my goals. Thanks again en good luck with further development.
 
Arjen
GeneralRe: Dynamic typing - how does it work actually?memberOleg Shilo16-Aug-09 13:02 
Member 881719 wrote:
Wondering when Microsoft is going to release C# 4.0.

 
I think it is October/November this year.
GeneralHost running script that spans multiple filesmemberkittelmann14-Aug-09 0:34 
My scenario is as follows:
I have an application, and users will be able to write small plugins to it, or modify existing plugins.
The plugins will be written/coded i CS-Script.
The size of the plugins will vary a lot. Some will be very small, while others will be large.
The users and plugin writers might not have access to a compiler, that's why I'm using CS-Script.
 
So, some scripts will be rather large, have multiple classes, and be split in several files. I have decided that the scripts will be placed in one directory per plugin.
 
So, I discover that I have a plugin directory, and what I want to do then is to load all *.cs files in there and execute one method in one of the files (I know which class/file that starting method is in).
I can include other files by using the //css_import statement, but preferably I'd like the users to not have to worry about which files to include. (I'd rater like them to not have to worry about any css directive at all).
 
Is it possible to do multiple CSScript.Load(file1) for one AsmHelper and thus load all files present without using //css_import ?
 
I have tried to merge all files into one string, but that fails since using statements should come before the rest of the code.
 
Do you have any idea if this is possible?
GeneralRe: Host running script that spans multiple filesmemberOleg Shilo14-Aug-09 2:18 
Yes it is possible. And you will be surprised how this actually is:
(the whole example can be downloaded from here http://dl.getdropbox.com/u/956512/kittelmann/LoadDir/LoadDir.7z[^])
 
public interface IScript
{
    void Print(string msg);
}

...

var masterScript = new StringBuilder();

var scripts = Directory.GetFiles(Environment.CurrentDirectory, 
                                 "*.cs"
                                 SearchOption.AllDirectories);

foreach (var file in scripts)
    masterScript.AppendFormat("//css_inc {0};\n", file);

IScript script = CSScript.LoadCode(masterScript.ToString())
                         .CreateObject("Plugins.Script")
                         .AlignToInterface<IScript>();

script.Print("Hello World!");

GeneralInvokeInst and namespaces gives exceptionmemberkittelmann13-Aug-09 9:22 
Namespaces in the script doesn't work when invoking an instance method.
Namespaces does seem to work when invoking a static method.
This applies to versin 2.5.0, and I have only tesed it within another C# application.
 
Working code:
string scriptCode = "using System;\n                       " +
                                    "public class Calc                     " +
                                    "{                                     " +
                                    "   public int Subtract(int a, int b)  " +
                                    "   {                                  " +
                                    "      return a - b;                   " +
                                    "   }                                  " +
                                    "}";
 
            CSScript.ShareHostRefAssemblies = false;
            AsmHelper helper = new AsmHelper(CSScript.LoadCode(scriptCode, null, false, ".\\CSScriptLibrary.dll", ".\\MyClient.exe"));
 
            object calc = helper.CreateObject("Calc");
            int c = (int)helper.InvokeInst(calc, "Subtract", 5, 3);
 
Non-working code:
string scriptCode = "using System;\n                       " +
                                    "namespace testspace{                   " +
                                    "public class Calc                     " +
                                    "{                                     " +
                                    "   public int Subtract(int a, int b)  " +
                                    "   {                                  " +
                                    "      return a - b;                   " +
                                    "   }                                  " +
                                    "}}";
 
            CSScript.ShareHostRefAssemblies = false;
            AsmHelper helper = new AsmHelper(CSScript.LoadCode(scriptCode, null, false, ".\\CSScriptLibrary.dll", ".\\MyClient.exe"));
 
            object calc = helper.CreateObject("testspace.Calc");
            int c = (int)helper.InvokeInst(calc, "Subtract", 5, 3);
The exception is:
ApplicationException: Method Calc.Subtract(System.Int32, System.Int32) cannot be found.
at:
   at CSScriptLibrary.AsmBrowser.FindMethod(String methodName, Object[] list)
   at CSScriptLibrary.AsmBrowser.Invoke(Object obj, String methodName, Object[] list)
   at CSScriptLibrary.AsmHelper.InvokeInst(Object obj, String methodName, Object[] list)
   ...

GeneralRe: InvokeInst and namespaces gives exceptionmemberOleg Shilo13-Aug-09 17:32 
Yes this particular scenario exposes the defect in AsmHelper.InvokeInst.
 
I have fixed the problem and the fix will be published tomorrow. In a mean time I will send you the binaries by email.
 
However I want to draw you attention that using Reflection based calls (AsmHelper.InvokeInst in your example) is not necessarily the best approach (though there is nothing wrong with this).
 
Arguable the better choice is CS-Script DuckTyping. Advantages: more readable, strongly typed code, your example will work with just out of box CS-Script v2.5.
 
using CSScriptLibrary;

...

public interface ICalc
{
    int Subtract(int a, int b);
}

...

static void Test()
{
    string scriptCode = @"using System;
                          
                          namespace testspace
                          {                  
                              public class Calc                     
                              {                                     
                                  public int Subtract(int a, int b)  
                                  {                                  
                                      return a - b;                   
                                  }                                  
                              }
                          }"
;

    CSScript.ShareHostRefAssemblies = false;
    var script = CSScript.LoadCode(scriptCode,
                                   Assembly.GetExecutingAssembly().Location, //your client.exe
                                   typeof(CSScript).Assembly.Location);      //CSScriptLibrary.dll

    ICalc calc = script.CreateObject("testspace.Calc")
                       .AlignToInterface<ICalc>();    //DuckTyping

    int c = calc.Subtract(5, 3);
    Console.WriteLine(c);
}
 
Cheers
GeneralRe: InvokeInst and namespaces gives exceptionmemberkittelmann14-Aug-09 0:13 
That seems like an excellent solution, because what I really want is not for the script to say that it implements my script-interface, but to actually enforce it from the host side.
GeneralDuplicate mscorlib loaded when loading CSScriptmemberkittelmann6-Aug-09 11:16 
Hello!
 
CSScript seems like a very nice script engine, and I though I'd give it a try for my application.
 
However, I just can't make it work. Sigh | :sigh:
I'm not if it's related to that I'm using Visual Studio 2010 Beta 1 with .NET Framework 4 Beta.
 
The code I'm using is:
 
TestScript.cs:
using System;
using System.Windows.Forms;
 
class TestScript
{
    public void ShowString(string message)
    {
        MessageBox.Show(message);
    }
}
 
MzOptions.cs (a part of my application, compiled and working save for this issue):
private void button3_Click(object sender, EventArgs e)
{
    //Run the script
    AsmHelper helper = new AsmHelper(CSScript.Load("ExportTemplates\\TestScript.cs"));
    helper.Invoke("TestScript.ShowString", "Hello World");
}
 
And the Load call throws the following exception:
(0,0): error CS1703: An assembly with the same identity 'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' has already been imported. Try removing one of the duplicate references.
 
in:
   at csscript.CSExecutor.Compile(String scriptFileName)
   at csscript.CSExecutor.Compile(String scriptFile, String assemblyFile, Boolean debugBuild)
   at CSScriptLibrary.CSScript.Load(String scriptFile, String assemblyFile, Boolean debugBuild, String[] refAssemblies)
   at CSScriptLibrary.CSScript.Load(String scriptFile)
   at MazermindClient.MzOptions.button3_Click(Object sender, EventArgs e) in D:\Data\Projects\Mazermind2\Source\MazermindClient\Forms\MzOptions.cs:line 78
   at System.Windows.Forms.Control.OnClick(EventArgs e)
 
...
 
   at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
   at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
   at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
   at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading.ThreadHelper.ThreadStart()
 
Do you have any suggestion to what I can change to fix it?
 
Thanks in advance!
GeneralRe: Duplicate mscorlib loaded when loading CSScriptmemberOleg Shilo7-Aug-09 14:23 
Hello kittelmann,
 
The problem you are experiencing is caused by your runtime environment. It looks like in your experiment your current AppDomain has at least two mscorlib, Version=4.0.0.0 loaded. And because CS-Script engine by default treats all loaded assemblies as potential referenced assemblies for the script it supplies the to MS C# compiler, which does not like such a duplication.
 
The solution would be to switch off the assembly sharing between Host and Script. Though then you will need to handle all referenced assemblies for the script by yourself.
 
With the next CS-Script release (in a day or two) the problem will be handled even in the assembly sharing mode as long as duplicated assemblies have the same file name (not path).
 
I have composed the example for you, which demonstrates the problem and way of solving it.
 
http://dl.getdropbox.com/u/956512/kittelmann/kittelmann.7z[^]
 
Note the example is using CS-Script v2.5 binaries.
 
Cheers,
Oleg
GeneralRe: Duplicate mscorlib loaded when loading CSScriptmemberkittelmann7-Aug-09 21:21 
Thanks for your help. I'm looking forward to the new version of CS-Script!
GeneralRe: Duplicate mscorlib loaded when loading CSScriptmemberkittelmann13-Aug-09 9:25 
I've downloaded 2.5.0, and there still seems to be the same problem with duplicate mscorlib loaded.
 
I have tried the CSScript.ShareHostRefAssemblies = false; approach, and it does seem to work.
 
I don't really have any idea as to why I would have duplicate mscorlib loaded, the only reason I can think of is that I have some references to other assemblies that have loaded mscorlib themselves...

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web01 | 2.6.130617.1 | Last Updated 30 Sep 2009
Article Copyright 2004 by Oleg Shilo
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid