February 2008 - Posts

Before posting another post in the Windows PowerShell domain, I thought it was useful to write down the way to write a simple cmdlet in Visual Studio, with easy iterative debugging support. I've used this recipe myself quite a bit, including in on-stage presentations where you want to avoid messing up things at any cost :-).

 

Step 1 - Create a Class Library project

In Visual Studio, create a new Class Library project in the language of your choice (e.g. C#).

image

 

Step 2 - Import references

Next, we need to reference two assemblies. The first one is the System.Management.Automation assembly from Windows PowerShell. If you've installed the Windows SDK on your machine, you'll find it under %programfiles%\Reference Assemblies\Windows Powershell\v1.0:

image

Add a reference to it:

image

Next, add a reference to System.Configuration.Install because our cmdlet needs installer support in order to register its snap-in (see below):

image

Solution Explorer should look like this now:

image

 

Step 3 - Write the basics of the cmdlet

In the Class1.cs file of your project (feel free to rename obviously), write your first cmdlet by deriving from Cmdlet:

image

Use the smart tip to import System.Management.Automation:

image

Finally implement the basic cmdlet by overriding ProcessRecord:

image

And adding some code to it:

image

Finally don't forget to add the CmdletAttribute to it (in practice use VerbsCommon to get a list of common verbs to be used as the cmdlet verb instead of my "Say" verb below which isn't standard PS vocab):

image

 

Step 5 - Add a snap-in

Snap-ins are used to deploy a set of cmdlets, providers, etc as a management package. Creating one is easy by adding a class deriving from PSSnapIn, which is an abstract class with three properties:

image

Don't forget to attribute it with RunInstaller(true) which requires to import System.ComponentModel:

image

image

 

Step 6 - Build and register the snap-in

Build the solution, and open a Visual Studio Command Prompt running as Administrator. Go to the bin\Debug output folder of your project and invoke installutil -i on the compiled assembly as shown below:

image

 

Step 7 - Set up a debugging console for our snap-in

