Intro to Client-Server Mapping in ExoWeb

As a follow up to my Brief Introduction to ExoWeb, I would like to go into more detail about the communications between client and server.

The client interacts with the server in two basic ways.

  1. Pulling information: type and instance data.
  2. Pushing information: changes to the model and/or instructions to do something.

The first type, pulling information, is pretty straightforward. Type information doesn’t change (frequently) so it is actually cached on the client if possible. Querying for instance data is similar to querying a database. You request an object of a particular type with a particular id, but you can also include a set of paths that tell the services what additional related data you are interested in. The primary component of a query might look something like this.

{ from: "Person", id: "1", and: ["this.Additional.Properties.To.Load"] }

The second type, pushing information, gets a little more interesting. If you’re going to sync data between two disconnected systems there are two primary approaches that you might take. First, you could send simple data from point A to point B, manipulate it, then send it back from point B to point A in the same form. As you could imagine this can get pretty expensive and tedious. Of course, you might just send the portions of data that have changed to cut down on overhead. The bigger problem, I think, is that you don’t really know what has happened unless you do full graph comparisons. Another approach is to keep track of changes as they occur and send those back and forth. This is what ExoWeb does.

changes: [ { type: "ValueChange", instance: { id: "1", type: "Person" }, property: "FirstName", oldValue: "Rob", newValue: "Robert" }, ... } ]

The client can also raise events, for example “save”, a built-in event. In response, the server can send back additional changes to the model.

changes: [ { type: "Save", idChanges: [ { type: "Person", from: "?4", to: "644" } ] }, ... ]

The payload isn’t limited to data. It can also include conditions, for example, permissions, or invalid data conditions. More on that later.

This has been a very basic introduction to the way client-server communication works in ExoWeb. Look out for more updates in the future.

A Brief Introduction to ExoWeb

A while back I talked about the ExoWeb project and scripts that are now hosted on github. That post was a little vague because not much has been documented about what you can actually do with ExoWeb. That’s what I hope to do here.

First off, let me restate the purpose of ExoWeb as simply as I can. ExoWeb exists to bridge the gap between the client and server. You can think of it as a combination client-server mapper and model-view mapper.

Client Server Mapping

When I say that ExoWeb is a client-server mapper what I mean is that it handles mapping from an object model on the server to the client (and vice versa) in much the same way that an ORM maps from a database schema to an object model. The general idea is that you’re persisting objects and that you would like to be able to easily manipulate those objects in JavaScript code, without any extra work.

For example, say you have a C# class that is persisted to a database using your choice of ORM.

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string FullName
    {
        get
        {
            return FirstName + " " + LastName;
        }
    }
}

You would want to be able to write JavaScript code to modify this object like so (ignoring the details of the syntax [1]).

person.set_FirstName("Bob");

ExoWeb aims to let you do this with very little effort.

What are some of the things that you might want to do with the model?

  • Have the full name automatically reflect the fact that the first name is now “Bob”
  • Save these changes by simply calling a method
  • “Round trip” to the server to perform complex or sensitive operations
  • Display the person’s information in a view

…which leads us to the next primary area of functionality.

View Model Mapping

You have a model on the client, so now you want to display some information to the user and possibly accept input. What are some of the tools that you might want to have at your disposal?

  • Create regions in your form that correspond to lists in the model
  • Two-way binding of properties to inputs elements and form regions
  • Respond to changes and redraw parts of the form as needed
  • Attach behavior to the form such as clicking links, toggling regions, etc
  • Take advantage of model metadata like formats, allowed values, validation rules, etc
  • Allow for lazy loading of certain information when it is needed on the form

That’s a glance at the basic features that we want from ExoWeb. So, what does it actually look like?

Disclaimer: ExoWeb is under heavy development, so this stuff is always changing. Feedback is welcome.

Setting up a Page

