At MIX11, I presented a session on Script# titled "Script#: Compiling C# to JavaScript" ... and I did a follow up blog post highlighting the key points from the presentation.
This blog post covers the Hello World demo, which will show how you can get started with script#, and deploy scripts authored using this approach. It doesn't go into more advanced topics, but hopefully it will also demonstrate a couple of key principles at play:
- Script# doesn't introduce some new and odd abstractions. You're still very much authoring script against the DOM and standard APIs, and existing knowledge of web development carries forward.
- The generated script is similar to script you might have authored directly, and can be distributed or deployed into a web application like any other script library, without a dependency on the compiler at runtime.
Script# enables you to leverage Visual Studio, C# syntax and existing familiar and robust set of .NET tools to scripting. In my MIX talk, I demonstrated some of this. In this post, you'll see some basic benefits such as intellisense and compile errors.
Creating a Script# Project
I am going to start with a solution that contains an ASP.NET Web Application (DemoWeb), which is going to contain my pages and scripts. I can of course deploy script#-generated scripts into any server application.
Next I am going to add a Script Library project, named DemoScript. This is a project template that gets installed into Visual Studio when you install script#. The project template creates a C# project, with a custom msbuild target that invokes the script# compiler msbuild task after the C# compiler is done with its part to produce an assembly.

Upon choosing to create a Script Library project, the Script# project template prompts for an optional deployment path. By default, the generated scripts are produced alongside the .dll assembly in the bin\Debug and bin\Release subfolders of the project. With a script# project, you can additionally choose to automatically deploy the generated scripts into a deployment folder, for example, into the /Content/Scripts folder within the web application, as I have chosen in the screenshot on the left.