Now launch Windows PowerShell and invoke get-pssnapin -registered (don't forget -registered!) to see that our registration was successful:

image

In the screenshot above we've also added the snap-in using add-pssnapin MySnapIn and tested it by invoking our say-hello cmdlet. Next we export the console configuration to a psc1 (PowerShell Console v1) file:

image

This is an XML file containing the configuration of a PowerShell console with respect to imported snap-ins, as show below:

image

 

Step 8 - Hook up the debugger

Close Windows PowerShell and go back to our project. Open the Project Properties and go to the Debug tab. In here, specify the program to launch as Windows PowerShell and the arguments to be -PSConsoleFile <path to your debug.psc1 file>:

image

To test, set a breakpoint in our cmdlet and hit F5:

image

Invoke the cmdlet from the started Windows PowerShell instance:

image

The breakpoint is hit! Mission completed...Happy cmdlet debugging!

Del.icio.us | Digg It | Technorati | Blinklist | Furl | reddit | DotNetKicks

Chances are you've already heard about Volta, a project of Microsoft Live Labs. If not, check out their website first at http://labs.live.com/volta/. So, what's the idea? Volta is a new way to build multi-tier web applications in a friction-free way. Wow, sounds almost like marketing, but what do we really mean by friction-free? When building multi-tier web applications today, you have to worry about lots of things at the same time: how many tiers you want and how you want to split them up, what to run in the browser and what on the server, how to take the maximum benefit of the client's capabilities without loosing cross-browser guarantees, etc. All sorts of glue enter the picture from day one: JavaScript, web services and tier communication aspects such as serialization, security, etc. So, what about getting rid of the (tedious) tier splitting task ourselves and leave it to tools and runtime? That's exactly what Volta is all about!

In this introduction I'll show you how to create a basic Volta project (assuming you've downloaded and installed the Volta bits from http://labs.live.com/volta/), while showing you some of the details about the implementation. Fasten your seatbelts!

 

Step 1 - Creating and analyzing the project

After installing Volta, you'll see a new project type in Visual Studio. Let's create a new Volta (Web) Application.

image 

Notice a few things:

  • Volta is a sub-project type for a given (managed) language, I've chosen to use C# in this introduction but you could do the same with VB.
  • The description: "Volta compilation to JavaScript". Despite the fact you'll write code in C#, Volta will perform compile-time translation (compiling is all about translation after all) to client-side JavaScript targeting multiple browsers.

The newly created solution should look like this:

image

Usual web application suspects are Page.html and favicon.ico, but notice these are children of a C# class. Let's open it:

using System;
using Microsoft.LiveLabs.Volta.Html;
using Microsoft.LiveLabs.Volta.Xml;

namespace VoltaApplication1
{
    public partial class VoltaPage1 : Page
    {
        public VoltaPage1()
        {
            InitializeComponent();
        }
    }
}

Despite some Volta-specific namespace imports, this is not really mind-blowing. Partial classes for some designer-supported project item type are common business. Let's dive a little deeper, what's InitializeComponent?

image

using Microsoft.LiveLabs.Volta;

[assembly: StartPage("Page.html")]
[assembly: VoltaFile("favicon.ico")]

namespace VoltaApplication1
{
    public partial class VoltaPage1
    {
        partial void InitializeComponent();
    }
}

The other side of the partial class curtain is more appealing it seems: a few attributes denoting some files and the project's start page as well as the use of a C# 3.0 specific feature: partial methods, meaning we can provide our own implementation of InitializeComponent on the other side, which we'll do in a second. But first things first: some HTML.

 

Step 2 - Creating the HTML page

Before I continue let me point out we're really talking about raw HTML. No ASP.NET magic or so. The reason? Volta doesn't know much about server-side technologies such as ASP.NET at the moment (it's a preview after all) and focuses primarily on the tier splitting problem for the moment. This being said, let's open up the Page.html file and create a simple calculator interface using the VS 2008 designer:

image

No JavaScript in the proximity so far. The good thing: you won't see any of it (except for the time we look at what's being generated). Now that we have the HTML page, we need to establish a connection to the elements on it in our C# code.

 

Step 3 - Extending our Volta page class

Our VoltaPage1.cs file will contain all the logic that drives the page's functionality. As pointed out in Step 1, there's one extensibility point to start from: the InitializeComponent partial method. Let's implement it as follows:

private Input _a;
private Input _b;
private Input _add;
private Input _multiply;
private Button _button;
private Div _result;

partial void InitializeComponent()
{
    _a = this.Document.GetById<Input>("a");
    _b = this.Document.GetById<Input>("b");
    _add = this.Document.GetById<Input>("plus");
    _multiply = this.Document.GetById<Input>("prod");
    _button = this.Document.GetById<Button>("calc");
    _button.Click += new HtmlEventHandler(_button_Click);

    _result = this.Document.GetById<Div>("res");
}

void _button_Click()
{
}

Notice the signature of InitializeComponent, using the partial keyword. This indicates we're implementing the partial method as outlined in my post on the topic. What's going on inside is more interesting: we retrieve the strong typed objects representing HTML elements in our C# code using GetById calls:

image

As you can see, elements that can be retrieved by name are all HtmlElement subclasses. Samples include Input, Button and Div as used in our sample. Also, notice that these elements have typical events associated with them:

image

which are exposed as regular events in managed languages, so easy to consume. Despite the fact we're writing managed code though, Volta will take care of doing the right thing to make this functionality available on the client directly using JavaScript, as we'll see in a minute.

 

Step 4 - A first test

Let's implement our button's Click event handler in a straightforward way first:

void _button_Click()
{
    _result.InnerText = "Hello";
}

Hit F5 and notice a mini webserver is spawn as shown in the notification area:

image

You can double-click if you want to get some info:

image

Pretty empty but in the meantime a browser instance should be opened:

image

When you hit Calculate nothing too exciting happens (yet) but the Hello text will appear in the div element:

image

Believe it or not, this by itself is already quite a task... Remember we didn't write any piece of JavaScript whatsoever and when you take a look back at the Volta WebServer window, you won't see new requests coming in, so there hasn't been a roundtrip to the server (you could even kill the web server and the page should still work - at least for now since we didn't split tiers yet)...

 