First off we have to include the ExoWeb script(s). Take a look at the github repo to see what’s available. The “dist” folder contains 3 scripts: exoweb-msajax.js, exoweb-msajax-nojquery.js, and jquery.exoweb-msajax.js. For now we’ll just include exoweb-msajax.js. ExoWeb currently also requires jQuery (1.3 or 1.4) and the MsAjax client libraries (specifically, MicrosoftAjax.js and MicrosoftAjaxTemplates.js). These will be included in the repo in the near future.

Side note: ExoWeb currently uses the MsAjax client libraries, primarily for two purposes: observer and integrated template rendering. In the near future these dependencies should be isolated so that other implementations could be used. For example, better integration with jQuery is a personal goal of mine.

Now that we have the right scripts included we need to set up the page’s context. This tells ExoWeb what data to load and what to do before and after it is loaded. We do this by calling the $exoweb function. It accepts a JavaScript object with any of the following properties.

  • model: A JavaScript object that defines the data to load from the server.
  • types: An array of types to load. This is usually not needed since types are automatically loaded based on the “model” parameter.
  • init: A function that is invoked as soon as model or type data has been requested.
  • contextReady: A function that is invoked as soon as the model or type data has been loaded, but before the UI is rendered.
  • domReady: A function that is invoked after the UI has been rendered.

You can call $exoweb any number of times, and as an example our query might look something like this (please forgive the contrived example).

$exoweb({
    init: function() {
        ExoWeb.UI.Template.load("/path/to/template");
    },
    types: [
        {
            from: "CustomWidget",
            and: ["this.CustomInformation"]
        }
    ],
    model: {
        widget: {
            from: "Widget",
            id: "1",
            and: ["this.Type.DefaultPrice"]
        }
    },
    contextReady: function() {
        context.model.widget.doSomething();
    },
    domReady: function() {
        $(".widget input[type=button].save").click(function() {
            context.server.save(context.model.widget);
        });
    }
});

During init we want to load an external template file. I will talk more about this in the future, but for now I will say that ExoWeb allows you to bind parts of your form to a dynamic template that is selected based on the HTML element and the data that will be rendered. This allows you to break out reusable templates for common display scenarios, but it also allows your form to be dynamic in the sense that the markup can change automatically based on user input.

The types and model portions are what trigger requests to the server. This will load up all of the metadata that is needed, as well as the instance data for the instances and paths that you specify. When the context is ready it will have a model property that contains a property for each thing that you requested (in this case, the widget).

Context ready allows you to perform custom operations after all of your data is loaded. For example, if you have an add/edit page you can perform setup logic that may be needed only in the add scenario.

DOM ready is a good place to put any DOM manipulation code that is specific to your page and it’s data and templates. For general UI behavior I would recommend using jQuery to attach behavior as needed based on css selectors (a topic for another day). Notice here the use of the “server” object, which is found on the context. The server object allows you to save, round trip, raise events, and inspect the changes that have occurred.

Now, to display this on the form we might write something like this.

<div class="sys-template widget" sys:attach="dataview"
    dataview:data="{~ context.model.widget, source={{ window }} }">
    <h3>Editing <span>{binding Name}</span></h3>
    <div class="sys-template" sys:attach="dataview" dataview:data="{@ Type }">
        <label>Type:</label>
        <select class="sys-template" sys:value="{binding systemValue}"
            sys:attach="dataview" dataview:data="{binding options}">
            <option value="{binding systemValue}">{binding displayValue}
                </option>
        </select>
    </div>
    <div class="sys-template" sys:attach="dataview" dataview:data="{@ Price }">
        <label>Price:</label>
        <input type="text" sys:value="{binding displayValue}" />
    </div>
    <input type="button" class="save" value="Save" />
</div>

The form is not rendered until the “widget” object has been loaded. Also, notice the “@” extension that is used to incorporate metadata in the form. For a pick list it will give you the list of options for a particular property. Also, for other properties it allows you to automatically convert from and to a “system” or “display” format. In a nutshell, the “display” format is a human-readable form of the underlying data that also includes format conditions for things like email, phone number, etc, while the “system” format is not intended to be shown to a user but instead can be used to uniquely identify an object.

