Hosting a Full-Browser Silverlight App on SLS

It’s been three or four days of wierd, difficult to diagnose problems with Silverlight and topics related to it. The latest one involved Microsoft’s free Silverlight hosting service at Silverlight Live Streaming. It’s damned nice of MS to offer Silverlight developers up to 10 free gigs of storage and streaming support. In my case I have a Linux server on Network Solutions, which I could use to deploy my Silverlight work, however to do so requires modifying the mime types the server supports. I don’t have that level of access, so SLS was just the ticket. Or so I thought about three hours ago when I started trying to deploy and link to it.

As it turned out I had written the kind of application that doesn’t play well on SLS: one that expects to fill the browser window and follow size changes on the client. The way SLS works is that you upload the application’s XAP file to the server, and then either use an embedded iframe to invoke it, or controls that generate an embedded iframe. Either way you get an iframe. I know. An iframe. Whatever. The problem is that I needed my iframe to respect width:100% and height:100%… and that has long been a problem with iframes. They’re fine with the width mandate, but ignore the height. If you have an app with a fixed size you can simply configure that size in the SLS application configuration panel, and all is well.

But in order to solve the problem for a full-browser application I had to provide some javascript in the page that resizes the iframe’s height style attribute dynamically. If you’re interested in this solution, you can read about it in detail on the Silverlight.net forums.

A Google Image Memory Game in Silverlight 2

I finally completed and deployed the Silverlight 2 game I have been working on for the last few days. I don’t think it will win any awards for game design, but it allowed me to explore a pretty wide swath of Microsoft’s second generation Flash competitor. I like the idea of Silverlight, for the simple reason that I want to do rich Internet apps, but I don’t want to learn ActionScript. I have nothing against Flash: it’s an amazing product with huge market share. Hell, its market share is so huge you really can’t call it a “share.” They have the whole market.

But… Silverlight is built on the .NET technology stack, which makes it immediately accessible to any developer with experience writing Windows Forms or ASP.NET applications. It leverages the concepts introduced with Windows Presentation Foundation in .NET 3.0 to essentially run sandboxed WPF apps in a web browser. It does what Flash does, more or less, on the .NET stack. Will it take off? I have no idea. I suspect that if people write cool stuff for it then it will. I doubt it will ever knock Flash off its pedestal, but it might garner a fair chunk of the market.

The game, which you can play here or by clicking the screenshot above, accepts a query term or terms, then searches Google Images on those terms and arranges the resulting images into a classic “memory” game grid. You play by clicking the tiles to reveal the images, and trying to match them up. In the process of writing it I worked with animations and storyboards, asynchronous calls to RESTful web services, json data serialization, and other interesting areas of the SL2 framework that I will write about in future posts. I also ran into numerous quirks and curiosities in the framework, as well as in the Silverlight Live Streaming service that I chose to host this game. The technology is not without warts, but it is very early in the development cycle, and I’m excited to see what the Silverlight team will be bringing us down the road.

Download the GMemory source code and project files.

Where You Test a Silverlight App Matters

I recently had to find the cause of a puzzling error in the Silverlight 2.0 game I am working on. The game uses Image controls to load pictures returned from Google image search. To load a picture I first create a new Uri object containing the address of the image, then use it to construct a BitmapImage object. I wire up a handler for the BitmapImage.DownloadProgressChanged event, as well as the Image.ImageFailed event, and then set the ImageSource property of the Image control to reference the new BitmapImage. All very straightforward, and it worked fine while I was referencing a test image (.png) located on my local disk (in /Bin/Debug/images).

However, once I got the Google search part working and started to pass http: addresses to my algorithm things went south. Every attempt to load an image failed and invoked my ImageFailed handler with an AG_E_NETWORK_ERROR exception. If you do much Silverlight programming with images I predict you will come to hate this particular error code, and I do hope the dev team replaces it with something more informative. Anyway, this was quite puzzling. I checked the URLs manually and each referenced a valid image that I could pull up in a browser. So what was the problem?