Step 5 - Gaining some basic understanding

So, what's going on? Take a look at the source (right-click, View Source) for the page:

image

I've indicated the most important part (I'll explain later why this statement is not really true :-)) of the page in Red: a seemingly innocent JavaScript script import. In order to view it, open up Windows Explorer and navigate to your solution folder and descent the bin\Debug\Volta path:

image

Page.html is what we're looking at in the browser (the reason it loads up in the browser is that it has been marked as the start page in the StartPageAttribute we noticed in Step 1). Compact.js isn't particularly interesting for now and implements support for non-IE browsers. The real stuff for our app seems to be going on in VoltaManagedInteropHelpers.js. Feel free to take a look at it, but you won't really see why things work the way they do. The reason for this is we're running in Debug mode, which injects the VoltaManagedInteropHelpers that take care of the debugging plumbing. Nevertheless, this is quite interesting by itself since you can set breakpoints in your C# code and see them getting triggered when performing operations in the browser:

image

I won't go in JavaScript debugging for now, but the debugger hooks used by Volta are definitely quite interesting for geeks :-). Just remember you're essentially seeing a fata morgana: C# isn't what it really is (JavaScript). To see the real "pure" application in all its glory, quit the browser and flip to Release mode in VS:

image

Notice you can choose to target another browser as well. When you run the application now, the page source will look quite different:

image

The plumbing is a bit bigger now, but the core isn't too difficult to understand. Notice the presence of a loader.js file which is referenced in the page source:

image

Feel free to take a look at it, what you'll see is a nice mechanism to establish communication with a server-side component to grab type definitions from the server on demand. The handler for that is living in jsfile.aspx:

<%@ Page Inherits="Microsoft.LiveLabs.Volta.Handler.JSILHandler, VoltaHandler, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" EnableSessionState="False" AutoEventWireup="false" EnableViewState="false" LinePragmas="false" ValidateRequest="true" %>

which is called the JSILHandler (JS = JavaScript, IL = Intermediate Language). The loader itself has various ways to get type definitions from the server over plain HTTP requests or using XMLHTTP (AJAX style). Without going in details, it suffices to say that the loader is used to grab the "VoltaApplication1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" assembly from the server, which lives - surprisingly - in the "VoltaApplication1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" folder. This is where things get more interesting. Before looking at the types, it may be worthwhile to take a look at the Volta server request logging output to see how types are loaded from the server:

image

Now, switch back to Windows Explorer to analyze the generated JavaScript source folder.

image

Assembly.js is the place where the assembly is defined: what dependencies it imports (VoltaHtml, mscorlib), the types it defines etc and where the entry point lives. After some formatting and outline of the JS file, you should read something like this (the reason for the dense emitted file is download size):

