Friday, October 29, 2010

Today we have shipped the first release of WCF Web APIs on wcf.codeplex.com. WCF Web APIs is a set of open source components that make it easy to develop WCF web services that target web and HTTP clients, including JavaScript Ajax applications running in a browser.

One of the components is WCF support for jQuery. It provides great Visual Studio experience for creating WCF services that are optimized for consumption from JavaScript clients running in a browser, in particular jQuery. This includes better support for the JSON format as well as application/x-www-form-urlencoded data. Submitting an HTML form to a WCF service with an Ajax call from jQuery has never been easier. Let’s have a look at the feature.

Installation

You must have Visual Studio 2010 to use the bits. Downloading and installing the WCF Support for jQuery 10.10.27 release from wcf.codeplex.com will install Visual Studio templates, as well as copy reference files and samples to %ProgramFiles%\Microsoft SDKs\WCF Support for jQuery.

Visual Studio project template

Create a new project and choose the “WCF jQuery Service Application” template in the “Web” group:

The template creates a web application project that contains a WCF service (WcfJQueryService.cs) and a sample HTML page that demonstrates how to invoke that service with an Ajax call using jQuery (default.htm):

The project references include two assemblies that have been installed as part of the WCF Support for jQuery release (you get get the source code of these assemblies from the wcf.codeplex.com site). System.Runtime.Serialization.Json.dll contains the JsonValue component which facilitates operating on JSON data in an untyped manner (JsonValue is to JSON what XElement is to XML). JsonValue supports serialization and deserialization to the JSON format. It has already shipped in Silverlight before, now we are porting it with some enhancements to .NET Framework.

The Microsoft.ServiceModel.Web.jQuery.dll contains a number of WCF components that integrate JsonValue with the WCF HTTP programming model, and add support for processing JSON and application/x-www-form-urlencoded data, which are the two most commonly used data formats for Ajax calls in JavaScript applications.

The WCF Support for jQuery package also includes an item template that allows a jQuery-enabled WCF service to be added to an existing web application project.

From jQuery client to WCF service

Let’s have a look at the WCF service to see what the programming experience is:

[WebInvoke(UriTemplate = "", Method = "POST")]

publicJsonValue Post(JsonObject body)

{

dynamic item = body;

item.id = items.Count;

items.Add(item);

return items[items.Count - 1];

}

The method above is extending the WCF HTTP programming model available since .NET Framework 3.5 SP1 with support for JsonValue as the method parameter and return value type. If JSON or application/x-www-form-urlencoded data arrives in the body of the POST request, it will be deserialized into the JsonObject instance passed to the Post method. The JsonValue instance the method returns will be serialized into JSON format on the HTTP response.

The default.html file shows how this method can be called from JavaScript, in this case using the Ajax call from the jQuery framework:

var person = {

Name: "John Doe",

Age: 21

};

$.post("./Service/", person, function (result) {

//...

});

In line 1-4 a JavaScript object ‘person’ is created. Line 5 initiates a POST HTTP request to the WCF service identified with a relative ‘./Service/’ URL, and passes the ‘person’ instance to be sent to the service. By default, jQuery serializes the JavaScript object using the application/x-www-form-urlencoded format. The HTTP request looks like the one below, with line 4 containing the serialized ‘person’ instance:

POST http://127.0.0.1:8326/Service/ HTTP/1.1

Content-Type: application/x-www-form-urlencoded

Name=John+Doe&Age=21

The interesting aspect of WCF support for application/url-form-encoded is that JavaScript applications can use that format to serialize not only simple lists of key/value pairs traditionally associated with an HTML form submission, but also arbitrarily complex JavaScript objects. JsonValue supports deserialization of data from application/x-www-form-urlencoded format following the jQuery’s $.param() serialization conventions. To see this format in action, let’s send a more complex object to the server by modifying the ‘person’ instance to:

var person = {

Name: "John Doe",

Age: 21,

Children: [

{

Name: "Jessica",

BestToy: "Fish"

},

{

Name: "Jeff",

BestToy: "Donkey"

}

]

};