After doing a little research on the Silverlight.net forums user IanBlackburn jumped in and pointed me to a helpful post on URL access restrictions in Silverlight 2. At first glance this didn’t clear up anything for me. The document states that image URLs are allowed to be cross-domain, so that wasn’ t it. A little more discussion and a closer reading and it suddenly dawned on me that while images could be cross-domain, they couldn’t be cross-scheme. What this means is that if your app is located at an http: address, for example, you can’t pull images from an https: address. It also means that if your app is located at a file: address you can’t pull images from an http: address.

Aha. See, when you create a Silverlight project in Visual Studio the default behavior is to create a TestPage.html at /Bin/Debug and embed your component in it. When you run the app to debug it is passed to the browser instance as a file: address pointing to that TestPage. Since my images were out on the net at http: addresses this caused the network error, which was really not a network error at all, but rather a wholly client-side policy-based security denial. Fortunately another default behavior of Visual Studio is to create a test website for the component. If you execute the test website and debug there, then the app is running at an http: address and all is well. So when it comes to accessing network resources, where you test your Silverlight app matters.

Deserializing Google Json Data in Silverlight 2.0

In the process of working on a game in Silverlight 2.0 I had a need to fetch some data from Google and manipulate it in C#. The premise of the game will be the subject of a future post. For now I want to talk about deserializing the json data returned by Google’s AJAX (RESTful) API using System.Runtime.Serialization.Json.DataContractJsonSerializer (implemented in System.ServiceModel.Web.dll).

The json serializer is a new addition in the .NET framework 3.5, and although there are a number of examples of how to use this class available on the web, all of them work with very simple, flat json objects. The json objects returned by Google’s API are not that simple. There are a number of nested types that make it a somewhat more complicated scenario than I have seen discussed on other sites. You can read about the AJAX API and the json result format here.

Specifically the examples given for Silverlight show what I will call “simple json deserialization.” Using this approach you can just declare a public class with all public properties representing the json attributes, and use this with the DataContractJsonSerializer. There is no need for [DataContract] or [DataMember] attributions. However, this approach failed with the more complex Google result format. While the ReadObject() call completed successfully all my properties were null. After messing around with it this afternoon while the kids played with their presents I finally came up with something that works. The relevant code is presented below:

[DataContract(Name="pages")]
public class GPage
{
  [DataMember(Name = "start")]
  public string Start { get; set; }
  [DataMember(Name = "label")]
  public string Label { get; set; }
}

[DataContract(Name="cursor")]
public class GCursor
{
  [DataMember(Name = "pages")]
  public GPage[] Pages { get; set; }
  [DataMember(Name = "estimatedResultCount")]
  public string EstimatedResultCount { get; set; }
  [DataMember(Name = "currentPageIndex")]
  public string CurrentPageIndex { get; set; }
  [DataMember(Name = "moreResultsUrl")]
  public string MoreResultsUrl { get; set; }
}

[DataContract(Name = "results")]
public class GResults
{
  [DataMember(Name = "GsearchResultClass")]
  public string GSearchResultClass { get; set; }
  [DataMember(Name = "html")]
  public string Html { get; set; }
}

[DataContract(Name="GimageResult")]
public class GImageResults : GResults
{
  [DataMember(Name="title")]
  public string Title { get; set; }
  [DataMember(Name = "titleNoFormatting")]
  public string TitleNoFormatting { get; set; }
  [DataMember(Name = "unescapedUrl")]
  public string UnescapedUrl { get; set; }
  [DataMember(Name = "url")]
  public string Url { get; set; }
  [DataMember(Name = "visibleUrl")]
  public string VisibleUrl { get; set; }
  [DataMember(Name = "originalContextUrl")]
  public string OriginalContextUrl { get; set; }
  [DataMember(Name = "width")]
  public int Width { get; set; }
  [DataMember(Name = "height")]
  public int Height { get; set; }
  [DataMember(Name = "tbWidth")]
  public int TbWidth { get; set; }
  [DataMember(Name = "tbHeight")]
  public int TbHeight { get; set; }
  [DataMember(Name = "tbUrl")]
  public string TbUrl { get; set; }
  [DataMember(Name = "content")]
  public string Content { get; set; }
  [DataMember(Name = "contentNoFormatting")]
  public string ContentNoFormatting { get; set; }
}