var Assembly = {
   Name:"VoltaApplication1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null",
   TypeDefs:{},
   TypeRefs:{},
   Instances:{},
   References:{
      cA:(function()
      {
         return LoadAssembly("VoltaHtml, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35");
      }),
      cB:(function()
      {
         return LoadAssembly("mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
      })
   }
};

Assembly["EntryPoint"] = (function()
{
   var kA = GetTypeDef(Assembly, "VoltaApplication1.Program");
   var mA = kA.Methods.eA;
   return mA.apply(arguments);
}
);

Assemblies[Assembly.Name] = Assembly;

Assembly.RegisterExports = (function()
{
}
);

As you can see, our application has an entry-point defined in VoltaApplication1.Program, which listens to the telling name of kA.Methods.eA. When hitting the entry-point through the Assembly["EntryPoint"] (triggered by window.onload that calls a.EntryPoint() where a is the loaded assembly), this eA method is called. But what's eA? It's an abbreviation for some mapped method defined in our C# code. But before getting into methods, let's look at types: what's kA really? It's defined as GetTypeDef on VoltaApplication1.Program, but internally some other mapping is going on in typeMappings.js:

var Assembly = LoadAssembly("VoltaApplication1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null");

Assembly.TypeMappings = {
   "VoltaApplication1.Program":"tA",
   "VoltaApplication1.VoltaPage1":"tB"
};

The reason this is important is to find out about the mapped JS file for the type in the Types folder:

image

To find the entry-point, we'll have to look at tA.js as inferred from the TypeMappings in the previous fragment. Feel free to open it, but our own logic in VoltaPage1 (mapped onto tB.js) seems more attractive for inspection in this post:

image

Frightening? Not really, one we have some nicer outlining :-). The nice thing is this should be the first and last time you read this contents of such a file (I like to guide people in unknown territory don't I?). Essentially the file represents all the details of the type, including methods, vtables (ever thought to see a vtable in JavaScript?), type initializers, etc:

image

For example, our VoltaPage1 type has been mapped on lB. The method table looks like this (and is hooked up a little further):

image

You'll recognize stuff for our event handler and our private member fields. Also add_Click (mE) is called fE (which corresponds to calc) passing in eL, which points at the following:

image

Here the real work happens, calling mA which maps onto set_InnerText on kA, an HtmlElement (that happens to be our <Div> tag retrieved using GetElementById<T>), and finally "Hello" is fed in. Enough JSIL joys for now (scroll a little further down to see the VTable for System.Object methods gang of four), let's go back to the user level and wire up our calculator.

 

Step 6 - Building and hooking up the calculator

Building the calculator is simple and it may be even insulting to show the sources, but I'm still gonna do it:

using System;

namespace VoltaApplication1
{
    public class Calculator
    {
        public int Add(int a, int b) { return a + b; }
        public int Multiply(int a, int b) { return a * b; }
    }
}

A simple page implementation invoking a calculator operation is:

void _button_Click()
{
    int a = int.Parse(_a.Value);
    int b = int.Parse(_b.Value);
    _result.InnerText = _calc.Add(a, b).ToString();
}

where _calc is an instance of our Calculator class that can be stored as a private field and initialized in the constructor. More fancy stuff such as the use of TryParse requires quite some complex transformations which aren't possible today though. I'll leave it to the reader to add some switching logic to determine the operation and invoke the right calculator method based on that.

However, the little piece of code above already allows us to show a few more details of Volta. First of all, in the Types folder you'll now see another type file:

image

Without sanitizing the source, it looks like this:

image

It's not too hard to spot the methods for Add and Multiply. It's important to realize that this piece of code maps onto JavaScript nicely. I invite you to try some more complicated logic and see how it maps onto JavaScript; it's not very difficult to predict what a call like this will map into (assuming the reader has some basic knowledge of JavaScript):

Window.Alert("Hello");

 

Step 7 - Splitting tiers

Okay, we talked about one of the main objects of Volta to be tier splitting. Let's make it somewhat more concrete now. The fact Volta can control what to emit on the client is the key to its power. All it needs is a little push to do the right thing and metadata is a natural choice to do this. This first thing though to make this happen is to enable tier splitting in the project properties:

image

This will add a reference to VoltaMultiTier to the project references:

image

Now switch back to the Calculator class and change it as follows:

using System;
using Microsoft.LiveLabs.Volta.MultiTier;

namespace VoltaApplication1
{
    [RunAtOrigin]
    public class Calculator
    {
        public int Add(int a, int b) { return a + b; }
        public int Multiply(int a, int b) { return a * b; }
    }
}

The key to tier splitting is in the RunAt attributes, in this case we use RunAtOrigin meaning we leave execution on the server as opposed to run it in client-side script. Executing the app still produces the right result:

image

but when looking in the Volta server request log, we'll see a request being made:

image

The file is called __TierSplit.aspx, so let's take a look at the output folder:

image

TierSplit hooks up the tier splitter service dispatcher from Volta:

<%@ Page Inherits="__Volta.__ServiceDispatcher, VoltaApplication1.Server" EnableSessionState="true" AutoEventWireup="false" EnableViewState="false" LinePragmas="false" ValidateRequest="true" %>

Using RunAt attributes you can make the life of the "dispatcher" much harder but we won't go down that route now. Just remember this is the entry point for remote operations that have to be executed on a server (service) tier. Also notice the appearance of the VoltaApplication1.Client assembly, which is referred to by Page.html now. In there you'll find the typical assembly.js and typeMappings.js files, as well as the type definitions which have grown to a total of five now. If you're interested, it's a worthwhile exercise to make sense of the JSIL in there. For our discussion it's sufficient to say that the new files hook up a few important MultiTier Volta types such as Microsoft.LiveLabs.Volta.MultiTier.Proxy, Microsoft.LiveLabs.Volta.MultiTier.ServiceLocation and Microsoft.LiveLabs.Volta.MultiTier.ClientMap as well as serialization stuff.

Another part of the multi-tier story lives in the bin folder where - surprisingly? - an assembly is emitted that contains our server-side functionality that's invoked through the dispatcher. It looks like this:

image

Essentially, the __ServiceDispatcher constructs the service object:

image

which holds the Add and Multiply methods that can be called remotely.

 

Step 8 - It's an asynchronous web

But what if the remote operation blocks due to expensive database operations or so? That's where asynchronous invocation comes into play. Again this is made easy through metadata tagging, this time on the method level:

using System;
using Microsoft.LiveLabs.Volta.MultiTier;

namespace VoltaApplication1
{
    [RunAtOrigin]
    public class Calculator
    {
        [Async]
        public int Add(int a, int b) { return a + b; }

        [Async]
        public int Multiply(int a, int b) { return a * b; }
    }
}

However, this won't work since asynchronous invocation requires another method signature. Instead, we'll create a blend of synchronous and asynchronous methods and leave the implementation of the asynchronous plumbing to Volta:

using System;
using Microsoft.LiveLabs.Volta.MultiTier;

namespace VoltaApplication1
{
    [RunAtOrigin]
    public class Calculator
    {
        public int Add(int a, int b) { return a + b; }
        public int Multiply(int a, int b) { return a * b; }

        [Async]
        public extern void Add(int a, int b, Callback<int> callback);
        [Async]
        public extern void Multiply(int a, int b, Callback<int> callback);
    }
}

Notice the use of the extern keyword, we leave it to Volta to come up with the right implementation and hint to create one by providing the Async attribute. You won't find the asynchronous stuff in the assembly, instead the type mappings will grow because of the addition of a AsyncCall method (I challenge you to spot it in the JSIL). To make it work asynchronously we'll need to change our page implementation slightly as follows:

void _button_Click()
{
    int a = int.Parse(_a.Value);
    int b = int.Parse(_b.Value);
    _calc.Add(a, b, result => { _result.InnerText = result.ToString(); });
}

In here we use a lambda expression to write the callback function:

result => { _result.InnerText = result.ToString(); }

result is the lambda parameter of type int (since Add takes in a Callback<int>) and the lambda body simply executes the callback code that makes the result visible. To put it in a broader perspective, Callback<T> is essentially the same as Action<T>:

public delegate void Callback<T>(T returnValue);

To see the difference between synchronous and asynchronous you could try to add a Thread.Sleep call to the Add method. In the synchronous case you'll see the Calculate button hang during the remote invocation, while the asynchronous invocation keeps the browser application nicely alive. This is what you'll see in the web server log:

image

Notice the XMLHttpRequest being made and the answer travelling back 5 seconds later in a POST, when using the following Add method definition:

public int Add(int a, int b) { Thread.Sleep(5000); return a + b; }

 

Conclusion

Volta is an interesting evolution in the way one can think about the creation of multi-tier web applications where plumbing is abstracted away nicely and where developers can leverage their existing .NET programming skills without having to worry about JavaScript in order to get the most out of the client's capabilities. Although Volta is in an early stage at the moment, I'd encourage web development enthusiasts to give it a shot at http://labs.live.com/volta/. I hope to have satisfied the geeks out there by giving some more insight in the hows of Volta and JSIL. Of course, the low-level details aren't really required to work with Volta but as usual I believe a somewhat deeper understanding helps to absorb the magic provided by the system.

Del.icio.us | Digg It | Technorati | Blinklist | Furl | reddit | DotNetKicks

More Posts « Previous page