This has been a very brief introduction to ExoWeb. There is much more to talk about and you can expect follow up posts in the near future.

The Exo-suite (and client scripts on Github)

Off and on at work over the last year or so I have been working on an open-source project called ExoWeb, as well as supporting projects called ExoGraph and ExoRule. ExoWeb and ExoGraph are hosted on Codeplex, though they are somewhat stale at this point.

Before I go any farther I’ll give you (and future self) my take on the purpose of these projects.

ExoGraph

…is essentially an enabler.

From the codeplex site:

ExoGraph is a graph library that leverages type information to optimize graph operations and notifications. The library exposes type-level events for object initialization, property retrieval, property path changes, and custom domain events within a graph context.

This doesn’t sound very useful in and of itself, right? Well, it’s not supposed to be. It’s an enabler, remember? That’s where ExoWeb and ExoRule come in…

ExoRule

…is a rules framework that leverages ExoGraph. That is all for now.

ExoWeb

…is a JavaScript framework, basically. It also relies on a supporting server-side web request handler as well as a working ExoGraph implementation.

From the codeplex site, ExoWeb…

…aims to provide a rich JavaScript object model, intuitive UI code based on the fundamental languages of the web (HTML, CSS, and JavaScript), model- and UI-driven validation, and seamless synchronization of changes between client and server.

That may not be crystal-clear, but fortunately you can browse the source, which is what I really want to write about anyway.

The JavaScript source is now hosted on Github. If you take a look at the source on Codeplex you’ll notice that there are 8 script files: exoweb.js, exoweb.model.js, exoweb.mapper.js, exoweb.view.js, exoweb.ui.js, exoweb.mock.js, exoweb.jquery.js, and start.debug.js. The source on Github, however, has many more script files as well as specs (using jasmine) and a build process (using rake) that produces the scripts listed above. It is loosely modeled after the jquery source.

I have a few goals in hosting the project on Github.

  1. Isolate classes and related functions in order to make it easier to manage, illuminate code structure, improve architecture and design, and limit dependencies.
  2. Allow for (hopefully) isolated testing of individual classes and functions.
  3. Isolate the bulk of the code which is not dependent on any particular JavaScript library or server-side technology.
  4. Take advantage of github’s popularity in open source software collaboration, and…well, I just like Github.

At the time of this writing the project produces the destination scripts that more or less match the scripts in the original project (not the ones on codeplex, they’re old). Also, a few of the source files have corresponding specs that pass, using nodejs to run them.

Finally, in writing the build script, I got the chance to learn a little rake (ruby make), which I highly recommend.

One of my other goals is to create working ExoGraph/ExoWeb implementations for django and rails. The beginnings of the django implementation is currently hosted on Github as well.

arguments…callee…caller…

Originally posted May 3 2010

Recently I spent some time looking at generating a stack trace in JavaScript for the purpose of error reporting. There are plenty of existing projects out there that solve this problem, so I wouldn’t recommend rolling your own.

As a result of this I came across some odd behavior in JavaScript. The code I was working with takes advantage of the special “arguments” variable (the “array” of arguments passed to the current function), which has a special “callee” property (the function that was called), which also has a special “caller” property (the function that called this function). You can probably see how this would be tempting if you’re trying to construct a stack trace. Unfortunately, this information is attached to the function object rather than some sort of “function invocation” object. There are at least two cases where this makes constructing an accurate stack trace impossible.

  1. Function recursively calls itself.
    • Since the caller property is attached to the function itself there is no way of knowing (through this information alone) how many times the function was called.
  2. Function A calls function B, which then calls function A…
    • Even if there are terminating condition, the code that attempts to reconstruct the stack trace (using “callee” and “caller”) will not terminate. There is a good description of this behavior here.