[DataContract(Name="responseData")]
public class GImageResponseData
{
  [DataMember(Name="results")]
  public GImageResults[] Results { get; set; }
  [DataMember(Name="cursor")]
  public GCursor Cursor { get; set; }
}

[DataContract(Name="GImageResponse")]
public class GImageResponse
{
  [DataMember(Name="responseData")]
  public GImageResponseData Response { get; set; }
  [DataMember(Name="responseDetails")]
  public string ResponseDetails { get; set; }
  [DataMember(Name="responseStatus")]
  public string ResponseStatus { get; set; }
}

// omitted: WebClient call to retrieve result stream

private void BuildUriList( Stream results )
{
  DataContractJsonSerializer jsonSerializer =
    new DataContractJsonSerializer(typeof(GImageResponse));
		
  GImageResponse gir = null;
		
  try
  {
    gir = (GImageResponse)jsonSerializer.ReadObject(results);
  }
  catch( Exception ex )
  {
    throw new Exception("Error deserializing json data", ex);
  }
	
  results.Close();

  foreach(GImageResults g in gir.Response.Results)
  {
    Uri u = new Uri(g.TbUrl);
    _uriList.Add(u);
  }
}

The only code I have omitted here is the WebClient call that actually retrieves the result stream. The key point of this is that in order to get everything working I had to fully attribute the classes and data members. The breakthrough came when I attributed one of the classes and noticed that suddenly the properties implemented in that class were correctly deserialized, while the rest remained null. The “simple” approach just didn’t work with nested types. You’ll note that the hierarchy of classes represented in the listing fully implements the Google json result set. In this case the search I am conducting is for images, however I plan to pull this code out into a library that is more generally useful for manipulating Google search results in C#.

In the meantime, now that I am past this Christmas roadblock, on with the game (which is, after all, the fun part).

The Best Use in the World for AJAX

Everyone likes the AJAX client-server interaction model for websites. Using Asynchronous Javascript and XML the client browser can display a page and then issue requests for additional or updated data in the background. It’s very cool, and frameworks like Google Web Toolkit or AJAX extensions for ASP.NET have made it easier than ever to accomplish. Gone are the days when everyone worked with raw XML, the DOM, and XMLHttpRequest. Now you can write client-side code in Java or even C# and have it compiled into client-side javascript that is fully AJAX enabled. So here’s a modest proposal: now that it is so easy to do, let’s all agree to use AJAX to load banner ads. I don’t know how many times per day I end up staring at “Waiting for ads.doubleclick.net” or something similar in the status bar, while the browser page remains blank or incomplete. What would be wrong with displaying some text in the banner space and then fetching the image from the ad servers in the background?

Three Views on Software Development

This week I happened to read three pieces by three different authors, whose publication dates span almost twenty years of evolution in the software industry, and whose ideas fall on opposite ends of a vast continuum of thinking about software and how it is written. Or at least two of them do.

The first is a remarkable paper hand-written and distributed by Edsger Dykstra in 1988, called “On the cruelty of really teaching computer science.” It has since been scanned and preserved for posterity. The handwriting is one of the things that make this work remarkable, and every teenager who today aspires to some technical trade should be required to read it and hand-write a commentary. They will learn that it was once possible for humans to think and express themselves in complete sentences, even when using a stylus and vegetable dye to scratch lines onto a surface of dried wood pulp and white clay.

Beyond that obvious and lamentable anachronism, I don’t consider myself qualified to fully understand Dysktra. He seems to be arguing that every program is a representation of a mathematical formula, and that if we were to truly educate new comp sci students we would have to begin by instructing them in formal mathematics. I don’t know. I recently worked on a large legacy system that has been maintained and extended by contractors from all over the world, over twenty years, and I am pretty sure that if you tried to express that monumental piece of shit as a formula the solar system would disappear with a soft, gaseous “pop.” This is one of those things that I intuitively think must be true at some scale, but must also be entirely irrelevant to almost anyone. Nevertheless, I admit it before the court as an exhibit marking one end of the continuum I mentioned above: software is so hard you have to understand formal mathematics to comprehend it correctly.