The corresponding HTTP request with this data is shown below, with line 4 containing the complex ‘person’ structure serialized into an application/x-www-form-urlencoded format using the $.param() convention from jQuery:

Although jQuery Ajax calls use application/x-www-form-urlencoded format by default, it is very easy to serialize the request payload in JSON format instead. Using Douglas Crockford’s json2 serializer (line 4), one can make a jQuery call like this:

A great feature of the JsonValue programming model in WCF is that regardless of the client’s choice of JSON or application/x-www-form-urlencoded as the serialization format for the request, WCF will deserialize and normalize the data into an instance of JsonValue. Given that, the application code may stay decoupled from the protocol.

So how does one access the data the client sent from the WCF service? JsonValue offers dictionary-like programming model. For example, to determine the favorite toy of the second child of the person, one could write the following code:

If the return type of a WCF method is JsonValue, the response content type is always application/json. Note that in line 5 above we are actually returning a string instance, but an implicit cast exists between a number of primitive data types and JsonValue. In this case the specific HTTP response would look as follows:

HTTP/1.1 200 OK

Content-Type: application/json; charset=utf-8

"Donkey"

Surely enough, donkey is the favorite toy of John’s second child.

JsonValue 201: dynamic properties

JsonValue supports a few more interesting constructs that facilitate operating on untyped data.

First of all, there is support for dynamic properties, which is more than just a syntactic improvement over array indexers. The two lines below extract the same value from a JsonObject:

The notation in line 2 is closer to the code one would expect to write to navigate an object in JavaScript, and some people find it more natural than using indexers in line 1.

Given that the data received from the client has not been validated against a specific schema of a CLR type, one cannot be sure the JsonObject really contains the data the server application expects, or whether the object even has the correct structure. For example, a malicious client could try to send an arbitrary string in the “Age” field instead of a number, or could completely omit the Children array. In that case, the indexer APIs (line 1 above) would throw an exception as soon as the code attempts to access a non-existing property (which is consistent with the behavior of indexers in the .NET Framework in general). One would therefore have to write a lot of validation code before accessing the data in the JsonValue object using indexers, especially if the data hierarchy is deep.

The dynamic properties of JsonValue offer a much more convenient validation experience. One can “dot into” any level of a complex object without any exceptions being thrown, only to perform a test of the value’s existence and CLR type match at the very end, with a very Fluent-like experience.

JsonObject body;

string aValue;

if (!body.AsDynamic().Children[7].BestToy.TryReadAs<string>(out aValue))

{

aValue = "None"; // assume a default value

}

You can imagine how this programming model is reducing the amount of code you need to write when navigating deep data hierarchies:

JsonValue 301: LINQ to JSON

Here is another useful feature JsonValue offers: LINQ to JSON. Using the ‘person’ object introduced above, let’s assume you are writing a method that is supposed to return the favorite toys of those children of the person whose name begin with ‘J’ (does this sound like a test from your SQL class?). Here is the code you could write:

JsonObject body;

string[] favoriteToys =