I was primarily interested in scenario 2, since this can cause errors. To get around this you can detect that you have already encountered a given function and simply stop. Of course this means that you lose any information that follows, but at least you won’t hang the browser.

Conclusion: always check MDC :)

http://eriwen.com/javascript/stacktrace-update/

http://helephant.com/2007/05/diy-javascript-stack-trace/

http://bytes.com/topic/javascript/answers/470251-recursive-functions-arguments-callee-caller

http://msdn.microsoft.com/en-us/library/7t96kt3h

https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Objects/Function/caller

Web Service Syntax Error???

Originally posted April 7 2010

Ok, I’ll start this post off with some background. A couple of years ago I wrote a SOAP web service that manages printing for multiple users through a web application. Sounds familiar, right? Anyway, the client that interacts with the web service uses the Microsoft AJAX JavaScript framework (version 1). The web service is hosted on a different server and domain. However, since this is an internal application with a small number of users they were content to enable cross-domain data access and be done with it.

A few weeks ago one of my coworkers was revisiting the client portion, which just happened to be upgraded to the beta version of the AJAX JavaScript framework. He started to see a syntax error, which I determined was occurring when handling the web service response. I knew that the client framework supported JSONP in some form, and I also noticed an interesting “jsonp” query string argument in the web service call. Believe it or not, the client was trying to use JSONP, even though the web service response was XML! This obviously would result in a syntax error when trying to deserialize.

After looking over the JavaScript code I determined that the WebServiceProxy was using JSONP if either the protocol or host of the request was different than the current page. I now know in hindsight that the documentation (at least in code) of WebServiceProxy.invoke clearly states this. Luckily, the “enableJsonp” parameter can be set to false to override this behavior.

So, the bottom line is: if you’re accessing a web service across domains and you don’t want to use JSONP, you have to set the “enableJsonp” argument to false. Here’s the method signature and documentation…

