Introduction

By now you’ve probably read a thing or two about Silverlight 2 already. About the layout system, the new set of built-in controls, data-binding, styles, templates, yada yada. You may either already be cranking out code utilizing all of these visually-oriented features, or you may be left wondering:

"How is any of this useful to me? I’m already using HTML/CSS/JS on the client, and I don’t have any intentions to visually enhance or replace my website."

My goal is to demonstrate how you can take advantage of Silverlight by taking you through some of the features in Silverlight that you can use to enhance your existing website in a non-obtrusive way. Think:

  1. Writing new code in a managed language (C#, Ruby, JScript.NET, whatever) instead of native (interpreted) JavaScript.
  2. Using OpenFileDialog to read files on the client, without round-tripping to the server.
  3. Storing transient data securely on the client in isolated storage.
  4. Improving responsiveness and performance by executing work in the background through a BackgroundWorker or by using ordinary threads.
  5. Accessing cross-domain data via the networking APIs.
  6. Retrieving real-time data from the server via sockets.
  7. Binding data by re-using WPF's data-binding engine.

If you’re wondering what the point of all this is, ask yourself (or the users of your website) when the last time is you (or they):

  1. had no idea how much time there was left before an upload would finish;
  2. couldn’t resume from a failed upload;
  3. lost data (article/comment/etc.) after trying to save it;
  4. wasted lots of server-side bandwidth (and decreased client-side responsiveness) because the server had to act as a proxy between the client and a third-party website.

This can be addressed with Silverlight. The key to integrating all of this is the two-way interoperability layer in Silverlight (sometimes referred to as 'the HTML/JS bridge'), which is what I will be going through in this article. I will show you how you can access the HTML DOM and use your existing JavaScript code. You will see how you can pass managed objects back and forth, and program against them in JavaScript like ordinary JS objects. We will dive deep and take a look at what really happens under the hood to understand how far exactly our interoperability goes.

Getting started

Accessing the HTML DOM

Silverlight’s gateway to the browser is System.Windows.Browser.HtmlPage. It’s a static type with properties – such as Window, Document and Plugin – which should all be self-explanatory. The only thing to note is the IsEnabled property. Access to the hosting page may be disabled in a few situations:

  1. The hosting page set the enableHtmlAccess hosting parameter to false. This is a common thing to do when hosting advertisements or other Silverlight content that you don’t trust.
  2. Your code executes within a custom host, such as the Blend designer.
  3. The plugin unloaded itself, either by removing itself from the HTML DOM, or by changing its source property.

Generally you’ll check for this flag before initializing code that uses HtmlPage, and bail out quickly if it returns false. There’s usually no need to check for this flag throughout the rest of your code.

With this information it should be straightforward to access the HTML DOM. To insert a new element into the DOM, you may previously have written:

JavaScript:
1 
2 
3 

var element = document.createElement("div");
element.innerHTML = "Hello, World!";
document.body.appendChild(element);

This translates to the following in C#:

C#:
1 
2 
3 

var element = HtmlPage.Document.CreateElement("div");
element.SetAttribute("innerHTML", "Hello, World!");
HtmlPage.Document.Body.AppendChild(element);

You get the idea.

A common thing you may run into is that when the plugin is initializing (the application's constructor executes), the HTML DOM may not be ready yet. This means you may not be able to find an element, or you may run into 'Operation aborted' errors in IE. To deal with this, you are encouraged to check for HtmlPage.Document.IsReady and handle HtmlPage.Document.DocumentReady if the document isn't already ready.

Invoking JavaScript

Calling into JavaScript isn't much more complicated. To continue getting right to the point, let's take the following JavaScript:

JavaScript:
1 
2 
3 

var calculator = new Calculator(); // Assume this is a JS library of ours.
var sum = calculator.add(5, 1);
alert(sum);

And turn it into C#:

C#:
1 
2 
3 

var calculator = HtmlPage.Window.CreateInstance("Calculator");
var sum = Convert.ToInt32(calculator.Invoke("add", 5, 1));
HtmlPage.Window.Alert(sum.ToString());

There are a couple of things going on here.

The first thing to notice is that you use HtmlWindow.CreateInstance to instantiate JavaScript objects. Under the hood this will evaluate some JavaScript to create the instance, due to lack of native support for instantiating objects through the browser's plugin API.

Next, notice that Window, an HtmlWindow type, has an Invoke method. It inherits this method from one of its base types, ScriptObject. A few other fundamental methods it inherited are InvokeSelf, GetProperty and SetProperty. These few methods let you do just about anything. I will cover them in-depth later in this article. For now all you need to remember is that these members let you get and set values, and invoke functions.

The other thing to notice is the call to Alert. We could've actually called into alert like this:

C#:
1 

HtmlPage.Window.Invoke("alert", sum);

In fact, that's exactly what HtmlWindow.Alert does under the hood. In general we decided to make commonly-used functions first-class for discoverability and sometimes performance reasons. Whenever there is a built-in way to do something, you'll want to use that instead of using late-bound calls.

Lastly, Invoke and GetProperty both have an Object return type. They may return a bool, double, string or ScriptObject. We always return a double for numbers because this is what Safari gives us back under the hood. Also, for now assume that ScriptObject is an ordinary JavaScript object.

With this knowledge you should be able to do just about anything from managed code already. You can instantiate objects, invoke functions that return objects, set properties on those objects, and so forth.

At this point you may be wondering what happens when you pass a managed object to JavaScript. Before we go into this, let's quickly go over the opposite of what we've done so far.

Invoking managed code

Before you can invoke any managed code from JavaScript, you first need to register the objects you want to expose to the browser. You also need to mark which members are callable with the ScriptableMemberAttribute, or mark all declared members at once with ScriptableTypeAttribute:

C#:
1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 

public class Calculator {

    [ScriptableMember]
    public int Add(int a, int b) {
        return a + b;
    }

    // Not callable from script.
    public int Subtract(int a, int b) {
        return a – b;
    }
}

public class App : Application {

    public App() {
        HtmlPage.RegisterScriptableObject("calc", new Calculator());
    }
}

After you have a scriptable object, you can use it from JavaScript:

JavaScript:
1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 

void onPluginLoaded(plugin) {
    var calc = plugin.content.calc;
    // If you are using ASP.NET AJAX to create a Silverlight instance, use this instead:
    // var calc = plugin.get_element().content.calc;
    var sum = calc.Add(5, 1); // Case sensitive.
    alert(sum);
    try {
        calc.Subtract(5, 1); // Failure. There's no such member.
    } catch (e) {
        alert(e.message ? e.message : e);
    }
}

As with calling into JavaScript from managed code, you can pass JavaScript objects and DOM elements to managed code, assuming the signature of the invoked member permits this.

You should make sure you don't access any managed objects before they're initialized. If you need to access them when the page is loaded, you should handle the plugin's onload event and access your managed objects from there.

Inside the marshalling layer

So far the examples we've seen are very basic. They involve calling methods with primitive arguments and return values. In Silverlight our support goes much further however. As I briefly mentioned before, you can pass arbitrary managed objects back and forth between Silverlight and the browser. We also have specialized support for DateTimes, Guids, structs in general, Delegates, lists and dictionaries.

JavaScript dates are ordinary objects. This is why we treat them as such by marshaling them to ScriptObjects, just like we do with any other type of JavaScript object. The only difference is that we check what type of value the target site expects. If it expects a DateTime, we will convert it to that. Similarly, when you pass a DateTime to JavaScript, we will convert it to a real JavaScript date object.

Our support for Guids is trivial. When one is passed to JavaScript, the marshalling layer converts it to a string. We do this because it's fairly common to use Guids as identifiers for data, and the easiest way to represent them in JavaScript is via an ordinary string. If you round-trip such a string back to managed code, we will only attempt to convert it back to a Guid if the target site expects a value of this type.

Struct support is relatively basic too. We try to enforce the right semantics by making sure we create copies of values before marshalling them, which involves boxing the value. Without explicitly copying the values, there are cases where a value type would very much act like a reference type. For example, passing a value type to JavaScript where one of the fields gets mutated would in fact mutate the field on the value on the caller's site.

Anything else that is not a ScriptObject or primitive will be marshaled by reference as a managed object. To understand how managed objects are marshaled, we should first take a look at how browser objects are marshaled.

Browser object marshalling

All browser objects are represented by ScriptObjects. This includes ordinary JavaScript objects, but also windows (HtmlWindow), documents (HtmlDocument) elements (HtmlElement), element collections (HtmlElementCollection) and even managed objects (ManagedObject, an internal type) that have gotten a life inside the browser. We do a lot of things when the browser returns an object reference to us as after invoking a function or property. This is all done transparently, so you don't need to worry about any of this, but it gives you an idea of what's really happening in part of the marshalling layer.

Type inference

In Silverlight 1.1 alpha we forced you to tell us what the type of an object was going to be via a generic type parameter. While the glorified cast may seem nicer than the casts you need now, you would quickly find that you don't always know the type of an object. In one place you may assume the elements of an array are of type ScriptObject, while in reality one of the elements is in fact an HTML DOM element. This made it difficult for us to guarantee correctness, impacting the reliability of any code that used our bridge.

This has changed in Silverlight 2. We now automatically determine the type of an object. In Internet Explorer we can do this very efficiently through a few native calls to QueryInterface. In the other browsers we are forced to determine the type via some 'JavaScript reflection.' In both Firefox and Safari this boils down to inspecting nodeType to see if an object is a document or element. If the object doesn't have this property, we will check if the object is an instance of HTMLWindow, NodeList or HTMLCollection in Firefox. In Safari 2 we'll look at a few other properties that let us determine whether it's a window or element collection.

We only need to do this when the value that the browser returned to us is an object. For every value the browser returns to us, it lets us know whether it's a bool, int, double, or an object, so we don't always need to do additional work to find out the type of a return value.

Object identity

When the browser returns a value, we convert or marshal this to a managed value. For primitives this is a straightforward process. Objects however are simply a pointer, so we need to marshal it to something that is usable from managed code. We need to marshal it to a ScriptObject or one of its derivates, based on the type we previously inferred.

The simplest thing we could've done is marshal a pointer to a new object every time. This would have several consequences though. In scenarios involving lots of round-tripping of objects, memory usage would grow and the pressure on the GC would increase. More importantly, we would have a correctness problem. Imagine the following code:

C#:
1 
2 
3 
4 

var f1 = HtmlPage.Document.GetElementById("foo");
var f2 = Htmlpage.Document.GetElementById("foo");
assert(f1.Id == f2.Id); // True.
assert(f1 == f2); // False.

This code queries for the same element twice. The variables f1 and f2 both refer to a different managed object, which in turn both wrap the same native browser object. This object identity issue might seem unimportant, but it hits you whenever you need to tell whether two objects are the same.

We could deal with this by overriding Equals/op_Equals and letting it compare the underlying browser object pointers, and let GetHashCode return the pointer's hash code. Although this would probably address the majority of the situations, it would simply be a work around. There still wouldn't be true object identity. You would still get the wrong result when comparing two variables typed as Object, as the CLR would end up comparing the references, rather than calling into the overloaded equals operator. Furthermore the GetHashCode implementation would be rather inefficient on Safari – which I'll explain further in a second.

To correctly implement object identity, we need to know whether we already marshaled a browser object before. If we did, we simply return that object. Otherwise, we marshal it and make sure we keep track of the managed object we create. We introduced an object cache in ScriptObject for exactly this.

The object cache maps pointers to WeakReferences of ScriptObjects. By using weak references we avoid keeping alive objects forever. Additionally, ScriptObject implements a finalizer to remove its entry in the object cache, such that we're not leaking at least sizeof(IntPtr) bytes per object that no longer exists.

At this point there's only one remaining problem. Safari doesn't preserve object identity in its plugin API, which means that we get back different pointers every time for the same native browser object. It is important to note that the pointers we get back are pointers to objects which wrap the real browser object – even so in FF. Both browsers support the NPAPI, a plugin API supported by most browsers, which defines the contract of an object (NPObject). To adhere to this contract, it usually needs to marshal its browser objects itself. Firefox seemingly does this by caching NPObjects to preserve object identity and reduce memory overhead. Safari apparently creates a new NPObject every time.

We addressed this problem by introducing a second object cache, which maps a custom identifier (an int) to an IntPtr of the browser object that we marshaled before, which is also the key in the primary object cache. We generate custom identifiers ourselves, and try to store this in a private field ($__slid) on the object, such that we can read this back later when we need to marshal another pointer. Whenever we are trying to marshal a pointer, we first try to read this private field and do a lookup in our secondary object cache to get back a different pointer (to this object) which we marshaled before.

This secondary cache is purely used as a heuristic to improve performance. We don't rely on any of the information we gather in this process. We use it to do a lookup in the real object cache, and we then call into script to verify the two pointers we have (a pointer which we want to marshal, and a pointer we marshaled before and believe points to the same browser object) do indeed point to the same browser object. We do this by calling into an anonymous JavaScript helper function, which looks like:

JavaScript:
1 
2 
3 

function(obj1, obj2) {
    return (obj1 == obj2);
}

When we pass two pointers to native browser objects, NPObjects, the browser will marshal these back to real browser objects. In every browser, including Safari, it will get back the original browser objects. Because of this, we can correctly tell whether two objects are the same in JavaScript.

Back in managed code we can use this to verify that two pointers are indeed the same. If they are, we go ahead and return the managed object we created before for this object. If they aren't, we will walk through our primary object cache and check if this pointer really wasn't marshaled before, by comparing each pointer to the current pointer via a call to our JavaScript helper function. If it turns out we never marshaled this browser object before, we will generate a new identifier and associate try to associate it with this browser object. We will update both object caches accordingly.

This process does involve a slight performance hit on Safari, in particular when you often marshal objects that you never marshaled before. Unfortunately there's not much we can do about this given the way Safari decided to implement the NPAPI, without sacrificing the usability of our managed API.

Managed object marshalling

Marshalling to JavaScript objects involves creating a browser object which wraps the managed object and acts as a proxy. Internally it's a ManagedObject which derives from Scriptobject. When a managed object is round-tripped, we will return its ManagedObject, rather than the real managed object it wraps. You can access the underlying managed object via the ScriptObject.ManagedObject property.

We decided to return ManagedObjects rather than their underlying objects to make the programming model more consistent and increase the reliability of user code: every object can be treated in the same way, just like you can in JavaScript. This means you don't have to constantly check if an object is either a browser object or a managed object.

ManagedObjects reference a ManagedObjectInfo which stores a method table with entries for each scriptable member for that type. The entries are wrappers around the actual members, which makes it possible for us to add special-casing for certain type of members, such as properties and events.

For every managed type we lazily construct the (case-sensitive) method table and cache this information for performance reasons. We use weak references such that this information can be released when there's no reason to hold onto it any longer. The process for constructing the method table for most types involves walking through all public members with a ScriptableMemberAttribute. We then walk their inheritance tree. For every type in this tree with a ScriptableTypeAttribute we add all of that type's declared members. This means that if you apply this attribute to your type, it will only add the members you declared in your type; it does not include any inherited members. We also add an addEventListener and removeEventListener method to the method table to support events in the same kind of way they're supported in the HTML DOM.

Another method we add is createManagedObject. This method lets you create instances of complex types that are used as parameters for any of the scriptable members. For example, if you have a CustomerService type with a scriptable Add(Customer) method, you will be able to create an instance of such a Customer type, assuming it has a public default constructor:

C#:
1 
2 
3 
4 

var customerService = plugin.content.customerService;
var customer = customerService.createManagedObject("Customer");
customer.Name = "John Doe"; // Assume we marked Customer.Name as a scriptable member.
customerService.Add(customer);

By automatically doing this work for you, you don't need to add calls to HtmlPage.RegisterCreatableType all over the place. You also don't need to hold on to the plugin object in order to call createObject to instantiate a type registered via RegisterCreatableType. In other words, each object that is a receiver (i.e. has a scriptable method which takes a complex object) is also a factory which creates complex objects.

We have basic support for method overloading, by finding the overload which matches the number of arguments and by doing some basic parameter validation.

Delegates are a special-case scenario. We map a delegate's DynamicInvoke method and add an apply method. This method allows you to invoke delegates in a 'late-bound' fashion from JavaScript. We will take care of unrolling the array of arguments and call DynamicInvoke on the delegate.

JavaScript functions are automatically marshaled to delegates if the target site expects one. Silverlight 2 currently only supports delegates that are compatible with the void(object, EventArgs) signature, such as EventHandler and EventHandler<TEventArgs>. Arbitrary delegate types aren't supported – at least not at the time of writing.

Types that implement IList will end up storing members in the method table that correspond to the functions that JavaScript arrays support. This means managed arrays, List<T>s, and so on can be treated and used as arrays in JavaScript.

Similarly, types with support for IDictionary<string, TValue> are also made more accessible from JavaScript. The keys in such a dictionary translate to fields in JavaScript. When you set a field, we will add or set the value with the field's name as the key. Accessing a field translates to a lookup in the dictionary.

Lastly, we always map the ToString method of every type, because some browsers implicitly call toString on objects, for example when passing them to alert.

Object lifetime

Normally a managed object gets collected by the GC when it's no longer rooted. In other words, when an object can no longer be accessed, the GC is allowed to collect it. When we pass such an object to the browser, we have to prevent this behavior. We do this by pinning the ManagedObject and giving lifetime ownership to the browser object that wraps it. This browser object is always a reference counted object which will unpin the ManagedObject when the last reference is released.

We will re-create the native browser object on the fly when a ManagedObject is passed to the browser after its native counter-part no longer exists.

If the managed runtime shuts down when the browser still has a reference to a managed object, for example by removing the plugin from the DOM after getting the reference, the browser object wrapping the managed object will know about this and gracefully let all calls fail. When the last reference goes away, it won't attempt to unpin the managed object either, which isn't a problem as the managed object was already freed from memory during the managed runtime shutdown.

The lifetime of all other objects is more trivial. Either when the managed runtime shuts down, or when a ScriptObject gets GC'ed because it's no longer reachable, we will release our reference to the native object. We guarantee that this reference is released on the UI thread.

Exception handling

Silverlight returns exceptions thrown in managed code as JavaScript errors. It does this by calling ToString on the exceptions, and then it passes this exception text on to the caller. Internet Explorer stores this in an error object. When catching this error, you can get back the exception text by accessing the message field. In all other browsers the object that you catch is the exception text.

There's one exception. It appears that Safari ignores any reported errors. This means that if you invoke a method which throws, your JavaScript code won't know if anything went wrong. It'll simply not get back a value. One way to deal with this is by always returning something from managed code, such as a Boolean value. This way you can assume something went wrong when you don't get back any value.

The opposite – throwing exceptions in JavaScript back to managed code – works similarly. Unfortunately the plugin API we use for browsers other than Internet Explorer (NPAPI) doesn't have first-class support for reporting exceptions. We can only tell whether a call failed or succeeded. We considered invoking JavaScript functions via a helper function, but this requires the ability to invoke JavaScript functions in a late-bound way (via Function.apply), something that isn't supported by every version of Safari that we support. Consequently we simply throw a generic InvalidOperationException whenever a JavaScript function invocation fails. In Internet Explorer it contains the error text of the exception that was thrown, while in all other browsers you will simply see a generic error message.

Use case: Extending the browser with OpenFileDialog support

Most browsers today don't support reading files on the client. You have to use an input element of type 'file' and let the browser send the file to the server, which can then echo the contents back to the client. Besides the somewhat awkward user experience, it also complicates the programming model. You have to restore the state of the page, or you have to use an iframe and do the round-tripping there.

Silverlight comes with an OpenFileDialog feature. This dialog provides read-only streams to one or more files selected by the user. Out of the box you can only use this feature from managed code. It takes little effort to encapsulate this feature though. Let's take a look at what it takes to extend the browser with this feature.

Step 1: Adding a Silverlight island to the page

There are several ways to do this. The easiest is to use VS and let it generate a page with Silverlight for you. It will embed Silverlight via an object tag, which refers to your Silverlight application (a .xap file). To integrate this application with your website, all you need to do is copy this object tag declaration and the .xap file.

Since our feature doesn't have any UI on the page, you can make sure the object tag's width and height is 0 pixels. You shouldn't use the display or visibility styles to make Silverlight invisible, as Silverlight may not even run at all in that case.

Step 2: Making OpenFileDialog scriptable

We can make OpenFileDialog scriptable by introducing a few wrappers. For the OpenFileDialog type itself we can simply add a scriptable method to our application. We'll let this method return an array of scriptable objects which wrap the OpenFileDialog's SelectedFiles property. In code this looks like:

C#:
1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
13 
14 

public class App : Application {

    public ScriptableFileInfo OpenFiles(string filter) {
        var dialog = new OpenFileDialog();
        dialog.Filter = filter;
        if (dialog.ShowDialog() == DialogResult.OK) {
            var fileInfos = new ScriptableFileInfo[dialog.SelectedFiles.Length];
            for (int i = 0; i &lt; dialog.SelectedFiles.Length; i++) {
                fileInfos[i] = new ScriptableFileInfo(fileInfos[i]);
            }
        }
        return new ScriptableFileInfo[0];
    }
}

And the ScriptableFileInfo type can be implemented like this:

C#:
1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
23 
24 

public class ScriptableFileInfo {

    private FileDialogFileInfo _info;

    [ScriptableMember(ScriptAlias = "contents")]
    public string Contents {
        get {
            using (var reader = new StreamReader(_info.OpenRead()) {
                return reader.ReadToEnd();
            }
        }
    }

    [ScriptableMember(ScriptAlias = "fileName")]
    public string FileName {
        get {
            return _info.FileName;
        }
    }

    public ScriptableFileInfo(FileDialogFileInfo info) {
        _info = info;
    }
}

Now, we still need to expose this to script. There are two options we can choose from:

  1. Add a ScriptableMemberAttribute to our OpenFiles method, and register our application object as a scriptable object by calling HtmlPage.RegisterScriptableObject.
  2. Encapsulate our OpenFiles method via a delegate which is accessible from script.

We will go with the last option because it's the easiest to work with from JavaScript. It's also just as easy to implement. In our application's constructor we simply add:

C#:
1 

HtmlPage.Window.SetProperty("openFiles", new Func<string, ScriptableFileInfo[]>(OpenFiles));

Step 3: Using OpenFileDialog from JavaScript

Now that we've added an openFiles function to the window object, we can access it from JavaScript like this:

JavaScript:
1 
2 
3 
4 

var selectedFiles = window.openFiles("Text Files|*.txt;*.csv|All Files|*.*");
for (var i = 0; i < selectedFiles.length; i++) {
    alert(selectedFiles[i].fileName + ": " + selectedFiles[i].contents);
}

We do still need to be careful about when we execute this code. The openFiles function won't be there until our application has been downloaded and its constructor has executed. You can account for this by handling the onload event on the Silverlight plugin. Once this event has occurred, you should be able to safely use the openFiles function on the window object.

Conclusion

Silverlight does a lot of work under the hood to make it a first-class citizen in the browser. People writing managed code can fully integrate with the existing codebase for a website. Those who prefer to continue writing JavaScript can fully leverage the features offered by Silverlight with little effort. This should allow everyone to get at least something out of Silverlight.

A while ago Rick Strahl raised a concern about returning dynamic query results in LINQ. It's a fairly common thing for people to return dynamic query results (i.e. create projections), using the new anonymous types feature. The consequence of using anonymous types is that you can't just return it from a method, because you don't know what to put for the method's return type. Or can you?

A trick you can use is to defer the projection to the caller. The data method would simply expect a 'projection' delegate/lambda, which it can use for the select part of the query. Because the non-projected query result type is always known, you can use this type as the parameter type of the 'projection' delegate/lambda. In code this looks like:

C#:
1 
2 
3 
4 

public IEnumerable<TProjection> GetCustomers<TProjection>(Func<Customer, TProjection> projection) {
    return from c in _customers
           select projection(c);
}

As you can see the return type is based on the type of the projection. The type of the projection is based on the type of projection that a caller uses. For example, in the code below the return type is an IEnumerable of the anonymous type defined in the call to GetCustomers.

C#:
1 
2 

var results = GetCustomers(customer => new { Name = customer.Name });
// results is of type IEnumerable<'anonymous type with property Name'>.

This trick also works with more complicated scenarios. For example, you can also deal with nested queries in a similar way.

C#:
1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
13 

public IEnumerable<TProjection> GetCustomersWithOrders<TProjection>(Func<Customer, IEnumerable<Order>, TProjection> projection) {
    return from customer in _customers
           let customerOrders = from order in _orders
                                where order.CustomerID = customer.ID
           select projection(customer, customerOrders);
}

// ...

var results = GetCustomersWithOrders((customer, orders) => new {
                                         Name = customer.Name,
                                         OrderCount = orders.Count()
                                     });

These examples use in-memory collections, but nothing prevents you from using the same technique with DLINQ or other APIs. When using DLINQ, you will just have to replace 'IEnumerable' in the above examples with 'IQueryable'.

But what about...
Now that said, this trick doesn't address the scenario where you have a complex projection, that you really wish to hide from the callers. For those scenarios I guess you don't really have a choice but to introduce a named type to hold the projection.

About half a year ago I wrote a short paper about IronRuby. It was a paper for school and it was later published in the German dotnet-magazin. Since it's no use sitting on my computer locally, I thought I'd share it, IronRuby, A Ruby implementation for the Common Language Runtime, with you.

Today, I have spent most of my time working on a new Virtual Earth Atlas control. I wanted to add support for drawing shapes on top of a map, to make it easy to for example build a driving directions app. While the Virtual Earth control doesn't support this stuff directly, unlike Google Maps, I saw that the VE API provides pretty much all of the plumbing. As always, you will want to look at the results. It should work in at least IE and Firefox (I only tested those). Don't forget to check out the link to the source-code behind that page to get a sense of how much code was involved in putting that page together.

During the next few days I will probably extend the control a bit to actually add proper pushpin support, add a fancy map controller and a few other things. I may even write a proper demo if I could get some useful data. If there is interest, I could talk a bit more on how I put this thing together (client-side and server-side). Either way, I will try to make the binaries and source available within a few days.

Update:
You can now download the demo app, which includes client-side and server-side source code. Instead of writing an article about the whole thing, I'd like to ask you to leave behind a comment to let me know what it is you would like to know. This may range from the (current) server-side Atlas infrastructure to extending the Virtual Earth control.

When an Atlas enabled page is loaded, several things need to be set up. In a nutshell, it goes like this:

  1. Based on the browser, load the first browser compatibility layer
  2. Load the Atlas core
  3. Based on the browser, load the second browser compatibility layer
  4. Process the Atlas markup
  5. Initialize all components

Step 1: Load the first browser compatibility layer
One of the key features of Atlas is to provide a unified library where you no longer have to worry about the capabilities of the browser when it comes to core features, such as attaching event handlers. Having such a unification allows for more compact and more readable code. Therefore, it makes sense to have this unification in place as soon as possible when the page is loaded, so that you (and Atlas) can rely on this practically everywhere. For this specific reason, the first compatibility layer is the first thing that is loaded. It is only loaded when the browser does not support certain "API's", such as HTMLElement.attachEvent, that is supported by IE and is commonly used. Since IE is still the most used (and targetted) browser, it probably makes sense to optimize for IE and provide compatibility layers for other, less used browsers instead. As a result, you don't see compatibility layers for IE in the current release (let's forget about the _loadIECompatLayer in AtlasCore.js, which really only determines which XMLHTTP object it should use).
The server-side ScriptManager control takes care of including the browser compatibility layers, by looking at what browser the client uses. If you don't use the server controls, you could use the Script server-control, which has a Browser property that you can set to conditionally include a script.

Step 2: Load the Atlas core
Another key feature of Atlas is that it brings certain object-oriented programming concepts to the client, such as classes, interfaces, delegates and events. If you think this allows for certain techniques to work in the same way as you may be used to in other languages (such as C#), you thought right. Right after the first level of unification is in place, the AtlasCore is loaded by the browser. Inside this script, Atlas will extend certain JavaScript objects, such as Function and String, to practically create a type system, and to add a level of convenience (for example strings get a format function which is similar to .NET's String.Format). The emulated type system is mostly built on top of JavaScript objects Function and Object, and includes functions for registering namespaces/classes and testing whether a type implements a certain interface.
Once the type system and other extensions are in place, the rest of the core library is loaded. This includes registering several classes, such as Web.Component and Web.Net.WebRequest (the core for all 'AJAX' related things in Atlas). It also includes instantiating several (singleton) objects that will be available until the page is unloaded, such as a debugger (with basic debugging/tracing capabilities) and an application which parses the markup once the page is completely loaded (i.e. window's onload event is raised).
Lastly, there is a TypeDescriptor that is used to keep track of all types that can be used declaratively.

Step 3: Based on the browser, load the second browser compatibility layer
In the current release of Atlas, there is another browser compatiblity layer, which is really only used for Safari at this point. This layer takes some 'side effects'/'features' of Safari into account. For example, Safari converts all tags to uppercase when a string is parsed into a DOM. Atlas (and JavaScript) is case sensitive, which means that Atlas markup would not work in Safari, unless a workaround would be implemented. In the second browser compatibility layer, the registration functions for registering declaratively usable types and properties are extended. Specifically, Atlas will start registering stuff twice, in both original casing and the casing that Safari converts to, to allow for Safari's intelligence.
After the extensions have been made, all types that were already registered will be registered again, to ensure that the new registration process is applied to previously registered types as well.

Step 4: Process the Atlas markup
After the core is loaded, and most browser features have been unified, the browser is practically done loading the page. It therefore will raise window's onload event. As I mentioned before, the application handles this event by parsing the Atlas markup.
It does so by finding the first Atlas script tag. When this script tag is found, all the declaratively defined script references are resolved. After all references have been resolved, the markup of the objects will be parsed.
The application will go through the children of the top level components element, and do a lookup in a table with mappings between tag names and type names. This table was populated with all types that called Web.TypeDescriptor.addType to allow themselves to be used in markup. For each type, Atlas will look if the type has a (static) 'parseFromMarkup' implementation. If it does not, it recursively does the same for the base type. Once it found a parse function, it will call it and provide the current xml element and the markup context. From there on, the function is responsible for processing the entire markup in this element.
The markup context stores all object references and is used to find objects within a specific scope. This is also the basis for resolving references between objects. At this moment, there is a top-level markup context (with all global objects), and a markup context for each template instance (for example in a ListView scenario). Because sometimes you want to be able to reference global objects from within a template, markup contexts can be parented. When an object inside an item template references a global object, Atlas will resolve this reference by first trying to find this object in the item template's markup context, and if it's not there, recursively try to find it in the parent markup context.
Generally, an implementation of 'parseFromMarkup' starts by instantiating the type based on the tag name of the xml node. When a type implements Web.ISupportBatchedUpdates, it will call its 'beginUpdate' function. This gives the instance a way of knowing if it is being initialized, so it can potentially delay certain logic in for example a property's setter. Right after that, all properties/events will be set. The attributes that were declared, will be parsed as property values or event handlers. Properties that can reference other objects in markup will not be set directly. Instead, the instance will be registered with the property in the markup context, and the reference will be resolved once all markup has been processed.
Properties that are declared as elements, will be parsed using logic similar to the way the application started parsing markup. Each property will be set to the instance (or instances if the property is an array) that are a result of parsing the child nodes of the property element.
Events will be parsed in a similar way, except that child nodes should result in action instances, that will be added as actions to the event.
After the instance has been (recursively) processed, the instance will be registered in the markup context as an object where the Web.ISupportBatchedUpdates's 'endUpdate' function still needs to be called. Most objects implement this function by actually initializing themselves. Therefore, the 'endUpdate' function of each object will be called after all markup has been parsed, and after all object references have been resolved.
Templates are not part of the initial parsing process. Controls such as ListView can use a template instance to create new instances of the types defined in the markup of the template. Ofcourse, the same parsing logic (and rules) applies when templates are parsed.
While this covers most of the markup parsing logic, there is one more thing I should mention. In some cases, there are non-user defined references between objects. For example, a behavior has a reference to its control, which it needs when it is initialized. To ensure that an object is guaranteed to have a reference to a different object, Atlas provides a component collection object. An instance of a component collection can be created by calling Web.Component's static 'createCollection' function. As an argument, you can pass an owner object. Web.UI.Control for example passes a reference to itself when it creates the behavior collection. Whenever an object is added to this collection, the owner object will be passed to the setOwner function of the added object.

Step 5: Initialize all components
In the previous step, all the objects were instantiated, and only references to elements were resolved. References to objects in markup were not resolved, because that would limit declaratively defined objects to only refer to objects that were previously declared. After all the objects have been instantiated, all references can be resolved.
Finally, the 'endUpdate' function will be called on all objects that implemented Web.ISupportBatchedUpdates, to actually initialize each object.

Hopefully this post gave you a better idea of how an Atlas page is constructed. Please leave a comment if you have feedback and/or questions.

Atlas provides a binding model which differs from the data-binding model in ASP.NET. It is a flexible binding mechanism, somewhat similar to the one provided by WPF (Windows Presentation Foundation), that basically lets you bind any property of 1 component to any property of another object. Therefore we call them bindings, instead of data-bindings, since we can for example even bind the style of 1 control to a property of another control.

Let's first look at a basic example that binds the value of a textbox to a label. Whenever we change the text in the textbox, we want to update the label's text property accordingly.

ASP.NET:
1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 

HTML:
[...]
<input id="nameTextBox" type="textbox" /><br />
<span id="nameLabel"></span>
[...]

Atlas:
<script type="text/xml-script">
  <page xmlns:script="http://schemas.microsoft.com/xml-script/2005">
    <components>
      <!-- 'Upgrade' the HTML textbox to an Atlas textbox. -->
      <textBox id="nameTextBox" />

      <!-- 'Upgrade' the HTML span to an Atlas label. -->
      <label id="nameLabel">
        <bindings>
          <binding dataContext="nameTextBox" dataPath="text" property="text" />
        </bindings>
      </label>
    </components>
  </page>
</script>

So, what does Atlas do to make this this possible? First of all, Atlas needs a way to listen to property value changes (unless we don't use automatic bindings). There is an INotifyPropertyChanged interface, which is similar to the one provided by .NET. Objects can implement this interface to let other objects listen to property value changes. The Atlas component class (base class for components such as controls and behaviors) implements this interface. Additionally, the component class has a function 'raisePropertyChanged(propertyName)' which you should call in every property's setter, to raise the INotifyPropertyChanged.propertyChanged event.

With this knowledge, lets look at a few parts of the TextBox implementation to learn how we should raise the propertyChanged event when an event of the HTML element was raised.

JavaScript:
1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
23 
24 
25 
26 
27 
28 
29 
30 
31 

[...]
var _text;
var _changeHandler;

this.get_text = function() {
  return this.element.value;
}

this.set_text = function(value) {
  if (this.element.value != value) {
    _text = value;
    this.element.value = value;
    this.raisePropertyChanged('text');
  }
}
this.initialize = function() {
  Web.UI.TextBox.callBaseMethod(this, 'initialize');
  _text = this.element.value;
  _changeHandler = Function.createDelegate(this, this._onChanged);
  this.element.attachEvent('onchange', _changeHandler);
  [...]
}

// Handles changes in the underlying HTML control.
this._onChanged = function() {
  if (this.element.value != _text) {
    _text = this.element.value;
    this.raisePropertyChanged('text');
  }
}
[...]

As you can see, we raise the propertyChanged event whenever the text in our textbox changes. This makes it possible to actually bind against this property.

When we create a binding, the binding will look at both the 'source' object (the data context) and the target object (on which you defined the binding) to see if it implements INotifyPropertyChanged. If the source object does, the binding will handle its propertyChanged event by evaluating the 'incoming' binding, if the property you specified in the dataPath was the property that changed and the direction is set to In or InOut.
If the target object implements INotifyPropertyChanged, its propertyChanged event will be handled by evaluating the 'outgoing' binding, if it is the property you defined on the binding and if the direction is set to Out or InOut.

Lastly, lets have a look at the public properties and methods of a binding, and see what they are good for. I got this list by looking at the getDescriptor implementation of Web.Binding in AtlasCore.js.

  • Property 'automatic': Specifies whether the binding should automatically be evaluated whenever the property of the source object's property was changed (In, InOut), or the target object's property was changed (Out, InOut). Sometimes you want to control when the binding should be evaluated. For example, you only want to evaluate a binding when a ServiceMethodRequest completed the request so it actually has data. You can do this by setting automatic to false, and explictly invoke the evaluateIn method of the binding. The default value is 'true'.
  • Property 'dataContext': Specifies the source object which has a property that you want to bind to. You can set this to another object, such as a TextBox control. If you don't set this, the binding will call its owner's dataContext property. Controls implement this property by either returning the dataContext that was set, or by returning its parent control's dataContext. Controls such as the ListView take care of setting the dataContext to for example a DataRow object when it creates ListView items, which makes it possible to bind against data items.
  • Property 'dataPath': The source object's property that you want to bind to. You can bind against 'nested properties' as well, using the following syntax: 'sourceObjectProperty.nestedProperty.anotherNestedProperty'. The binding will split this path and run code similar to:
      'var value = mySourceObject.getProperty('sourceObjectProperty')
      .getProperty('nestedProperty')
      .getProperty(anotherNestedProperty)'
    The default value is nothing, which means you will actually bind to the source object itself.
  • Property 'direction': Lets you specify whether you want to listen for changes (In), propagate changes (Out), or both (InOut). The default value is 'In'.
  • Property 'property': The target object's property that you want to bind to. You should always set this property.
  • Property 'propertyKey': Sometimes you want to bind to a member of the property you specified in the 'property' property. For example, you may want to bind to the style's property 'width'. You can do so by setting the property 'property' to style, and set the property 'propertyKey' to 'width'.
  • Property 'transformerArgument': An argument that will be passed to a transformer.
  • Event 'transform': This event lets you apply a transformation during the evaluation of a binding. This can be useful if you for example want to display a bound value differently in the target object. There are several built-in transformers, such as Add, which can be useful to add a value (specified using the property 'transformerArgument') to the bound value. This is useful if you are binding to an index, which generally start at 0, and you want to display them starting at 1.
  • Method 'evaluateIn': Evaluates the 'incoming' binding, if the direction was set to In or InOut. It does so by actually getting the value of the source object's property (based on the dataContext and dataPath values), and call the target object property's setter with this value.
  • Method 'evaluateOut': Similar to evaluateIn, except that it works the other way round, and only works when the direction is set to Out or InOut.

Hopefully this answers some questions with relation to bindings. Please leave a comment with any questions that you may have, or leave behind a suggestion for a different aspect of Atlas that you want me to zoom in on.

Today, someone asked a question on how to create a master-detail, where the detail was actually related information. Specifically, this person had a list of products, and you could drill-down by clicking on 'comments' to see the comments for that product.

To do this, you could create 2 data sources: the products datasource and the comments datasource. When someone clicks on a comment button of a product, we should first set a ProductID parameter on the comments datasource, which it will pass to the select method on the server. After this property is set, we should actually invoke the select method of that datasource. That's it, basically. The code for this should be something like this:

ASP.NET:
1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
23 
24 
25 
26 
27 
28 
29 
30 
31 
32 
33 
34 

<dataSource id="productDataSource" serviceURL="Products.asmx" />
<dataSource id="commentsDataSource" serviceURL="Comments.asmx" />

<listView id="productListView" ....>
  <bindings>
    <binding dataContext="productDataSource" dataPath="data" property="data" />
  </bindings>
  [...]
      <label id="nameLabel">
        <bindings>
          <binding dataPath="ProductName" property="text" />
        </bindings>
      </label>
      <button id="commentsButton">
        <click>
          <setProperty target="commentsDataSource" property="selectParameters" 
            propertyKey="ProductID">
            <bindings>
              <binding dataPath="sender.dataContext.ProductID" property="value" />
            </bindings>
          </setProperty>
          <invokeMethod target="commentsDataSource" method="select" />
        </click>
      </button>
  [...]
</listView>
[...]
<listView id="commentsListView">
  <bindings>
    <binding dataContext="commentsDataSource" dataPath="data" property="data" />
  </bindings>
  [...]
</listView>
[...]

The interesting bit is probably the dataPath in our binding between ProductID and value. Actions (such as setProperty and invokeMethod) have their own data context, to allow you to bind to for example event arguments for the event that was raised. However, we are interested in the data context that holds the product data. There are really at least two ways you can get to that data context: either by using the sender's data context (as shown above), or by explicitly setting the data context of our binding to for example our button control. The latter would look like this:

ASP.NET:
1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
13 

[...]
      <button id="commentsButton">
        <click>
          <setProperty target="commentsDataSource" property="selectParameters" 
            propertyKey="ProductID">
            <bindings>
              <binding dataContext="commentsButton" dataPath="dataContext.ProductID" property="value" />
            </bindings>
          </setProperty>
          <invokeMethod target="commentsDataSource" method="select" />
        </click>
      </button>
[...]

Hopefully this answers some questions with relation to bindings and ways to create a drill-down scenario.

Someone on the Atlas forums was interested in an Atlas progress bar. So, I went ahead and wrote a basic, client-side Atlas progress bar. If you want, you can also download the source.

So, what is involved to build such a control? Not a hell'u'valot, really.

Step 1: Derive from Web.UI.Control
First of all, you will want to derive from the base Atlas control class, Web.UI.Control. It contains some plumbing for you, such as associating itself with an HTML element. Additionally, you should register your type to make it possible to instantiate it declaratively. In this case, we will register our type with the namespace 'script' and the tagname 'progressBar'. You should also register your class, so Atlas can do its thing, such as describing what the base type is, etc.

JavaScript:
1 
2 
3 
4 
5 
6 
7 

Web.UI.ProgressBar = function(associatedElement) {
    Web.UI.ProgressBar.initializeBase(this, [associatedElement]);
    
    
}
Type.registerSealedClass('Web.UI.ProgressBar', Web.UI.Control);
Web.TypeDescriptor.addType('script','progressBar', Web.UI.ProgressBar);

Step 2: Make it configurable
Secondly, you will want to add some properties to let a user configure the control. In our case, we will add properties like an interval, the url to the service, and a method that we will call on this service to get the progress. Properties have to follow an exact naming convention: the getter of the property should be a function prefixed with 'get_', and the setter should be prefixed with 'set_' and expect 1 parameter. Additionally, we should add these properties to our control's descriptor. Please see step 4 on how this should be done.

JavaScript:
1 
2 
3 
4 
5 
6 
7 
8 
9 
10 

// Define a 'private field'.
var _serviceURL;

this.get_serviceURL = function() {
    return _serviceURL;
}

this.set_serviceURL = function(value) {
    _serviceURL = value;
}

Step 3: Add a timer that will query the service on every tick
Since we want to query the service n milliseconds, we could just re-use the Web.Timer internally. We should define a delegate to represent the function that we want the timer to invoke on each tick. To be safe, we should make sure we clean up after ourselves when our control is disposed.
Please note that we prevent our control from querying the service multiple times when we are still waiting for a response.

JavaScript:
1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
23 
24 
25 
26 
27 
28 
29 
30 
31 
32 
33 
34 
35 
36 
37 
38 
39 
40 
41 
42 
43 
44 
45 
46 
47 
48 
49 
50 

var _responsePending;
var _timer;
var _tickHandler;

this.initialize = function() {
    Web.UI.ProgressBar.callBaseMethod(this, 'initialize');

    _tickHandler = Function.createDelegate(this, this._onTimerTick);

    // Add our event handler to the tick event of the timer.
    _timer.tick.add(_tickHandler);

    this.set_progress(0);
}

this.dispose = function() {
    if (_timer) {
        // Remove the reference of the timer's tick event to our event handler.
        _timer.tick.remove(_tickHandler);
        _tickHandler = null;
        _timer.dispose();
    }

    // Just to be safe we should explicitly set this to null to make 
    // sure we aren't still referencing the timer.
    _timer = null;

    Web.UI.ProgressBar.callBaseMethod(this, 'dispose');
}

this._onTimerTick = function(sender, eventArgs) {
    if (!_responsePending) {
        _responsePending = true;

        // Asynchronously call the service method. Pass a reference to 
        // this control as the context, so we can use that in our 
        // '_onMethodComplete' callback function.
        Web.Net.ServiceMethodRequest.callMethod(_serviceURL, _serviceMethod, 
            null, _onMethodComplete, null, null, this);
    }
}

function _onMethodComplete(result, response, context) {
    // Get a reference to the control.
    var behavior = context;

    // Update the progress bar.
    behavior.set_progress(result);
    _responsePending = false;
}

Step 4: Add a few methods to control our progress bar
Finally, we should add a few methods to start/stop our progress bar. All we need to do is add a start/stop function that enables/disables the timer. Since we want these to be callable by other objects, we should describe these methods in our control's descriptor.

JavaScript:
1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
13 
14 
15 
16 
17 
18 

this.getDescriptor = function() {
    var td = Web.UI.ProgressBar.callBaseMethod(this, 'getDescriptor');
    td.addProperty('interval', Number);
    td.addProperty('progress', Number);
    td.addProperty('serviceURL', String);
    td.addProperty('serviceMethod', String);
    td.addMethod('start');
    td.addMethod('stop');
    return td;
}

this.start = function() {
    _timer.set_enabled(true);
}

this.stop = function() {
    _timer.set_enabled(false);
}

Step 5: Test our control
Now we're done with our control, we should be able to test it. Once you added a reference to your new script control's file, you should be good to go and use it. Since our progress bar needs to be started explicitly, and since we will want to simulate a task, we should add a few more controls to put together a proper demo.

ASP.NET:
1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
23 
24 
25 
26 
27 
28 
29 
30 
31 
32 
33 
34 
35 
36 

[...]
<div class="progressBarContainer">
  <!-- This div is associated with our progress bar control. -->
  <div id="pb1" class="progressBar"></div>
</div>
[...]

<script type="text/xml-script">
    <page xmlns:script="http://schemas.microsoft.com/xml-script/2005">
        <components>
            <!-- This component can be invoked to actually start a 
                 simulated time-consuming task. -->
            <serviceMethod id="taskService1" url="TaskService.asmx" 
                methodName="StartTask1" />

            <!-- Our progress bar's id should refer to a valid associated 
                 HTML element. -->
            <progressBar id="pb1" interval="500" serviceURL="TaskService.asmx" 
                serviceMethod="GetProgressTask1" />

            <!-- Our button should both start the task and the progress bar. -->            
            <button id="start1">
                <click>
                    <invokeMethod target="taskService1" method="invoke" />
                    <invokeMethod target="pb1" method="start" />
                </click>
            </button>
        </components>
        <references>
            <add src="ScriptLibrary/AtlasUI.js" />
            <add src="ScriptLibrary/AtlasControls.js" />
            <!-- Add a reference to our control. -->
            <add src="ScriptLibrary/ProgressBar.js" />
        </references>
    </