(from child in (JsonValue)body.AsDynamic().Children

where child.Value.AsDynamic().Name.ReadAs<string>(string.Empty).StartsWith("J")

You don’t have to worry whether the ‘Children’ property exists on the ‘body’ JsonObject (line 3), or whether it is a JSON array. If it does not, the LINQ expression will just not return any matches. No exception is going to be thrown.

You don’t have to worry whether the ‘Name’ property exists on a child object (line 4). Instead, you can provide a default name in the ReadAs method that will be returned in the absence of the property.

Similarly, in case a child whose name starts with ‘J’ has been found, you don’t have to worry whether the child has a ‘BestToy’ property (line 5) – if she does not, you can just fall back to returning a ‘No favorite toy’ string.

In other words, writing compact and robust LINQ expressions against JSON data with unknown structure is easy.

Read more

I have only touched on the key features of the WCF support for jQuery release. Find out more in the dedicated documentation section on wcf.codeplex.com. Let us know what you think and help us shape the direction of this feature going forward.

If you haven’t had a chance to watch Glenn Block’s talk at PDC 2010 that explains what we are doing and why, make sure to check it out. At the high level, these are the components available in our first Codeplex release (and there are more to come):

WCF Support for jQuery: components that facilitate creating WCF web services that are optimized for consumption from JavaScript clients running in a browser, in particular jQuery. This includes better support for the JSON format as well as application/x-www-form-urlencoded. Read more about this feature on my next blog post.

WCF HTTP: a brand new WCF HTTP processing stack that makes programming WCF web services easy with a set first class concepts and utilities targeting the HTTP protocol. Read more about this aspect at Glenn Block’s blog.

Domain Service support for Windows Azure Table Storage. When hosting WCF RIA Services in Windows Azure, you can now easily leverage Windows Azure Table Storage as your data backend. Read more at Kyle McClellan’s blog.

T4 template based client code generation. The feature leverages the code generation extensibility point added to the product and provides a well factored and granular mechanism to customize client code generation logic using T4 templates. Read more at Varun Puranik’s blog.

The goal of the open source Laharsub project is to provide a solution that makes it easy for web applications to organize internet scale message exchange using a publish/subscribe pattern. The project is an ongoing experiment with a variety of web technologies. Current focus is on AJAX (in particular jQuery) and Silverlight clients, a REST based HTTP long polling subscription protocol implemented by a .NET WCF HTTP middle tier service, and researching middle tier and back end technologies that enable scale-out to a large number of clients.

Laharsub 2010.10.09 release provides the Laharsub service based on WCF HTTP service, an in-memory pub\sub backend implementation, and three client implementations: jQuery, Silverlight, and .NET.

Methodology

The test scenario used for the purpose of performance measurements simulates a chat/collaboration message exchange pattern. The server maintains a specified number of topics. Each topic has the same number of unique clients acting both as publishers and subscribers of the topic. Each of the clients is publishing messages to the topic at specified frequency. Upon receiving a message published to a topic, the Laharsub server sends notifications containing this message to all subscribers of the topic (including the client which published the message).

The following three configurations were tested:

Variations in the number of topics, with 2 clients per topic, each publishing messages to the topic every 1 second.

Variations in the number of topics, with 2 clients per topic, each publishing messages to the topic every 5 seconds.

Variations in the number of topics, with 5 clients per topic, each publishing messages to the topic every 15 seconds.

The key quality of service metric of every measurement is the roundtrip latency of a message, measured as the time elapsed between the moment a message was published to a topic by a client and the moment the message was received by a client subscribing to that topic. In the context of a chat scenario, this is the time required for a message typed into a messaging client to reach the other participant or participants of the chat.

The client application simulating the chat/collaboration scenario is called LoadTestClient.exe and is included in the Laharsub release. Each run of the test lasts 30 seconds, preceded by 10 seconds of a warm-up operation intended for the system to reach a steady state. Measurements are recorded only after the warm-up period. Every message published to a topic is 10 bytes long and consists of a timestamp representing the moment the message was created on the client that publishes it. When a client subscribing to the topic receives that message, it calculates the time elapsed from its creation and records this data as a single measurement. In the course of the 30 second test run, a large number of measurements are recorded. Arithmetic average and standard deviation of the latency are calculated from all these measurements for a given variation.

The tests have been run in the following environment:

The Laharsub.exe server was running as a console application on a 64 bit Windows 2008 R2 operating system on a Intel Quad Core 2.4GHz machine with 4GB of RAM and a 100MB/s network card.

There were two client machines used in every variation (except one involving a single topic, in which case a single machine was used). Each machine was running LoadTestClient.exe on a 32 bit Windows 7 Ultimate operating system on an Intel Dual Core 2.2GHz with 2GB of RAM and a 100MB/s network card.

The two client machines and the server were on a local network connected with a 100MB/s switch.

For each test variation testes the following metrics were gathered:

Average and standard deviation of notification latency, as described above.

Average memory utilization of the Laharsub.exe server (private bytes).

Average network utilization of the server machine.

There are numerous factors that affect latency of message delivery as well as other metrics, and it is certain most of them are going to be different in a production environment than the test environment described above. Therefore only consider the results discussed below as a general guidance, and measure performance of the Laharsub server in your particular application. In particular, it is to be expected the network environment (e.g. distance between the clients and the server) are going to be a major factor that impacts message latency. In that sense, the test environment above represents close to an ideal case for achieving low notification latency.

Latency

Average latency measured for all of the variations of each of the test configurations are presented on Figure 1 below.

It must be noted that the Laharsub server was not the bottleneck of scalability to a larger number of concurrent clients in any of the variations depicted on Figure 1. In every case the bottleneck was CPU utilization on the client machine. (Unfortunately I do not have more client machines at my disposal to try to load the network or the server). Server utilization is discussed more in the following sections.

Apart from average notification latency, standard deviation of the latency measurements shown on Figure 2 provides more insight into the overall quality of service.

It is apparent from the two graphs that the average and standard deviation of notification latencies are correlated. Figure 3 and Figure 4 provide a more graphical representation of the distribution of latency measurements for individual notifications for points identified as A and B on Figure 1, respectively.

One interesting observation about the notification distribution in time is the apparent arrival of several notifications at the same moment. This observation demonstrates the benefit of Laharsub protocol multiplexing several topic subscriptions on a single HTTP long poll request, which in turn causes several notification to be sent back to client on a single HTTP long poll response. These notifications appear to arrive at the same time since the start of the measurement. If the multiplexing optimization was absent, these notifications would require a separate HTTP long poll response each, which in turn would increase the average notification latency.

Detailed measurements

As mentioned before, three configurations were tested:

Variations in the number of topics, with 2 clients per topic, each publishing messages to the topic every 1 second.

Variations in the number of topics, with 2 clients per topic, each publishing messages to the topic every 5 seconds.

Variations in the number of topics, with 5 clients per topic, each publishing messages to the topic every 15 seconds.

Details of average and standard deviation of the latency, as well as memory and network utilization on the server for all of the configurations above are presented on Figure 5, 6, and 7 below, respectively.

One interesting observation is that network utilization (as measured on the server) in every configuration grows linearly with the number of concurrent clients. This should not be surprising, given a fixed message size and fixed publication frequency in all of the above configurations.

The data above also seems to suggest the average and standard deviation of notification latency grows non-linearly with the number of concurrent clients, an effect that is further amplified by a more higher publication frequency.

Server memory

Consumption of memory by the server process (private bytes) for the three configuration tested is shown on Figure 8.

It appears that memory consumption grows linearly with the number of concurrent clients in each of the three configurations. There appear to be two factors affecting memory consumption: concurrent connections on the server, and the number of messages held in memory by the server. In the test scenario, the memory consumed by messages stored in memory is negligable, provided the 10 byte size of every message and the configured message TTL of 15 seconds. It is to be expected that message size and TTL may contribute substantially to the memory consumption in other deployments. The memory cost of supporting a specific number of concurrent clients (concurrent TCP connections) is independent of the message size.

Network utilization

Network utilization as measured on the server for all three test configurations is shown on Figure 9 below.

It is not surprising that network utilization grows linearly with the number of messages exchanged. One aspect to be noted is that despite the relatively large overhead of the HTTP protocol over the body payload (10 bytes) in the HTTP long polling protocol that the Laharsub server is using, in none of the configurations did the network utilization of a 100MB/s interface exceed 18%. As discussed before, this is partially due to the subscription and notification multiplexing on a single HTTP long poll request.

Laharsub pub\sub server based on .NET 4.0 WCF HTTP service that implements the REST publish/subscrive APIs for creating topics, publishing to a topic, and subscribing to topics. The implementation uses HTTP long polling protocol with subscription multiplexing for improved performance.

My name is Tomasz Janczuk. I am currently working on my own venture - Mobile Chapters (http://mobilechapters.com). Formerly at Microsoft (12 years), focusing on node.js, JavaScript, Windows Azure, and .NET Framework.