WebServiceProxy.invoke(servicePath, methodName, useGet, params, onSuccess, onFailure, userContext, timeout, enableJsonp, jsonpCallbackParameter) {
/// <summary locid=”M:J#Sys.Net.WebServiceProxy.invoke”></summary>
/// <param name=”servicePath” type=”String”>Path to the webservice</param>
/// <param name=”methodName” type=”String” mayBeNull=”true” optional=”true”>Method to invoke</param>
/// <param name=”useGet” type=”Boolean” optional=”true” mayBeNull=”true”>Controls whether requests use HttpGet</param>
/// <param name=”params” mayBeNull=”true” optional=”true”>Method args.</param>
/// <param name=”onSuccess” type=”Function” mayBeNull=”true” optional=”true”>Success callback</param>
/// <param name=”onFailure” type=”Function” mayBeNull=”true” optional=”true”>Failure callback</param>
/// <param name=”userContext” mayBeNull=”true” optional=”true”>Success callback</param>
/// <param name=”timeout” type=”Number” optional=”true” mayBeNull=”true”>Timeout in milliseconds</param>
/// <param name=”enableJsonp” type=”Boolean” optional=”true” mayBeNull=”true”>Whether to use JSONP if the servicePath is for a different domain (default is true).</param>
/// <param name=”jsonpCallbackParameter” type=”String” optional=”true” mayBeNull=”true”>The name of the callback parameter for JSONP request (default is callback).</param>
/// <returns type=”Sys.Net.WebRequest” mayBeNull=”true”>Returns the request that was sent (null for JSONP requests).</returns>

MS AJAX and JSON Date Serialization

I’m making heavy use of Microsoft AJAX right now at work.  No, not the webforms controls, the JavaScript library.  That’ s a little better, right?

Anyway, one of the nice little features in MS AJAX is the ability to invoke a web service, passing in some arbitrary JavaScript object(s), and it just works!  Well, mostly of the time anyway.  Today I found out that you have to be careful with dates.  When I called a web service in this manner, and the object was a Date or contained a Date, the deserialized DateTime object on the server was off by several hours.

At this point you’re probably thinking, “I know what the problem is, you idiot!  It’s local time!”  Hopefully you’re more polite than that, but you would be right, of course.  Since JSON doesn’t account for dates, we’re forced to improvise.  Check out this link for a discussion of the JSON date format that the AJAX team decided on using.  You’ll notice that he mentions several time that the string format represents a UTC date & time.  In my own defense, I simply provided a Date object and the rest was supposed to be magic (as we developers are so fond of saying).  After all, the Date object does include time zone information.  Unfortunately, the serialization code doesn’t take that into account.

if (Date.isInstanceOfType(object)) {
stringBuilder.append(‘”\\/Date(‘).
append(object.getTime()).
append(‘)\\/”‘);
break;
}

Since the date was going to be converted to a string anyway I went ahead and did the conversion ahead of time.  Something like this…

var offset = obj.getTimezoneOffset() * 100 / 60;
var offsetText = offset >= 1000 ? offset.toPrecision(4) : “0″ +
offset.toPrecision(3);
return “/Date(” + (+obj).toString() + “-” + offsetText + “)/”;

There are, of course, other ways to do this.  You could convert the date to a UTC date and let the serialization code do its thing.  This was my first solution, but I scrapped it in favor of the code above since it’s more consistent with how the dates were formatted when sent from the server.  You could also parse out the offset from the date string with a regex, but that just didn’t feel right.

Moral of the story:  either make sure your dates are UTC or serialize with the offset yourself.  I could think of cases where both would be inconvenient or impractical.  Hopefully you don’t have to face that problem.

Tiny MCE Spellchecker Gotcha

In hindsight this should have been a lot easier…

If you’re not familiar with tinymce you should go check it out.  Its a solid rich text editor for the web, which can be easily initialized and manipulated via JavaScript.  And best of all, its free!

Today I ran into a problem with the spell checking feature.  I’ll go ahead and state up front:  this was NOT a problem with tinymce.  This was my own doing.  It seemed that, although the spell checker was able to report misspellings in the editor, when you clicked on a misspelled word the highlighting would disappear and no context menu was shown.  Strange…

First off, tinymce’s source code can be downloaded from their site (see “Deveopment package”), which made debugging really easy.  I noticed while inspecting the page using firebug that when I triggered spell checking the misspelled word(s) in the editor were wrapped in a span with a special class name.  I tracked down the spot in the code where the text was wrapped happened, and more importantly unwrapped, and then set breakpoints so that I could intercept when this was happening.  I found that it was ultimately being called from a “mousedown” event, which was in turn creating a new undo operation in the editor and firing the editor’s custom “change” event.

This took me back a few month to when I was integrating the editor into the website.  We basically use the editor to replace text areas on the page, which I gather is the norm.  Believe it or not, tinymce is kind enough to keep the original text area up to date as you make changes.  Unfortunately it doesn’t seem to fire the native browser events that we needed to detect that these changes were occurring.  The editor has its own events, some which mimic native browser events.

One in particular that I was interested in was the “onChange” event.  The documentation states that the event is raised “when contents inside the editor gets changed.”  If you look at the event handler arguments (Parameters) you’ll see that it makes mention of “undo levels” and “undo managers”.  As I understand it, the event actually fires when an “undo level” is added, some atomic action that can be reverted.  This explains why changes were being picked up at seemingly arbitrary times while editing the text.

Anyway, what does any of this have to do with the spell checking results disappearing?  Well, it turns out there were a couple of factors at work here.  The first I have already hinted at.  We were watching for “change” events on the editor and reacting accordingly.  These change events were also firing when you click inside of the editor, which is something that you would obviously do if you were trying to fix a typo to get rid of that nasty red underlining.  I presume this is because when the user has clicked, the text that they have typed can be viewed as an atomic action.  This can be slightly confusing if you don’t know what to expect, but it does make some sense in that it follows Microsoft Word behavior (a worthy goal for a rich text editor).

At any rate, the second factor was even more tricky.  The behavior that depends on knowing when the editor changes  (the reason we’re subscribing to the onChange event in the first place) also has to know what the current value is.  It is essentially a property change eventing mechanism.  This is all well and good, except that I was getting the editor’s value through the editor object’s getContent method, without so much as skimming the documentation for it (it seemed pretty straightforward).  The documentation states that the function will “cleanup the content before it gets returned using the different cleanup rules options.”

If you think about it for a minute, you can see why this is a problem.  The editor’s content is essentially going to be the html that is displayed, right?  So, if the function is going to return the editor’s content, then it seems reasonable for it to “cleanup the content” first.  And what would cleaning up the content involve?  That’s right!  It removes the html that wraps the text to signify that a word is misspelled.  After all, we wouldn’t want to store that in the database.

So at this point I’ve determined what the problem is.  Luckily, it doesn’t appear that I need to call the getContent method after all.  The original text area’s value is updated anyway, so I just read the value directly from the text area. Problem solved!  Now I can go home…

Add JavaScript to a PDF Document with iTextSharp

Originally posted June 8 2010

As you might have guessed from the title, this post is of the “get it done” variety.  So, the code may be a little rough.  Its the sort of code that works, but isn’t fully understood (by me at least).  I wasn’t able to find a clear example on the net, so I pieced together examples and guesses based on reading the code and interpreting method and class names.

Why guess?  Well, iTextSharp is a pretty robust open source project which is useful for creating and manipulating PDF documents.  The problem is, it doesn’t seem to have any useful documentation online.  It is open source, so you can read the code all day.  Also, there are some tutorials that you can download from the files page (in the examples folder).

The goal was to have a PDF document print automatically from a web page.  I decided to pass on coming up with a cross-browser (read: works in IE) method for automatically printing the document on the client, and instead decided to insert JavaScript into the generated PDF document that would cause it to print when opened.  This is what I came up with.

PdfReader reader = new PdfReader(inputStreamOrFile);
int pageCount = reader.NumberOfPages;
Rectangle pageSize = reader.GetPageSize(1);
// Setup writer
PdfDocument document = new PdfDocument(pageSize);
PdfWriter writer = PdfWriter.GetInstance(document, outputStreamOrFile);
document.Open();
// Copy each page
PdfContentByte content = writer.DirectContent;
for (int i = 0; i < pageCount; i++)
{
document.NewPage();
PdfImportedPage page = writer.GetImportedPage(reader, i + 1); // page numbers are one-based
content.AddTemplate(page, 0, 0); // x and y correspond to position on the page?
}
// Insert JavaScript to print the document after a fraction of a second (allow time to become visible).
string jsText = “var res = app.setTimeOut(‘var pp = this.getPrintParams();pp.interactive = pp.constants.interactionLevel.full;this.print(pp);’, 200);”;
//string jsTextNoWait = ”var pp = this.getPrintParams();pp.interactive = pp.constants.interactionLevel.full;this.print(pp);”;
PdfAction js = PdfAction.JavaScript(jsText, writer);
writer.AddJavaScript(js);

document.Close()

As for the JavaScript, the call to setTimeOut is there so that the PDF is rendered before the print dialog is shown.  Otherwise, the users will see the print dialog and a blank page, which may be confusing.  If the PDF is not visible anyway (as in my case) then you don’t really need the timeout.  The actual printing is based on the documentation of Acrobat JavaScript from Adobe’s website.  In this example, the iteration level is set to “full”, meaning that the user will get the print dialog and progress feedback.  You can also use “automatic” (no dialog, includes progress) and “silent” (no dialog or progress).

The New ASP.NET AJAX: Part 1 – Getting Started with the Script Loader

Background: I had an existing ASP.NET AJAX-enabled application and wanted to use the Script Manager control in conjunction with the new client-only Script Loader. I wasn’t quite sure how they would work together and there is (understandably) precious little in the way of documentation. Here is what I have found so far…
By the way, if you haven’t heard of the Script Loader then you can read about it here and here, or Google it (with Bing…)!

Include the Script Loader

My first thought was to just include the script loader’s script file (“start.js”) early, before the page scripts that would use it. Unfortunately, this line of code gave me grief.

if(typeof(Sys) !== "undefined") Sys.Application.notifyScriptLoaded();

It’s automatically appended to script references so we’re stuck with it. This line of code predates the Script Loader, unfortunately. When it was written the AJAX JavaScript library lived in one big JavaScript file, so you either had it or you didn’t. Today, the start script defines Sys (so that you can do things like Sys.require), but it doesn’t define the Application namespace. Therefore, the above line of code causes a “null or not an object” error. In order to get around this you just have to make sure that the start script is injected farther down the page than other script references that may include the offending line of code. In my case I used the ScriptManagerProxy control.

Define Your Scripts

This step is optional if you are just using the scripts from Microsoft or jQuery.

Sys.loader.defineScripts(   {      releaseUrl: "%/{0}.js",      debugUrl: "%/{0}.debug.js"   },   [      {         name: "MyScript",         executionDependencies: ["WebServices"],         isLoaded: !!(MyControl)      }   ]);

The first argument is named defaultScriptInfo, in case you’re wondering. Sounds interesting, doesn’t it? This is where you can put the common settings for all of the scripts that you are defining here. No need to repeat yourself. If you want you can pass null and be done with it.

The second argument is an array of JavaScript objects that tell the Script Loader everything it needs to know about each individual script(s). Here’s a breakdown of the properties:

name: This one is pretty obvious. I assume that you can use any arbitrary text here, but you may want to be selective since it will ultimately be used in JavaScript code. This is the name that you will use in other script definitions to indicate that it is a dependency (“WebServices” in the above example). It is also the attribute name that is tacked on to the Sys.scripts object.
releaseUrl: This is the url (sort of) that can be used to load our script in release mode. This is the literal url, with two exceptions. First, the special “%” character is a placeholder for “the place that I got this script from” (the script loader script). This means that if you downloaded the start script form CDN, then all of the other scripts that you request will also come from CDN. If you download it from your web server, then all of the other scripts will come from your web server. Also, “{0}” is replaced with the script name. This is useful if you’re defining a common url scheme.

debugUrl: Same as releaseUrl, except that this url is used in debug mode.

dependencies and executionDependencies: An array of script names. These are the scripts that must be present before your script can function. These two attributes accomplish this in slightly different ways. (Disclaimer: my current understanding of these options is based on reading through code as well as some guess work.) As I understand it, dependencies indicates that the script loader should wait for the dependencies before it attempts to load the script, whereas executionDependencies indicates that the script loader can fetch scripts in parallel and then execute them in the correct order (more on this later).

isLoaded: Tells the script loader whether or not your script is already loaded. This is useful for things like jQuery that may be commonly included as a static script reference, or for scripts that may or may not be included by the Script Manager.

Fix Your Script Files

If you have existing scripts that you want to load using the Script Loader, they probably look something like this:

<start of file>bunch o' code...<end of file>

In order to take full advantage of the script loader you will need to change your files to looks something like this:

<start of file>;(function() {   function execute () {      bunch o' code...   }

   if (window.Sys && Sys.loader) {      Sys.loader.registerScript("MyScript", null, execute);   }   else {      execute();   }}) ();<end of file>

That bit at the end looks for the Script Loader and if it is found it tells the Script Loader that it is ready to execute whenever its dependency are loaded. Otherwise, it simply executes on the spot. That way it can function with or without the Script Loader.

With this in mind the distinction between dependencies and executionDependencies makes more sense. You may not be able to change a script to match this format. If that is the case, then the scripts cannot be fetched in parallel.

Using Your Scripts

Sys.require([Sys.scripts.MyScript], function() {   bunch o' code...});

It’s as simple as that! The function that you provide as the second argument is executed whenever the required scripts have been loaded.