At the other end lies a recent piece by Stuart Cohen for Business Week, in which he discerns a fundamental flaw in the open source (FOSS) business model: the product is free. The product, of course, is supposed to be free. That’s the Stallman-esque proposition on which the whole thing is founded: that software has some ethereal quality that renders it a morally unfit object of profitable work. But programmers have to eat too, and so the business of free software (eh?) was supposed to be founded on the sales of support. Somehow it is ethically suspicious to charge money for software, but just fine to charge money for helping people to use it. It turns out that people don’t need to buy much support, and the reason that Cohen assigns for this is that the software is just too good. Good software is now a commodity, therefore the only way to make money in software is to collaborate, somehow, using Cohen’s software or software like it, which presumably he doesn’t sell, but which you pay to collaborate with… or something.

With all due respect and apologies in advance: bullshit. I have some news for Mr. Cohen. Few people have ever needed to buy software support. When faced with the need to pay for support, or the need to RTFM and figure out how the stuff works, most people always took the latter path. In various positions over the years I have paid out hundreds of thousands of company dollars for software support contracts under which I have never actually received any support. This is exactly the revenue stream that still pays for Larry Ellison’s toy jets. The payments were not actually intended to cause the delivery of support. They were membership dues for the Oracle customer club, or the SAP customer club, or entry fees for the Microsoft Customer Portal… whatever. If you really needed help you went to a community forum and asked there. To say that this is because the software was too good entirely misses the point, besides being a statement full of comedic energy in its own right.

Packaged retail software is the kind of programming that you might argue has become somewhat of a commodity, largely due to open source initiatives. That isn’t the kind of software that generates large support contract revenue streams. Therefore the expectations of the community that thought to build a business model on that platform were somewhat delusional. If they want to eat they will probably have to go back to selling their work, like the rest of us. The kind of software that requires support is the kind that is far from commoditized: the thousands of custom applications that businesses build every year to enable or improve their work processes. If that stuff is a commodity I’d like to know where the market is, so I can buy some. From my perspective code quality and effectiveness in these kinds of projects has decreased over the last twenty years, even as there has been an explosion in the number of custom apps being built and the people building them. Which brings me to the third piece I read.

Actually, it is one of a series of three essays by Jack W. Reeves that he published beginning with an installment in C++ Journal in the Fall 1992 volume. The basic thrust of the argument is that program code is design. It is based on the idea that a design is a complete specification for something that can be built. In the case of what we programmers do, the code is a design that is built by the tools into something that runs on a particular system. It might, at first glance, seem about as relevant a point as Dykstra’s, except that much flows from this seemingly innocent assumption; such as the conclusion that a lot of the other crap we have accumulated over the years in a quest for reproducable results, like UML, is not design, and can never be design. I think a lot of programmers feel the intuitive truth of this. You can work months on complete diagrams and descriptions of a software system, but what you have at the end cannot be turned into software. Once you start writing code that can be built, it immediately diverges from all that carefully prepared “design.”

Reeves goes on to argue that the popularity of languages like C++ is due to their support for higher level abstractions, which encourage and enable expressing the design in the one place that it can be effectively expressed: code. I like this idea, and I think it recognizes some hard realities that guys like Cohen just don’t get. Software is never going to be easy, or commoditized. The fact that easy software has become a commodity doesn’t illustrate an exception to the rule. Technical and business managers don’t need any further incentives to underestimate the risk of building software: they already do that very well. They don’t need to be told that good software is a commodity, either, because it isn’t. The truth, as usual, lies in the middle and I think Reeves nails the target pretty accurately, even when he skewers the people who have taken to using mechanical device analogies to describe software construction, something I’ve been guilty of. He doesn’t argue that such analogies are wrong; just woefully inadequate to describe the actual complexity of building good software.