ScriptSharp-v0 4 2
ScriptSharp-v0 4 2
net
Script#
Version 0.4.2.0
September 11, 2007
Table of Contents
Introduction .................................................................................................................................................. 5
What can you build with Script#? ............................................................................................................. 5
Script# 101 .................................................................................................................................................... 7
The Hello World Application (Using Scriptlets for Script Code-behind) ................................................... 7
Building a Script Component in a Script# Class Library .......................................................................... 18
Summary ................................................................................................................................................. 22
The Script# Framework ............................................................................................................................... 23
Script Type System and Base Class Library ............................................................................................. 23
Script# Framework .................................................................................................................................. 23
Core Programming Model, Networking, and UI Concepts - ssfx.Core.dll ........................................... 23
Cross-Domain AJAX using JSONP - ssfx.XDAjax.dll .............................................................................. 24
UI Controls and Behaviors - ssfx.UI.Forms.dll ..................................................................................... 24
Reflection Utility - ssfx.Reflection.dll .................................................................................................. 24
Microsoft Silverlight XAML DOM - ssagctrl.dll .................................................................................... 24
Microsoft Virtual Earth APIs - ssve4.dll ............................................................................................... 24
Windows Vista Sidebar Gadgets - ssgadgets.dll ................................................................................. 24
File System APIs - ssfso.dll .................................................................................................................. 24
RSS Feeds - ssfeeds.dll ........................................................................................................................ 24
Naming Convention ................................................................................................................................ 25
Using Script# with Microsoft ASP.NET AJAX ............................................................................................... 25
Differences and Limitations .................................................................................................................... 25
Importing Existing Script Libraries and Scriptable APIs .............................................................................. 26
Native Scriptable Objects and ActiveX Controls ................................................................................. 26
Existing Script Libraries ....................................................................................................................... 28
A Deeper Look at the Script# System.......................................................................................................... 29
How Script# Works? ................................................................................................................................ 29
Components and Layers.......................................................................................................................... 30
Script Runtime Choice ............................................................................................................................. 31
Using Script# ........................................................................................................................................... 31
Script Components and Libraries ........................................................................................................ 31
Scriptlets ............................................................................................................................................. 32
Limitations .............................................................................................................................................. 33
C# Limitations...................................................................................................................................... 33
JavaScript Limitations ......................................................................................................................... 34
How Do I Accomplish a Particular Script Scenario? .................................................................................... 35
Using eval to Execute Code and Perform JSON Deserialization?............................................................ 35
Using alert, prompt and Related Methods ............................................................................................. 35
Performing Late-bound Member Access ................................................................................................ 36
Deleting a Field from an Object .............................................................................................................. 37
Enumerating Members of an Object ...................................................................................................... 37
Retrieving the Native Script Type of an Object ....................................................................................... 37
Defining and Implementing Global Methods.......................................................................................... 38
Invoking Global Methods ........................................................................................................................ 38
Defining Nested Functions to Implement Closures ................................................................................ 38
Creating and Using Plain Script or JSON Objects .................................................................................... 39
Creating Plain JSON Objects .................................................................................................................... 40
Checking for Undefined .......................................................................................................................... 41
How is a Particular C# Feature Modeled in Script? .................................................................................... 41
How is a Namespace Defined?................................................................................................................ 41
How is a Class Defined? .......................................................................................................................... 41
How is a Derived Class Defined? ............................................................................................................. 42
How is an Interface Defined? .................................................................................................................. 42
How is a Delegate Type Defined? ........................................................................................................... 43
How are Delegates Used? ....................................................................................................................... 43
How are Enumerations Defined and Consumed? ................................................................................... 44
How are Properties Declared and Accessed? ......................................................................................... 45
How are Indexers Declared and Accessed? ............................................................................................ 45
How are Events Declared and Accessed? ............................................................................................... 46
How are Static Members Declared and Accessed? ................................................................................ 47
How is a foreach Statement Implemented? ........................................................................................... 47
How are Anonymous Delegates Implemented ....................................................................................... 48
Roadmap ..................................................................................................................................................... 49
Feedback ..................................................................................................................................................... 50
Version History............................................................................................................................................ 51
License......................................................................................................................................................... 57
Introduction
Script# is a C# compiler that generates JavaScript (instead of MSIL) for use in Web applications or other
script-based applications such as Windows Vista Sidebar gadgets. The primary goal of Script# is to
provide a more productive scripting environment for developing Ajax applications that are more
maintainable over the long term by leveraging various aspects of the C# development model such as:
A key tenet of Script# is to generate JavaScript that is readable, understandable, and closely matches the
originating source wherever possible. The goal is not to abstract away the underlying script APIs (such as
the DOM), but to instead allow direct access, so the engineering choice of using a more productive tool
does not sacrifice functionality or performance. The resulting JavaScript is compatible with the script
support available in modern browsers.
Script# works by leveraging the C# build process, and fits in naturally and intuitively, as explained in the
How Script# Works section. The compiler requires .NET Framework v2.0 on the development machine.
You can deploy the resulting scripts on any server environment. You will need ASP.NET 2.0 on the server
if you’re using the server-side features (script code-behind for pages).
Script# can be leveraged in existing applications. It provides facilities to import existing script libraries as
well as scriptable APIs such as the DOM, and those exposed by browser plugins such as Flash and other
ActiveX controls. This is explained in the Importing Existing Script Libraries and Scriptable APIs section.
To enable you to quickly start creating script-based applications and components, Script# provides
support for key DOM APIs, as well as other APIs such as WPF/E and Virtual Earth. It provides support for
Microsoft ASP.NET AJAX, and also provides its own highly functional framework as an option for you to
use. For out-of-browser scenarios, Script# provides a number of APIs that can be used to build Sidebar
gadgets such as the Gadget API itself, RSS feeds APIs and the File System APIs. The feature set of these
APIs are described in the Script# Framework section.
Script# is an evolving project as presented in the Roadmap section. Please do send feedback and
suggestions, so they may be incorporated into the overall roadmap and future versions. The
introductory blog post is at http://www.nikhilk.net/ScriptSharpIntro.aspx. The Script# project page is
located at http://projects.nikhilk.net/Projects/ScriptSharp.aspx.
Script# introduces the concept of a Scriptlet, which can be thought of as the equivalent to the
“main” method of a regular client application. The runtime capability is provided by the Script#
Framework, which can be used in a vanilla html page. However, this is further simplified by its
server control counterpart, <ssfx:Scriptlet> which has a dependency on ASP.NET 2.0. This
control also provides a design-time experience including C# editing of the code-behind.
A regular C# Class Library project is used along with added Script# build steps to produce both
release and debug flavors of script files in addition to the regular .NET assembly. The resulting
script files can be packaged into server controls, or imported into pages directly. The original
.NET assemblies can be used as references for other class library projects, or references within
Scriptlet controls.
Script# Gadget.
A Script# Gadget is a special type of class library. Gadgets are essentially HTML pages with their
functionality and behavior implemented in script, much like a regular Web page. The key
differentiator is that a Gadget project refers to the Gadget API assembly, and implements
specific classes representing the different parts of the gadget: the main UI, the settings page etc.
The functionality of the compiler is almost identical. A few compiler features have been
disabled, and various APIs from core types have been removed as they are not supported by the
Microsoft ASP.NET AJAX runtime. The Script# framework is supported alongside the ASP.NET
AJAX runtime; however this allows you to use the Script# development methodology and
compiler even if you want to constrain your dependencies to the ASP.NET AJAX runtime.
The usage of the ASP.NET AJAX mode and its limitations are described in the section on Using
Script# with Microsoft ASP.NET AJAX.
The next section provides a Script# 101 overview that describes using scriptlets and building script
class libraries.
Script# 101
This section walks you through a HelloWorld-like scenario to demonstrate how you can implement
client-side browser-based Web applications and reusable components using Script# and Visual Studio.
This walkthrough assumes you have installed Script#. While the walkthrough is described using Visual
Studio, the steps can be adapted to Visual C# Express and Visual Web Developer just as well.
The resulting Web site structure looks like the following (as shown in the screenshot of the solution
explorer below) with Script# assemblies present in the Bin\Script folder and the corresponding debug
and release script files within the App_Scripts folder.
The content in bold below was added to the default page created from the Web site template to provide
a user interface to implement the Hello World scenario.
1
This walkthrough is based on server controls. However, it is certainly possible to use Script# without a
dependency on ASP.NET or ASP.NET server controls.
<body>
<form id="form1" runat="server">
<div>
<label>Enter your Name:</label>
<input type="text" id="nameTextBox" />
<button type="button" id=”okButton”>OK</button>
<hr />
<label id="greetingLabel"></label>
</div>
</form>
<ssfx:Scriptlet runat="server" ID="scriptlet">
<References>
<ssfx:AssemblyReference Name="sscorlib" />
<ssfx:AssemblyReference Name="ssfx.Core" />
</References>
<Code>
using System;
using ScriptFX;
The following is a screenshot of the page inside the IDE when you switch to design view, select the
Scriptlet control, and choose to show its associated task panel.
The Scriptlet server control provides a design-time experience to allow you to edit the C# code-behind,
add script and assembly references etc. in much the same way as you would for a regular C# client
application. Select “Edit C# Code” from the Scriptlet’s associated task panel. The screenshot below
illustrates the C# code editing experience provided by the server control designer including color coding,
intellisense, general text editor features such as change tracking, line numbers etc.
Here is the code you need to author within the Scriptlet control. As you can see it is regular C# code.
using System;
using System.DHTML;
using ScriptFX;
okButton.AttachEvent("onclick", _clickHandler);
}
_clickHandler = null;
}
}
Essentially execution starts in the Main method of your scriptlet. The code creates an instance of the
MyScriptlet class which then uses the DOM to find the <button> with id=”okButton” in the page. It
creates a delegate to the button click event handler and associates that with the button.
The click handler finds the <input> with id=”nameTextBox” and the <label> with id=”greetingLabel” to
extract the text entered by the user, and to display a formatted greeting in the page.
The MyScriptlet instance implements the IDisposable interface, and performs cleanup, namely
disassociates the event handler from the button. This is automatically called by Script# when the page is
being unloaded.
The code here uses the DHTML DOM directly. Script# also provides higher level abstractions that
simplify UI programming, but the DOM APIs provide sufficient functionality to implement this Hello
World scenario.
Essentially at runtime, the C# code was compiled against the set of referenced assemblies and imported
namespaces, and the equivalent JavaScript was generated for your class. In addition the Scriptlet control
also generates some JavaScript to load the scripts corresponding to assemblies you referenced, and start
your code once those scripts have been loaded.
If you are curious about the code that was generated, you can View Source in your browser. Here is the
generated script:
////////////////////////////////////////////////////////////////////////////////
// Scriptlet.MyScriptlet
ScriptFX.Application.Current.run(Scriptlet.MyScriptlet);
}
ScriptHost.initialize([
'App_Scripts/ssfx.Core.js'
]);
As you will notice, the generated script code looks similar to the originating C# code. This is intentional.
The Scriptlet control allows you to change code generation settings to generate release mode code that
is minimized to reduce the size of the script.
The Scriptlet control also supports the scenario where the C# code has been precompiled.
Finally, you can use the scriptlet model without necessarily using the Scriptlet server control or ASP.NET
(for example, in a vanilla HTML page) by precompiling the C# code, and using some boilerplate template
that mimic the bootstrapping code generated by the Scriptlet server control.
are preserved. Even though you are not stepping through the original code in the debugger, this enables
the debugging experience to still be usable.
Open a new instance of Visual Studio. Once the browser is running, you can attach to the browser
(iexplorer.exe) using the Tools | Attach to Process menu. When you attach to the browser make sure
you pick Script as the type of debugging you’d like to perform (instead of Native or Managed).
Open the Script Explorer tool window in Visual Studio, from the Debug | Windows menu. This shows all
executing scripts. You can open any script file and place breakpoints.
For the purposes of experimentation, place the breakpoint in Default.aspx within the
Scriptlet_MyScriptlet$_onOKButtonClick function. This is the event handler for the button.
Now click the button in the browser. The breakpoint should be hit, and you can now use the debugger,
for example, examine variables in the watch window.
NOTE: You need to ensure script debugging is enabled in Internet Explorer. It is not by default. In order
to enable it, open the Internet Options dialog via the Tools | Options menu, and open the Advanced tab.
In the Browsing category, ensure the following settings:
Debugging in Firefox
You can get the Firebug extension for Firefox which embeds a script debugger within the Firefox
browser.
The debugger has the equivalents of the Visual Studio debugger. The dropdown on the bottom in the
Debugger tag displays the list of script files similar to the Script Explorer. You can select Default.aspx
from that list. The content of the script file is shown. You can place a breakpoint within the same
method as before. When you click the button in the page, and the breakpoint is encountered, the right
hand side of the debugger window displays a watch window and a call stack dropdown.
First we’re going to add a Web handler (.ashx file) that will accept requests from the client, create a
greeting on the server, and send the resulting greeting back to the client. Right click on the Web site in
the solution explorer, and choose Add New Item, and pick the Generic Handler item and name the new
file Greeting.ashx.
using System;
using System.Web;
context.Response.ContentType = "text/plain";
context.Response.Write("Hello " + name + "! The current time on the server is " +
DateTime.Now);
}
return false;
}
}
}
Now we have an HTTP service we can call from the client. The requests to the service take the form of
Greeting.ashx?name=<text_entered_by_user>.
Now we need to write some code that uses XMLHttp to make these calls when the OK button is clicked
instead of generating the greeting text completely on the client.
Rather than hard-coding the URL format inside the code, lets pass it in as an argument into the Scriptlet.
This will introduce the Arguments feature of the Scriptlet control, and the corresponding
ScriptletArguments type in the C# code.
From the code editor window, click the Arguments button on the toolbar. This brings up an Argument
collection editor, where you can add an string literal argument named urlFormat that contains the
format of the URL requests to be used.
...
</ssfx:Scriptlet>
This argument is now available as a member of the ScriptletArguments instance passed into your
scriptlet. In fact, the ScriptletArguments class is a dynamically generated class, so the intellisense in the
code editor window also detects the addition of the urlFormat member of the arguments instance as
shown:
...
_request = null;
}
}
...
}
The Script# framework provides higher level HTTPRequest classes to simplify network programming.
XMLHttp was used here to minimize the concept count for this walkthrough. Furthermore, the Script#
framework provides various other APIs and objects to further increase your productivity as a script
developer, and to enable you to create richer Web applications.
Add a project named “Clock” to the solution, and choose Script# Class Library as the type of project.
The ClockBehavior is designed to be attached to a <label> element, and encapsulates a timer that ticks
once per second. On each tick, the behavior displays the current time in the associated label. Here is the
code for the ClockBehavior.
// ClockBehavior.cs
//
using System;
using System.DHTML;
using ScriptFX;
using ScriptFX.UI;
namespace Clock {
Window.ClearInterval(_intervalCookie);
}
base.Dispose();
}
If you are curious about what was generated you can choose to show all files in the project which
displays the hidden “bin” folder. Within the “Debug” folder you should see Clock.dll, Clock.xml, Clock.js
and Clock.debug.js.
Type.createNamespace('Clock');
////////////////////////////////////////////////////////////////////////////////
// Clock.ClockBehavior
Clock.ClockBehavior.createClass('Clock.ClockBehavior', ScriptFX.UI.Behavior);
Again the generated script looks similar to the initial authored C# code, and is structured for ease of
debugging.
Clock.js contains a release mode version of the same script in which whitespace has been stripped out
along with any comments. Furthermore, private and internal members have been minimized to reduce
script file size.
Type.createNamespace('Clock');Clock.ClockBehavior=function(domElement,id){Clock.ClockBehavior.con
structBase(this,[domElement,id]);this.$1_0=window.setInterval(Delegate.create(this,this.$1_1),100
0);}
Clock.ClockBehavior.prototype={$1_0:0,dispose:function(){if(this.$1_0){window.clearInterval(this.
$1_0);}Clock.ClockBehavior.callBase(this, 'dispose');},$1_1:function(){var $0=new
Date();this.get_domElement().innerHTML=$0.format('T');}}
Clock.ClockBehavior.createClass('Clock.ClockBehavior',ScriptFX.UI.Behavior);
<label id="clockLabel"></label>
Next we need to add a reference to the assembly we just authored, and add some code to instantiate an
instance of the ClockBehavior class.
Switch to design view, and select the Scriptlet control. Select the Edit References task of the Scriptlet
control’s task panel. The following dialog appears:
In order to reference the Clock assembly, we need to first import this into the Web site. Click Import and
select the Clock.dll file from the bin\Debug folder of the Clock project. The import process copies
Clock.dll and Clock.xml files into the Web site’s bin\Script folder. It also copies the Clock.debug.js and
Clock.js script files into the Web site’s App_Scripts folder. Once the import has taken place, click Add to
add the assembly to the list of referenced assemblies, and then OK, to save the changes to the
References collection of the Scriptlet.
The last part of this step is to write some code that uses the ClockBehavior class. Select the Edit Code
task from the scriptlet and add the code shown in bold.
using System;
using System.DHTML;
using ScriptFX;
using Clock;
...
...
}
The ClockBehavior code that you authored will now start displaying the current time in its associated
label element.
Summary
This walkthrough provided a very basic overview of Script#, and using it to implement application code-
behind in the form of scriptlets, as well as reusable components. It showed how you can use C# to
implement your client-side logic, without writing any more script, thereby deriving the benefits of
intellisense in the IDE, and compile-time checking of your code. You can use the Class Browser feature in
Visual Studio to browse the Script# assemblies as well as the custom script components you author,
which leads to increased discoverability of framework features beyond what can be achieved by looking
at script code directly.
There is a lot more you can do with Script# as well as additional options, and framework components
and building blocks to use. Hopefully this walkthrough provided enough context and a general idea of
starting your development with Script#!
The type system simulates key OOP constructs to provide structure to the generated code that mimics
the original C# source code. The OOP constructs include namespaces, classes, interfaces, enumerations,
and delegates. The implementation allows runtime inspection of types to retrieve type names, base
classes, checking for the existence of an interface implementation etc. The type system uses the
prototype feature of JavaScript to define classes.
The base class library is partly implemented by extending the prototype of key objects such as Array,
String, Number, Date etc. to provide an API that is consistent to the .NET equivalents, as well as API that
is useful in the scripting environment that is beyond that available in .NET. The base class library also
provides some new types such as StringBuilder, CultureInfo, Debug etc. and capabilities such as string
formatting that simplify various aspects of script authoring.
Script# Framework
The Script# Framework is a set of assemblies that provide a script-based application and programming
model. It is possible to implement an alternative framework on top of Script# without depending on the
Script# Framework, if you have unique requirements.
The ScriptFX.UI namespace provides the core infrastructure classes to associate script-based logic with
DOM elements. Specifically it introduces the notion of Controls and Behaviors. In addition it defines core
interface contracts for some UI elements. It provides a high-performance extensible animation core that
can be used to incorporate visual glitz into an application. In the future this will consist of other core UI
infrastructure and services such as templating and drag/drop.
2
Microsoft Silverlight APIs and assembly names often contain the “ag” prefix. Ag stems from the periodic table,
representing the Silver metal.
outside the Web browser to trusted applications such as gadgets. This API allows
subscribing/unsubscribing to RSS feeds, and access the data present in the user’s RSS feeds.
Naming Convention
You may have noticed a naming convention at play. Indeed there is a pattern. All the assemblies named
ssfx*.dll represent framework implementations in script (that were compiled using Script# of course). All
the other ss*.dll assemblies represent existing script APIs or scriptable APIs that have been imported.
Essentially the compiler is switched into Atlas-mode when the Atlas runtime (aacorlib.dll) is referenced
instead of the Script# runtime (sscorlib.dll). Only one runtime can be referenced when invoking the
compiler, and this provides a handy way to both switch modes, and at the same time provides the
specific APIs available for use with ASP.NET AJAX. In addition to aacorlib.dll
Along with aacorlib.dll, aaagctrl.dll provides the metadata to program against Microsoft Silverlight when
using ASP.NET AJAX. None of the functionality implemented in any of the ss*.dll assemblies can be used
in this mode, as all the ss*.dll assemblies reference sscorlib.dll.
1. No support for foreach over arrays – In Script# arrays are extended to implement IEnumerable,
and they are not in ASP.NET AJAX. Hence foreach over plain arrays does not work. The work
around is to use a regular for loop.
2. No support for auto-generated event accessors. Auto-generated event accessors require the
existence of a Delegate class with Delegate.Combine/Remove semantics, which are not provided
by ASP.NET AJAX. The workaround is to explicitly implement the add/remove accessors for
events in your code, rather than have the compiler generate it.
3. Lack of Array, String, Math etc. extensions – ASP.NET AJAX does not provide the full set of
extensions that are provided by Script# over the core JavaScript objects. Furthermore, in
ASP.NET AJAX, the extensions to the Array object are provided as static methods on the Array
type, rather than instance methods on Array instances. These differences manifest themselves
3
Atlas was the codename for ASP.NET AJAX.
by virtue of the core types in aacorlib.dll having a reduced or different APIs than their
counterparts in sscorlib.dll which represents the Script# runtime.
A type that represents a native object or existing script and simply exists to provide signature
information for APIs that can be used application types is marked as such by applying the Imported
metadata attribute. This allows other code to reference the type, but indicates to the Script# compiler,
that the type does not contain any C# source that needs to be compiled into script.
namespace System.WindowsMediaPlayer {
private MediaPlayerControls() {
// Private to disallow creation
}
[IgnoreNamespace]
[Imported]
public sealed class MediaPlayer : DOMElement {
// This particular class derives from DOMElement as media player is
// represented by an <object> tag.
4
Prior builds of Script# had a concept called “System Assemblies”. Such assemblies only contained metadata, and
no implementation. With newer builds of Script# (starting with 0.3.0.0), there is no longer a special type of
assembly. Instead metadata definitions can be included alongside types that do contain C# implementation that
gets compiled into script as described in this section.
private MediaPlayer() {
// Private to disallow creation
// Application code can use Document.GetElementById and cast
// the resulting element into a MediaPlayer instance to
// program against a media player instance on the page.
}
[IntrinsicProperty]
public MediaPlayerControls Controls {
// Notice the use of the IntrinsicProperty attribute. This
// ensures the compiler does not add the prefix get_ in calls
// to this property.
get { return null; }
}
[IntrinsicProperty]
public string URL {
get { return null; }
set { }
}
}
}
The object model created in the snippet above is representative of the type of object model needed to
create a page shown in the media player sample at
http://msdn.microsoft.com/library/default.asp?url=/library/en-
us/wmplay10/mmp_sdk/usingtheplayercontrolinawebpage.asp.
Once the above wrapper has been created, the following sample C# code can be written to consume it.
Since the MediaPlayer was written to derive from DOMElement, Document.CreateElement can be used
to create an ActiveX <object> tag, and the result can be cast into MediaPlayer. Thereafter you can use
the strongly typed OM on your class. This works because the casts only exist to enable the C# code to
compile. In script, the casts simply become no-ops.
using System;
using System.WindowsMediaPlayer;
namespace MyApp {
public PlayerApplication() {
_player = (MediaPlayer)Document.CreateElement(„object‟);
// Set other properties of the <object> tag
Document.Body.AppendChild(_player);
}
Note that the above approach can also be used for plugin objects added to pages using the <embed> tag
that is required in browsers other than Internet Explorer.
For ActiveX COM objects that aren’t inserted into the DOM, and are instead instantiated by calling new
ActiveXObject (allowed on Internet Explorer), you could define the C# wrapper class by deriving from
Object directly. In addition you’ll need to provide an implicit type conversion operator (operator
declarations are only allowed on metadata wrapper classes) from the ActiveXObject type, so that you
can successfully cast the resulting ActiveXObject into your object for use in C# code. The following
example defines metadata for the FileSystemObject.
namespace System.FileSystem {
[IgnoreNamespace]
[Imported]
public sealed class FileSystemObject {
private FileSystemObject() {
// Private to disallow direct creation. App code should use new ActiveXObject
// to create instances.
}
using System;
using System.FileSystem;
namespace MyApp {
public SampleApp() {
FileSystemObject fso = new ActiveXObject(“Scripting.FileSystemObject”);
}
}
}
For example, Virtual Earth can be consumed by importing the scripts at described at
http://dev.live.com/virtualearth/sdk/. In order to consume them from C#, a system assembly can
provide metadata for those APIs to C# code.
namespace System.VirtualEarth {
[IgnoreNamespace]
[Imported]
public sealed class VEMap {
[PreserveCase]
public void Pan(int deltaX, int deltaY) {
// Notice the use of the PreserveCase attribute. Unlike most
// scripting APIs, Virtual Earth uses pascal-cased names. This
// attribute suppresses conversion to camel-case names that is
// otherwise performed by the Script# compiler.
}
}
}
C# Compiler Generated
(csc.exe) Assembly Associated
Referenced (.dll) Script
Assemblies
(.js)
(.dll)
Script# works by converting C# source directly into JavaScript. In order to do so, it parses your C# code
like a real C# compiler. In addition to your .cs source files, it consumes a set of reference assemblies that
contain metadata about namespaces and types you are importing. The assumption is that these
assemblies have corresponding JavaScript files you will include into your deployed Web application,
along with your generated script code. In addition to the Script# compiler, you can also run the regular
C# compiler to validate the C# code and to generate an assembly that can be used as a reference in a
future project. In fact, the Script# compiler assumes that you will compile your code through the C#
compiler to ensure it is valid C# code.
When authoring code to be compiled into JavaScript it is important to reference the sscorlib.dll instead
of the regular mscorlib.dll that C# projects ordinarily do. sscorlib.dll provides the definition of key .NET
types such as System.Object, primitive types, and other core BCL types. A C# project can avoid
depending on mscorlib.dll using the /nostdlib option on the command line call to csc.exe and by setting
the NoStdLib property to True in the .csproj project file. The Script# install provides a project template
with the right project settings.
The Script# compiler and the Script# core runtime are closely coupled to one another. The compiler
compiles the C# code for a target type system and base class library which is defined by the Script# core
runtime.
The core runtime is provided in the form of sscorlib.dll which must be referenced by C# projects. Its
equivalent script, sscorlib.js must be referenced by Web applications. C# projects that need to be
translated to script should not reference mscorlib.dll. Instead they should reference sscorlib.dll, which
provides the equivalent for key types in the System namespace such as Object, Int32, String, Array, Type
etc. tuned for what is available at runtime in script. The associated script file extends the core set of
JavaScript types such as String, Number, Function etc. so that they provide APIs that model what the C#
or .NET programmer would expect.
In addition to sscorlib.dll, the Script# system also contains other assemblies such as sswpfe.dll. The latter
provides the metadata necessary to program against the WPF/E browser plugin which enables
programming against the scriptable media and vector graphics capabilities offered by the plugin.
(ssfx.UI.Forms.dll), an implementation of cross-domain Ajax using JSON, JSONP and script elements
(ssfx.XDAjax.dll) and Reflection (ssfx.Reflection.dll).
Each assembly is associated with a JavaScript file. The assemblies are used at compilation time. The
JavaScript files are sent down to the browser and used at runtime.
The compiler and the core runtime are however completely decoupled from the Script# framework. As a
result, it is entirely possible to use Script# without buying into the rest of the framework. This is
especially useful if you have an alternative framework design you’d like to implement, or have unique
requirements.
sscorlib: This assembly is the native script runtime of choice that is specifically designed for Script#. It
provides a type system, BCL-like extensions to native script objects, as well as runtime APIs to support
various compiler features. This enables the best C# development experience, and associated framework
APIs.
aacorlib: This assembly is a trimmed down version of sscorlib that can be used to target the Microsoft
ASP.NET Ajax runtime. It is a subset of sscorlib. Some compiler features are disabled when using aacorlib
as the runtime, since Microsoft ASP.NET Ajax provides a subset of the functionality available with
sscorlib.
Using Script#
The Script# compiler can be from the command-line either directly by running ssc.exe or indirectly by
building a .csproj using msbuild. In the latter case, the .csproj includes a reference to the Script# msbuild
.targets file (nStuff.ScriptSharp.targets), which includes references to a Script# msbuild task that is
responsible for invoking the Script# compiler programmatically.
It is recommended that you use the msbuild approach rather than using ssc.exe directly, as this provides
the full benefits of a C# project in the Visual Studio IDE.
Component developers are encouraged to distribute the generated script files, as well as the .NET
assembly and the associated doc-comment file. The .NET assembly provides metadata that can be
included as a reference, so users can write and compile their applications and components in Script#.
The XML doc-comments are used by the code editor engine in Visual Studio to enhance the intellisense
experience.
The generated script code can be referenced by hand-coded JavaScript, from other components
compiled using Script#, or included into ASP.NET server controls in order to implement their client-side
functionality. Script# can be used in all of these scenarios. This model of using Script# offers the
maximum flexibility since the generated script can be used in any manner. In particular it can be used to
create frameworks, as well as redistributable components that can then plug into those frameworks.
An assembly meant for use with Script# needs to have a the ScriptAssembly metadata attribute. Script
components and libraries should contain the following metadata:
using System;
[assembly: ScriptAssembly]
The Script# install provides a Script# Class Library project template that can be used to start developing
your components and libraries. The project includes a reference to sscorlib.dll and sets the NoStdLib
property to true to automatically avoid including a reference to mscorlib.dll. You can add references to
other Script# assemblies (both the ones the ship with Script#, or custom ones you’ve developed or
acquired) via the standard Add Reference dialog in Visual Studio. The template also includes the
assembly metadata attribute.
The Script# Framework is itself written in C# and compiled into a set of assemblies (ssfx.*.dll) using the
C# compiler and the associated set of script files (ssfx.*.js and ssfx.*.debug.js) using the Script# compiler.
Scriptlets
Scriptlets are the equivalent of executable applications. They are used to implement code-behind for a
Web page. Unlike components and script libraries, scriptlets are usually specific to a particular page, and
often work directly against the HTML elements present on the particular page they are associated with.
In concrete programmatic terms, a Scriptlet is a class that has a public static Main method. The signature
of a Scriptlet is slightly different. Rather than taking in an array of string arguments as a parameter, a
Scriptlet enables more advanced scenarios by accepting either a Dictionary of parameters, or an
instance of ScriptletArguments which is essentially a dictionary, but offers strong typing.
While a Scriptlet can be easily used in any HTML page, it is especially geared toward ASP.NET scenarios
where a Scriptlet server control allows you to implement your client-side code-behind in C# that is
converted to JavaScript dynamically, as well as provide a number of other facilities.
...
</Code>
</ssfx:Scriptlet>
The Scriptlet server control offers a design-time experience that enables editing the C #code with
intellisense and other aspects of the regular C #code editor, as well as the ability to compile and check
the code for errors before running the page.
The Scriptlet control converts your code to script dynamically at runtime. Its PrecompiledScriptlet
property can be set instead of specifying the code inline.
The scriptlet also generates some boilerplate code to bootstrap your code by loading in scripts
corresponding to the references listed in the References collection. In addition it passes an object
containing argument name/value pairs into the Main method of your code.
Scriptlets can be included in any HTML page manually. They can be precompiled into a script assembly
and the corresponding generated script can be included into the page. The generated boilerplate
bootstrapping script can be included manually into the page.
Limitations
C# Limitations
Script# is not intended to take an arbitrary existing C# application, and convert it to script to run within
the browser. It does not attempt to provide a script implementation for the full .NET framework (eg.
things like Windows Forms or the entire BCL). Doing so would not be practical or scale to the runtime
scripting environment. Script# targets a subset of the C# language as implemented in .NET Framework
2.0. The idea is that Script# is very much about script development, but in a manner that benefits from
an overall better tooling and authoring support.
All types must belong to a namespace. Nested types are not allowed.
Nested namespace declarations are not allowed. Instead you must declare the whole
namespace in one location.
The “System” namespace can only be used for imported types representing native scriptable
objects or existing script types.
The set of reserved words that cannot be used in Script# include not only C# reserved words,
but also JavaScript’s reserved keywords.
Struct types may have just a constructor and some fields. Methods and properties are
disallowed.
Pointer types are disallowed.
Method and constructor overloads are not supported except in imported types.
Destructors, operators and object conversion are not supported.
Enumeration fields must have an explicit value.
Some of these limitations listed above do not apply to creating System assemblies. System assemblies
were covered in the conceptual overview, and are covered in more depth later on.
In addition there are a known set of limitations in the current implementation that will hopefully be
supported in future builds:
You cannot specify namespaced-qualified type names either. As a workaround you can use
aliases (eg. using Foo = SomeNamespace.SomeType;)
Generics
Support for ref, out and params modifiers on parameters
Miscellaneous others (to be documented)
JavaScript Limitations
Script# provides support for the majority of JavaScript constructs needed to write real world
applications and frameworks. It does however have some limitations, and some small differences in the
authoring model as a result of being grounded in C# and OOP.
generator makes use of “$” in generated identifier names to ensure they do not conflict with
your own identifiers.
As you’ll see the limitations have minimal impact. The limitations should not prevent you from
implementing any real Ajax scenarios, or from leveraging the full capabilities of the DOM.
However, global methods are not permitted in C#. Therefore, this functionality is exposed to C#
developers via the Script.Eval method instead. Script.Eval is however not a runtime abstraction. Instead
the compiler transforms this into the native eval method in generated script.
// C#
string code = ...;
object result = Script.Eval(code);
// Generated Script
var code = ...;
var result = eval(code);
One of the key uses of eval is to parse JSON literals as part of deserialization. The Script.Eval method can
be used here as shown.
// C#
object data = Script.Eval(“[ { name: „abc‟, value: 123 } ]”);
// C#
Script.Alert(msg);
// Generated Script
alert(msg);
5
If there are other interesting script scenarios not covered in this document, please do send feedback.
Script# also introduces the notion of properties which are implemented via get/set accessor methods,
and the notion of events which are implemented via add/remove accessor methods. The late-bound
access extends to these higher level concepts as well.
As shown in the examples, you can use late-bound access where the member name is a constant at
compile time, or is a variable. Both models work, and generate the minimal script making full use of
script’s dynamic nature.
// C#
object o = ...;
string fieldName = ...;
object value = Type.GetField(o, “aaa”);
Type.SetField(o, “aaa”, value);
Type.SetField(o, fieldName, value);
// Generated Script
var o = ...;
var fieldName = ...;
var value = o.aaa;
o.aaa = value;
o[fieldName] = value;
// C#
object o = ...;
string methodName = ...;
object result = Type.InvokeMethod(o, “doFoo”, param1, param2);
Type.InvokeMethod(o, methodName, param1);
// Generated Script
var o = ...;
var result = o.doFoo(param1, param2);
o[methodName](param1);
// C#
object o = ...;
string propName = ...;
object value = Type.GetProperty(o, “foo”);
Type.SetProperty(o, “foo”, value);
Type.SetProperty(o, propName, value);
// Generated Script
var o = ...;
var propName = ...;
var value = o.get_foo();
o.set_foo(value);
o[„set_‟ + propName](value);
// C#
object o = ...;
Type.DeleteField(o, “xyz”);
// Generated Script
var o = ...;
delete o.xyz;
// C#
Dictionary d = ...;
foreach (DictionaryEntry entry in d) {
// Use entry.Key and entry.Value
}
// Generated Script
for (var $key in d) {
var entry = { key: $key, value: d[$key] };
}
Script in fact allows you to enumerate the members of any object, and not just plain JavaScript objects.
In order to support this scenario, Script# allows you to create a Dictionary from any object in your C#
code (this simply becomes a no-op in generated script) which you can then enumerate as described
above.
// C#
MyClass c = ...;
foreach (DictionaryEntry entry in Dictionary.GetDictionary(c)) {
}
// Generated Script
var c = ...;
for (var $key in c) {
var entry = { key: $key, value: c[$key] };
}
// C#
object o = ...;
if (Type.GetScriptType(o) == “undefined”) { ... }
// Generated Script
var o = ...;
if (typeof(o) == „undefined‟) { ... }
You can create a static class and annotate the class with the GlobalMembers metadata attribute. All
methods and properties of this class are promoted as top-level global members. Such a class may not
contain fields, or events.
// C#
[GlobalMethods]
public static class PageImplementation {
// Generated Script
function onBodyLoad() {
}
// C#
object result = Type.InvokeMethod(null, “doFoo”, param1, param2);
// Generated Script
var result = doFoo(param1, param2);
// C#
public delegate void XyzDelegate(int i);
DoStuff(o, delegate(int i) {
_data = localData + i + MyClass.GlobalData;
});
}
// Generated Script
MyClass = function() {
}
MyClass.prototype = {
_data: 0,
myMethod: function(o) {
var localData = 0;
nStuff.ScriptSharp.Tests.MyClass.doStuff(o,
new Delegate(this, function(i) {
this._data = localData + i + MyClass.GlobalData;
}));
},
doStuff: function(o, d) {
// Some code, including code that invokes the delegate passed in
}
}
MyClass.createClass('MyClass');
Such objects are modeled via sealed classes with the [Record] metadata attribute in C# as shown below:
// C#
namespace UI {
[Record]
public sealed class Point {
public int x;
public int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
}
}
// Generated Script
Type.createNamespace(„UI‟);
UI.$create_Point = function(x, y) {
var $o = { };
$o.x = x;
$o.y = y;
return $o;
}
As you can see the Point object instantiated is just a plain-script object. In essence a plain-script object is
essentially equivalent to an associative collection of name/value pairs, aka, a Dictionary.
One interesting scenario where plain script objects come into play is objects deserialized from a JSON
string. However, deserialized Dictionaries aren’t the friendliest thing to program against, esp. in a
strongly typed language such as C#, as will be evident from the following example. You can use records
to define a shape/type structure to enable friendly programming against raw data.
// C#
// Without Structs
string data = „{ x: 10, y: 100 }‟;
Dictionary d = (Dictionary)ScriptFX.JSON.Deserialize(data);
int x = (int)d[“x”];
// With Structs
Point p = (Point)ScriptFX.JSON.Deserialize(data);
int x = p.x;
The Dictionary object supports creation of an object which you can add fields to. It also provides a
special constructor that takes a sequence of name/value pairs to create an object literal in script.
// C#
Dictionary d1 = new Dictionary();
d1[“abc”] = 123;
d1[“xyz”] = true;
d1[“foo”] = “bar”;
// Generated Script
var d1 = {};
d1[„abc‟] = 123;
d1[„xyz‟] = true;
d1[„foo‟] = „bar‟
// C#
void DoSomething(string o) {
if (Script.IsNullOrUndefined(o)) {
return “”;
}
}
// Generated Script
function DoSomething(o) {
// This test equates to:
// if ((o === null) || (o === undefined))
if (isNullOrUndefined(o)) {
return “”;
}
}
// C#
namespace Sample.Components {
}
// Generated Script
Type.createNamespace(„Sample.Components‟);
// C#
namespace Demo {
public class Person {
private string _name;
public Person(string name) { ... }
6
Please send feedback if there are additional interesting C# constructs and patterns to cover.
get { ... }
}
}
}
// Generated Script
Demo.Person = function(name) {
...
}
Demo.Person.prototype = {
_name: null,
get_Name: function() { ... }
};
Demo.Person.createClass(„Demo.Person‟);
Note that various access modifiers like internal, public, sealed, abstract etc. do not manifest in the
generated script. These are enforced at the C# source level, by the C# compiler.
// C#
namespace Demo {
public class Employee : Person {
public Employee(string name) : base(name) { ... }
}
}
// Generated Script
Demo.Employee = function(name) {
Demo.Employee.initializeBase(this, [ name ]);
}
Demo.Employee.createClass(„Demo.Employee‟, Demo.Person);
// C#
public interface IDisposable {
void Dispose();
}
// Generated Script
var IDisposable = function() { }
IDisposable.createInterface(„IDisposable‟);
Note that the members of an interface are not defined in generated script. This is because an interface
in script is simply a marker on the type, that can be inspected at runtime. The full implementation of all
interface members is enforced at the C# source level, by the C# compiler.
// C#
public class Control : IDisposable {
}
// Generated Script
var Control = function() {
}
Control.createClass(„Control‟, null, IDisposable);
// C#
public class App {
private void OnClick(object sender, EventArgs e) { ... }
// Generated Script
App = function() {
}
App.prototype = {
_onClick: function(sender, e) { ... },
_main: function() {
Var handler = Delegate.create(this, this._onClick);
}
}
Once a delegate has been created, it can be passed off as an event handler or callback to another
component. That component can manage a list of delegates. This is done using the Delegate.Combine
and Delegate.Remove methods just like you’d expect.
// C#
public class Button {
private EventHandler _clickHandler;
// Generated Script
Button.prototype = {
_clickHandler: null,
add_click: function(value) {
this._clickHandler = Delegate.combine(this._clickHandler, value);
},
remove_click: function(value) {
this._clickHandler = Delegate.remove(this._clickHandler, value);
}
}
Finally, a delegate can be invoked, which invokes the sequence of delegates referenced by the delegate
instance. Each function is automatically instantiated using the instance of the object bound to a
particular delegate instance.
// C#
public class Button {
protected virtual void OnClick(EventArgs e) {
if (_clickHandler != null) {
_clickHandler(this, e);
}
}
}
// Generated Script
Button.prototype = {
onClick: function(e) {
if (this._clickHandler) {
this._clickHandler(this, e);
}
}
}
// C#
public enum Colors { Red = 0, Green = 1, Blue = 2 }
[Flags]
public enum Options { OptionA = 1, OptionB = 2, OptionC = 4 }
Colors c = Colors.Red;
Options o = Options.OptionA | Options.OptionB;
// Generated Script
var Colors = Type.createEnum(false, „Colors‟, { Red: 0, Green: 1, Blue: 2 });
var Options = Type.createEnum(true, „Options‟,
{ OptionA: 1, OptionB: 2, OptionC: 4 });
var c = Colors.Red;
Note that in debug and non-minimized builds enumeration fields are referenced explicitly. However in
the interest of saving script size, the compiler substitutes field references with their numeric values
when minimization is turned on. Consequently, all type information associated with enumeration values
is lost, and their runtime type is the same as that of an integer or number. Therefore it is recommended
that you do not retrieve the runtime type of enumeration field values. For example, the minimized
variant of the above code would be as follows:
var c = 0;
var o = 1 | 2;
// C#
namespace Demo {
public class Person {
private string _name;
public string Name {
get { return _name }
set { _name = value; }
}
}
}
Person p;
p.Name = “Nikhil Kothari”;
// Generated Script
Demo.Person = function() {
}
Demo.Person.prototype = {
_name: null,
get_name: function() { return this._name; }
set_name: function(value) { this._name = value; }
};
Demo.Person.createClass(„Demo.Person‟);
var p;
p.set_name(„Nikhil Kothari‟);
// C#
namespace Demo {
public class Set {
public object this[string name] {
get { ... }
set { ... }
}
}
}
Set s;
s[“abc”] = object1;
object o = s[“abc”];
// Generated Script
Demo.Set = function() {
}
Demo.Set.prototype = {
get_item: function(name) { ... }
set_item: function(name, value) { ... }
};
Demo.Set.createClass(„Demo.Set‟);
var s;
s.set_item(„abc‟, object1);
var o = s.get_item(„abc‟);
The accessors can either be explicitly defined, or they can be auto-generated by the compiler for a field
event as shown below.
// C#
public class Button {
public event EventHandler Click {
add { ... }
remove { ... }
}
}
public class Timer {
public event EventHandler Tick;
}
// Generated Script
Button.prototype = {
add_click: function(value) {
...
},
remove_click: function(value) {
...
}
}
Timer.prototype = {
__tick: null,
add_tick: function(value) {
// C#
public class Application {
private static Application Current;
static Application() {
Current = new Application();
}
// Generated Script
Application = function() {
}
Application.prototype = {
/* instance members */
}
Application.createClass(„Application‟);
/* Static Methods */
Application.getCurrent = function() {
return Application._current;
}
// C#
int[] items;
Dictionary table;
foreach (int i in items) {
// Consume i
}
foreach (DictionaryEntry entry in table) {
// Consume entry, i.e. entry.Key and entry.Value
}
// Generated Script
var items;
var table;
var $var1 = items.getEnumertor();
while ($var1.moveNext()) {
var i = $var1.get_current();
// Consume i
}
var $dict1 = table;
for (var $key in $dict1) {
var entry = { key: $key, value: $dict1[$key] };
// Consume entry, i.e. entry.key and entry.value
}
You can build support for enumeration into your own classes by implementing IEnumerable just like you
would in C#.
Anonymous delegates within static members do not have context to the member variables of the class,
vs. anonymous delegates defined within an instance member do have access to member variables.
// C#
public delegate void XyzDelegate(int i);
DoStuffStatic(o, delegate(int i) {
localData = i + MyClass.GlobalData;
});
}
DoStuffInstance(o, delegate(int i) {
_data = localData + i + MyClass.GlobalData;
});
}
// Generated Script
MyClass = function() {
}
MyClass.staticMethod = function(o) {
var localData = 0;
MyClass.doStuffStatic(o, new Delegate(null, function(i) {
localData = i + MyClass.GlobalData;
}));
}
MyClass.doStuffStatic = function(o, d) {
// Some code, including code that invokes the delegate passed in
}
MyClass.prototype = {
_data: 0,
instanceMethod: function(o) {
var localData = 0;
doStuffInstance(o, new Delegate(this, function(i) {
this._data = localData + i + MyClass.GlobalData;
}));
},
doStuffInstance: function(o, d) {
// Some code, including code that invokes the delegate passed in
}
}
MyClass.createClass('MyClass');
MyClass.GlobalData = 0;
The example shows the generation of nested functions, which use data local to the outer function or
scope via a script closure. The example also shows how the nested method is packaged as a delegate to
match C# semantics, and how the delegates are declared differently for anonymous methods within
static and instance methods.
Roadmap
Script# is an on-going project. There are some unfinished features, as well as various ideas for future
development. The current set of builds are considered the v1 generation of the product. The v-next
generation will commence once v1.0 of Script# will be completed.
If there is feedback about what you’re looking for in any of these areas, please do send comments and
suggestions.
Compiler
The key incomplete features include support for generics, parameter modifiers (ref, out, params), and
support for metadata generation into the resulting script. The plan for implementing this is in the v-next
generation of the product.
Other plans for the future include generating instrumented code to enable code coverage
measurement, profiling, static linking etc.
Script# Framework
This is where most of the work will take place in terms of both script libraries and system script
assemblies.
Some of the functionality in terms of new script framework functionality include support for data-
binding, completing the RPC stack, adding drag/drop support, adding a declarative markup model,
completing the animation stack, and providing other useful UI infrastructure components such as a
Calendar control and a RichTextBox control.
Feedback
All feedback on Script# as well as on this document, and other help content is welcome. The project
page at http://projects.nikhilk.net/projects/ScriptSharp.aspx includes discussion forums and a bug
tracking list. In order to send comments, questions, bug reports and other feedback offline, please send
it via my contact form at http://www.nikhilk.net/Contact.aspx.
Please make sure to include “Script#” in the subject. Also please include sufficient details about what
you are doing, what you are seeing, what you’d expect etc. (information that you think is relevant).
Please do not send source code as-is. It will be deleted without being looked at. You may include
relevant snippets, if they are relevant.
Version History
Version Date Notes
0.1.0.0 5/22/2006 Initial Release
0.1.1.0 6/01/2006 Following are the key changes based on dogfooding feedback, and some comments to initial blog
post:
Feature Work
Simplify scriptlet authoring (see the ScriptMain method)
Add Scriptlet arguments and references in <nStuff:Scriptlet>server control
Add EnableScriptDebugging property on Scriplet control. Selecting True sends down
unminimized framework scripts (sscorlib.js and ssfxcore.js); setting to false (the default)
sends down minimized scripts.
Support Application and Library projects in IDE and command-line compiler
Support for delete, typeof, >>>, and >>>= operators
Support for calling global methods (eval, parseInt, isNaN, alert, etc.)
Support for generating global functions
Support for enumerating members off any object
New methods on Array and String to improve programmability
Added documentation guide
Bug Fixes/Incremental Changs
Enum.ToString now works
Enums with non-integer based underlying values now work
Generate $() alias for calls to Document.GetElementById
Fix Exception class properties
Fix enumeration type definitions
Enable running sscorlib.js and ssfxcore.js in Mozilla with 0 warnings in strict mode
Include raw framework scripts in zip download
0.1.2.0 6/25/2006 Bug fixes from dogfooding feedback, comments, as well as some more feature work.
Feature Work
Add some APIs to strings (eg. Quote, Unquote, TrimStart, TrimEnd etc.)
Add ability to create types in a late-bound manner (Type.CreateInstance)
Enable usage of global methods as delegates when subscribing to events
Add XML DOM APIs as well as a good chunk of DHTML DOM APIs to sscorlib.
Add JSON class to ScriptFX.Core
Add basic networking stack to ScriptFX.Core.
Add ScriptFX.Reflection.dll for higher level reflection APIs.
Debug.Trace and Debug.Inspect use debugService when available. Web Development
Helper provides a debug service to the page.
Added basic JsonReader/JsonWriter for use in server-side code.
Bug Fixes
Assemblies involved in project to project references got locked by msbuild/VS preventing
further rebuilds – this is no longer the case.
Fix Dictionary.GetDictionary to return a string
Make +=, |= etc. operators work on properties.
Make structs work
Default values for fields of non-integer and non-boolean types
Fix event fields with auto-generated add/remove accessors actually work
Fix Enum and Delegate implementations in sscorlib
Fix retail build minimization bugs related to generated parameter names, and parameter
references in methods.
One big change worth calling out specifically: The type system in sscorlib.js has been changed to co-
exist with the Atlas type system; the two type systems will now not clobber and trample over each
other; types defined within one type system however will not be perceived as types in the other
type system.
0.1.3.0 7/15/2006 Bug fixes
New features
Added support for using alias stmts (using Foo = SomeNamespace.SomeType;) – these are
useful given namespace-qualified types are not supported in Script#.
Optimize away enum field references with actual runtime value in minimized release
builds to reduce script size, and derive some small perf benefit with reduced lookups
Enum creation syntax slightly modified for slightly improved performance
Flesh out more of mozilla compat layer, and DOM objects such as Style
Added InnerText and Children properties to DOMElement
Added CultureInfo, string formatting
Added string APIs such as PadLeft, PadRight, FromChar
Added the ability to create global names for delegate instances
(Delegate.CreateExport/DeleteExport)
Optimize usage of global functions as eventhandlers wrapped with a delegate so there is
no overhead of a delegate instance.
Add Browser detection logic and capability to Application class
Added support for cross-domain Ajax calls (ScriptFX.XDAjax.dll) using script elements and
callbacks (ala JSONP); Added BookmarkScriptlet sample working against del.icio.us’ APIs.
0.1.3.1 7/16/2006 Quick bug fix
Introduced DOMDocumentFragment in sscorlib.dll. Document.CreateDocumentFragment
now returns a DOMDocumentFragment instead of DOMDocument.
0.1.3.2 7/17/2006 More quick bug fixes
String and number formatting
Syntax errors in release flavor
0.1.4.0 7/23/2006 New Features
Support for conversion of C# anonymous delegates into nested script functions added
Support for browser-based CSS selectors (HTML.IE, HTML.IE7, HTML.Firefox etc.)
Added ScriptFX.UI.DOMEventList
Added Script.IsNull, IsNullOrUndefined, IsUndefined, to allow testing of local variables
against null or undefined
Added various APIs on String: IndexOfAny, LastIndexOfAny, Compare,
Added various APIs on Array: Sort(callback), Map, ForEach, Filter, Some, Every
CompareTo, Insert, Remove, Replace, HTMLEncode, HTMLDecode
Allow c#-style exception catch handlers without an explicit exception variable
Add HTTPRequest.SetContentAsForm to simplify simulating form post requests
Add basic OM for filters/transitions (Filters collection on DOMElement, VisualFilter and
related classes)
Add ActiveXObject class
Bug Fixes
Fixes to JSON serialization related to serializing 0, false, and empty string
0.1.4.1 8/3/2006 Simplified usage of Delegates with intrinsic script objects – no need for calling Delegate.Unwrap
anymore
APIs with Delegate parameter take a strongly typed delegate instead of untyped Function object.
Fixed Delegate.Remove
Replaced Function.Empty with Delegate.Null
0.1.5.0 8/30/2006 New Features/Changes
UI Framework start: Behavior, Control
AutoComplete, PopupBehavior
Initial bits of RESTful services and REST-based RPC stack
HTTPRequest.SetContentAsJSON, .CreateURI
Type system implementation now compatible with Microsoft ASP.NET Ajax. A type defined within
Script# now appears as a type defined in Atlas and vice versa. Furthermore it is possible to derive a
type in Script# from an Atlas type (assuming there is a system script assembly providing metadata
representing Atlas types).
Changes
Structs are no longer allowed. Instead use sealed classes annotated with [Record]. This
helps preserve script reference type semantics.
Fixes
Implement fixes to date encoding in JSON, as well as added support for Unicode
sequences.
Fixed scriptlets (broken in previous build)
0.2.2.0 1/8/2007 New
Added support for Virtual Earth (ssve4.dll) along with a basic sample (map.aspx)
Add fixed size arrays (new int[5])
Added ArrayList – for variable sized array scenarios
Added Dictionary.Count, Clear, Remove, ContainsKey
When building using msbuild, scripts can now be generated in a different directory
than c# assembly (using the ScriptPath property on the ScriptSharpTask) – this
enables placing C# projects under bin\Script in Web sites, and having scripts
generated into App_Scripts
Fixes:
Fixed Type.IsAssignableFrom to take in a Type and match .NET signature
Fixed casing of XML property on XMLNode
Fixed crash when trying to define operator methods (now raises an error as
expected)
0.2.3.0 2/12/2007 Assembly refactoring:
ssfx.UI.Core.dll is no more; its been merged into ssfx.UI.Core to simplify the assembly
layering (there is essentially one core now).
ssfx.UI.AutoComplete.dll is also no more; the functionality has been moved into
ssfx.UI.Forms.dll along with other core forms/controls features.
Changes/Updates:
Use of === and !== instead of == and != in generated script to match C# equality semantics
Added some metadata for some DOM classes (click, select, scrollIntoView, pixel???), some
compat APIs
Enable calling global methods using Type.InvokeMethod (using null as the first param)
New:
OverlayBehavior to create translucent overlays for modal dialog scenarios
ssgadgets.dll – metadata for Sidebar gadget APIs
ssfso.dll – metadata for Scripting File System Object
New Sidebar gadget project template
Fixes
Fixed the bug preventing passing delegates as ctor parameters
Fixed the bug preventing anonymous delegates from accessing variables defined within a
nested block inside a function
Return error codes from ssc.exe on failed compiles
Fixes to debug.inspect
0.2.3.2 2/13/2007 Fix some project template bugs in gadget and web site templates.
0.3.0.0 5/21/2007 Introduction of a Microsoft ASP.NET Ajax compatible mode, by referencing aacorlib.dll instead of
sscorlib.dll. This runs the compiler in reduced functionality mode such that the generated script only
depends on MicrosoftAjax.js.
Removed sswpfe.dll and added ssagctrl.dll. This is synchronized with the Microsoft Silverlight 1.0
Beta build. Also added is the aaagctrl.dll, which is the equivalent dll for that works on top of
aacorlib.dll.
Removed the distinction between regular and system assemblies. Any assembly can now contain a
mix of application types and imported types. Application types contain code that is converted to
script. Imported types are skipped from conversion, but can be used to represent native scriptable
APIs and existing script libraries.
Bug fixes:
Added support for ?? operator.
Fixed ^= operator.
Fixed usage of byte types.
Added support for properties named the same as a type.
Match C# semantics when searching for types by auto-including parent namespaces in
search order.
Fixed code generation of derived classes with static ctors
Fixed compiler parsing of floats and decimals on non US-english locales.
Fixed JSON parsing of long and float numbers
Fixed JSON serialization of double values
Fixed Sys.UI.DomEvent and ArrayList.RemoveAt to match ASP.NET Ajax signatures
0.4.1.0 9/6/2007 Quick incremental release to fix some key things:
Add Add/RemoveEventListener on Silverlight storyboard
Fix silverlight creation javascript bootstrapper
Add support for setting style on silverlight object/embed tag
Marked Sys.Debug method as [DebugConditional] so calls are stripped out in release
builds.
Queue class in ASP.NET Ajax mode now correctly resolves to Array
Fix access to static constants consumed in a derived class
New feature:
Support for indexer methods in code – compiled into Javascript as parameterized
property getters/setters.
0.4.2.0 9/11/2007 Minor Silverlight related bug fixes
OnResize/OnFullScreen events
Workaround for Silverlight bug resulting in invalid size property values during the onLoad
event.
Add some missing Silverlight 1.0 APIs
License
End User License Agreement for Script#
IT IS IMPORTANT THAT YOU CAREFULLY READ THIS NOTICE BEFORE INSTALLING THIS PRODUCT. BY INSTALLING, OR OTHERWISE USING
THIS SOFTWARE, YOU AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE AGREEMENT (THE “AGREEMENT”) WHICH CONSTITUTES A
LEGALLY BINDING CONTRACT BETWEEN THE LICENSOR (PROJECTS.NIKHILK.NET, HEREAFTER „WE‟, OR „US‟) AND THE LICENSEE (EITHER
AN INDIVIDUAL OR ENTITY, HEREAFTER „YOU‟).
THIS AGREEMENT
1.1 In this Agreement, the phrase “Software” means any version of the computer programs above and all
associated media, printed materials, “online” or electronic documentation and bundled software.
1.2 The Software is licensed, not sold, to You for use only under the terms of this Agreement. We reserve
any rights not expressly granted to You.
1.3 By installing, copying or otherwise using the Software, You agree to be bound by the terms of this
Agreement. If You do not agree to the terms of this Agreement You must not use the Software and must
immediately delete any and all copies of the Software in your procession.
GRANT OF LICENSE
2.1 We hereby grant You the following non-exclusive license to use the Software. The rights granted to
the Licensee are personal and non-transferable.
2.2 You may deploy the script files included with the product or those generated from using the product
to a Web server.
2.3 The following are the restrictions placed on the use of the Software. You may not:
- Remove the auto-generated header identifying Script# as the generator or tool used to produce
the script files you deploy into your application or component.
- Modify or adapt the Software into another program or product.
- Reverse engineer, disassemble or decompile, or make any attempt to discover the source code of
the Software through current or future available technologies.
- Redistribute, publish or deploy the Software on a standalone basis for others to copy without prior
acknowledgment from the Licensor.
- Copy or republish any portion of the documentation without prior acknowledgment from the
Licensor.
- Sell, re-license, sub-license, rent, lease any part of the Software or create derivative works.
- Use the Software to perform any unauthorized transfer of information or any illegal purpose.
2.4 We may from time to time create updated versions of the Software and may, at our option, make such
updates available to You.
2.5 The Software is pre-release software. We have the sole right to determine all aspects of future
updates, changes, and releases of the Software.
2.6 You permit the Software to connect and communicate with our servers to send version and usage
information for the purposes of improving the Software or sending information about available updates.
2.7 You agree to indemnify, hold harmless, and defend Us from and against any claims, allegations,
lawsuits, losses and costs (including attorney fees), that arise or result from the use, deployment or
distribution the software.
2.8 Any feedback including bug reports, feature suggestions or ideas provided by You to Us through any
communication channel are given to Us without any associated charge or implied patent or intellectual
rights. Thereafter, We have the full right to use, share and commercialize such feedback in any way and
for any purpose. You will not give feedback that is subject to a license that requires Us to license the
Software to third parties because of inclusion of such feedback. These rights survive this Agreement.
2.9 We do not provide any support services because the software is being made available to You in “as-is”
form.
2.10 We reserve the right to update the Agreement and the terms of the License with newer versions of
the Software.
WARRANTIES
4.1 We expressly disclaim any warranty for the Software. The Software and any associated materials are
provided “As Is” without warranty of any kind, either express or implied, including without limitation, the
implied warranties or merchantability, fitness for a particular purpose, or non-infringement. The entire
risk arising out of use or performance of the Software remains with You.
TERMINATION
5.1 This Agreement takes effect upon your use of the Software and remains effective until terminated. You
may terminate it at any time by destroying all copies of the Software in possession. It will also
automatically terminate if You fail to comply with any term or condition of this Agreement. You agree on
termination of this Agreement to destroy all copies of the Software in possession.
GENERAL TERMS
6.1 This written Agreement is the exclusive agreement between You and Us concerning the Software and
supersedes any prior agreement, communication, advertising or representation concerning the Software.
6.2 This Agreement may be modified only by a writing signed by You and Us.
6.3 In the event of litigation between You and Us concerning the Software, the prevailing party in the
litigation will be entitled to recover attorney fees and expenses from the other party.
6.4 This Agreement is governed by the laws of the State of Washington, USA. Irrespective of the country in
which the Software was acquired, the construction, validity and performance of the Agreement shall be
governed in all respects by English law. You agree to submit to exclusive jurisdiction of English courts.
6.5 If any provision of this Agreement is found to be invalid by any court having competent jurisdiction,
the invalidity of such provision shall not affect the validity of the remaining provisions of this Agreement,
which shall remain in full force and effect.
6.6 You agree that the Software will not be shipped, transferred or exported into any country or used in
any manner prohibited by the United States Export Administration Act or any other export laws,
restrictions or regulations.