The script# compiler compiles the DemoScript project to produce debug and release versions of scripts, along with mscorlib.js which provides functionality like a type system in script, and basic utility APIs.
I also went ahead and added a couple of files to the Web project - Hello.htm, a simple page which will consume the generated script, and HelloService.ashx, a simple service that produces a JSON response when the client issues a request to it.
Here is the HTML markup in Hello.htm:
<head>
<title>Hello Script#</title>
</head>
<body>
<h1>Hello World</h1>
<h2>Powered by Script#!</h2>
<hr />
<label>What is your name?</label><br /><br />
<input type="text" id="nameTextBox" />
<button type="button" id="helloButton">Hello</button>
</body>
</html>
And here is the implementation of the service in HelloService.ashx:
public class HelloService : IHttpHandler {
public void ProcessRequest(HttpContext context) {
string name = context.Request.QueryString["name"];
object result = new {
greeting = "Hello " + name + "! Its script# demo time...",
timestamp = DateTime.UtcNow.ToString()
};
JavaScriptSerializer serializer = new JavaScriptSerializer();
string json = serializer.Serialize(result);
context.Response.ContentType = "application/json";
context.Response.Write(json);
}
}
Authoring Script with Script#
With the solution and Web application setup work completed, and out of the way, we can now focus on using script# and authoring script.
The first step is to add a new Page class. You can think of a Page class as roughly equivalent to code-behind for a page.
This adds a class with the following template-based boiler plate code.
using System;
using System.Collections.Generic;
using System.Html;
using System.Runtime.CompilerServices;
namespace DemoScript {
[GlobalMethods]
internal static class HelloPage {
static HelloPage() {
// Add script that runs on startup as the script is loaded into
// the page
}
}
}
In script#, static constructors get generated as code that runs immediately as the script is loaded and parsed. You can author regular classes with regular instance methods as well to create script types and functions, but we don't need to go there for this first introduction post.
As you start authoring code, there are some interesting things to call out. The HTML DOM APIs have been defined in the System.Html namespace (within the Script.Web.dll assembly that is automatically referenced in your project). This provides strongly typed access to the DOM as well as intellisense, and build errors if you have typos, missing parameters etc. as shown in the following screenshots.
Here is the initial code written to locate the button element from the markup, and then bind an event handler to its "click" event:
Element helloButton = Document.GetElementById("helloButton");
helloButton.AddEventListener("click", delegate(ElementEvent e) {
}, false);
Now we'll fill out the event handler to retrieve the text from the input element and invoke the service hosted on the server, and display the generated greeting from the server.
Element helloButton = Document.GetElementById("helloButton");
helloButton.AddEventListener("click", delegate(ElementEvent e) {
InputElement nameTextBox = Document.GetElementById("nameTextBox").As<InputElement>();
XmlHttpRequest xhr = new XmlHttpRequest();
xhr.Open(HttpVerb.Get, "/HelloService.ashx?name=" + nameTextBox.Value.EncodeUriComponent());
xhr.OnReadyStateChange = delegate() {
if (xhr.ReadyState == ReadyState.Loaded) {
Dictionary<string, string> data =
Json.ParseData<Dictionary<string, string>>(xhr.ResponseText);
string greeting = String.Format("{0}\r\nGenerated on {1}...",
data["greeting"], data["timestamp"]);
Script.Alert(greeting);
}
};
xhr.Send();
}, false);
The key things to note here are this is very much like script you'd author directly - create an XMLHttpRequest instance, invoke a request, and process the response upon completion.
There are a few Script# specifics or benefits - notice the use of InputElement, which derives from Element (to add members like the Value property), and the use of enums like HttpVerb and ReadyState rather than literal values. These are present in the C# source code to improve readability and reduce possibility of errors, but effectively go away from generated script, and don't have runtime impact.
Here is the resulting script:
var helloButton = document.getElementById('helloButton');
helloButton.addEventListener('click', function(e) {
var nameTextBox = document.getElementById('nameTextBox');
var xhr = new XMLHttpRequest();
xhr.open('GET', '/HelloService.ashx?name=' + encodeURIComponent(nameTextBox.value));
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
var data = JSON.parse(xhr.responseText);
var greeting = String.format('{0}\r\nGenerated on {1}...', data.greeting, data.timestamp);
alert(greeting);
}
};
xhr.send();
}, false);
The release script minimizes whitespace, as well as identifiers for local variables, internal members, types etc. as shown (whitespace added back for readability):
var $0=document.getElementById('helloButton');
$0.addEventListener('click',function($p1_0){
var $1_0=document.getElementById('nameTextBox');
var $1_1=new XMLHttpRequest();
$1_1.open('GET','/HelloService.ashx?name='+encodeURIComponent($1_0.value));
$1_1.onreadystatechange=function(){
if ($1_1.readyState === 4) {
var $2_0 = JSON.parse($1_1.responseText);
var $2_1 = String.format('{0}\r\nGenerated on {1}...', $2_0.greeting, $2_0.timestamp);
alert($2_1);
}
};
$1_1.send();
}, false);
Deploying and Using the Compiled Scripts
The next step here is to add a reference to the generated script in the page. Script# provides a script loader that loads scripts asynchronously, manages dependencies and more, but again, for this introduction, I am going to use vanilla script tags, to keep things simple, and highlight the fact that the generated scripts in fact work like any other script - with no dependency on the script# compiler at runtime.
<script type="text/javascript" src="/Content/Scripts/mscorlib.debug.js"></script>
<script type="text/javascript" src="/Content/Scripts/DemoScript.debug.js"></script>
Working with JSON Data in C#
The HelloService implementation returns a JSON formatted object with two members: greeting and timestamp. I am using a Dictionary<string, string> type to work against this JSON-formatted data on the client.
However I might want to create a proxy type and work with the JSON data in a strongly typed manner from a C# code perspective, without changing what happens at runtime.
I can define a proxy class as follows:
[Imported]
public sealed class ServerResult : Record {
public string Greeting;
public string Timestamp;
}
Essentially a Record class tells the Script# compiler that the class represents a vanilla JavaScript object, and consequently is limited to public fields (that correspond to the members). A record class can also have a public constructor, but we don't need that functionality here, as the record is representing the data produced by parsing the JSON response from the server.
Additionally, the [Imported] metadata attribute instructs the compiler that it doesn't need to generate any script for it. Its simply there to represent the shape of the object created from the JSON response.
To use this class, I simply need to change the code that handles the response to the following:
ServerResult data =
Json.ParseData<ServerResult>(xhr.ResponseText);
string greeting = String.Format("{0}\r\nGenerated on {1}...",
data.Greeting, data.Timestamp);
Script.Alert(greeting);
Using jQuery
I'll do a follow up which covers jQuery in more depth (using jQuery and its Fluent API pattern for chaining calls, authoring jQuery plugins etc.) in the future, but I wanted to show how jQuery can be applied in this HelloWorld scenario.
The first thing I'll do is add a reference to Script.jQuery.dll, which contains all of the jQuery core APIs (updated to match jQuery 1.5.1, as of this writing), and then import the jQueryApi namespace.
Here is the equivalent functionality implemented using jQuery:
jQuery.OnDocumentReady(delegate() {
jQuery.Select("#helloButton").
Click(delegate(jQueryEvent e) {
string name = jQuery.Select("#nameTextBox").GetValue();
string url = "/HelloService.ashx?name=" + name.EncodeUriComponent();
jQuery.GetData<ServerResult>(url,
delegate(ServerResult data) {
string greeting = String.Format("{0}\r\nGenerated on {1}...",
data.Greeting, data.Timestamp);
Script.Alert(greeting);
});
});
});
As you can see, it uses familiar jQuery patterns - once the document is ready, select an element, bind to an event, get data using an ajax request, consume data and so on. The other thing you'll also see is how jQuery simplifies the code... script# with jQuery lives up to the jQuery experience you might have had in the past.
The resulting script is the following (again, similar to what you might have implemented directly):
$(function() {
$('#helloButton').click(function(e) {
var name = $('#nameTextBox').val();
var url = '/HelloService.ashx?name=' + encodeURIComponent(name);
$.get(url, function(data) {
var greeting = String.format('{0}\r\nGenerated on {1}...', data.greeting, data.timestamp);
alert(greeting);
});
});
});
Summary
You can download the sample code for this blog here, and open the project on your machine, once you've installed script#.
Hopefully this blog post provides an introduction to getting started with using script#, compiling your c# to produce script, and deploying and running that script within your web application. Hopefully it also underscores the fact that script# doesn't introduce abstractions, and that you're still very much coding the same APIs, the HTML DOM, jQuery, XMLHttpRequest etc. and that the resulting script is a reasonable representation of your original source code. Stay tuned for more script# related content. In the meantime you can also follow me on twitter and/or follow script# on twitter to stay up to date with announcements and updates.