February 2008 - Posts - Jon Galloway

February 2008 - Posts

Opening Adobe Illustrator (AI) files when you don't have Adobe Illustrator

You've been waiting for the design firm to send final artwork. The e-mail finally arrives...

Here's the art! Goodbye!

Uh, oh. That organic.ai file is an Adobe Illustrator Artwork file. Since I'm not a full time designer, I haven't gotten around to spending $600 for Illustrator, and I need PNG's for my website. What to do?

The AI / PDF Connection

We'll take advantage of a little trick: you can rename an AI file from SampleArtFile.ai to SampleArtFile.pdf and open it in the PDF viewer of your choice - like, say, Foxit Reader. How could that work? Let's ask old man wikipedia:

Adobe Illustrator Artwork (AI) is a proprietary file format developed by Adobe Systems for representing single-page vector-based drawings in either the EPS or PDF formats. The .ai filename extension is used by Adobe Illustrator.

[...]

Recent versions of the AI file format, including the PDF-based formats and recent EPS formats, are based on a native format called PGF that is unrelated to both EPS and PDF. PDF compatibility is achieved not by extending the PDF format, but by embedding a complete copy of the native PGF data within the PDF file. The same kind of “dual path” approach is also used when recent versions of Illustrator are saving EPS-compatible files.

So every AI file is really a valid PDF, and you can view it just by changing the file extension.

Okay, great, we can view the art. What if we want to make changes, or export at a specific size or resolution?

Options For Importing or Converting AI / PDF Files

Importing AI and PDF Files In Inkscape

I'm sure I'm tilting at windmills here, but I really like the idea of an open standard vector format, for that same reason it's good that HTML is an open standard. That makes SVG my vector format of choice, and you already know that I love Inkscape (free, open source) so much I want to marry it. Inkscape's recent builds can import and export a large variety of vector and bitmap formats, including AI and PDF.

So we can easily open the file in Inkscape, make any edits, and save it as an appropriately sized PNG or other bitmap file. Since a lot of my readers are in the .NET camp, I'll remind you that it can import and export XAML as well, so Inkscape can take us from AI to XAML really quickly.

Inkscape AI PDF Import

Note - the organic.ai artwork pictured above is available under Creative Commons license from Vecteezy.com.

Online Conversion from PDF or AI to SVG With FreeSVG

Before Inkscape added PDF and AI import, I used to use the FreeSVG service at freesvg.texterity.com. It's really simple - upload a PDF, get e-mailed an SVG file:

FreeSVG

And it's smart enough to know that AI files can be opened as PDF's, so I when I uploaded organic.ai, it automatically renamed it to organic.ai.pdf:

Thank you for uploading your file to FreeSVG. We will convert your file into an SVG file set, and return a link to you shortly.
Here is a recap of what you've submitted:  organic.ai.pdf

Expression Design

Expression Design can import a variety of vector formats, including PDF compatible AI files), and it can export to bitmaps as well as XAML. Expression Design isn't free, so if you just need to import and export I think Inkscape's a smarter choice. That's not to say Expression Design isn't worth the money - it's got some cool features that Inkscape doesn't, like the nice brushes that Microsoft picked up through the Creature House Expression acquisition. Plus, if you're a Microsoft shop you might have access to Expression Design through an MSDN subscription.

Expression - Import File Formats

Epilogue

Enjoy your vacation, François. We've got it covered.

What's been announced about Silverlight 2? See ScottGu's "First Look" post

I've had a lot of people ask me for hints about what's in Silverlight 2. My general strategy is to tell them to read Scott Guthrie's blog, then fake a seizure. That strategy will work even better starting today, since Scott just posted a First Look at Silverlight 2, along with an eight part tutorial on building a Silverlight Digg client.

There's a lot of information in this series. I think it's an excellent read:

  • It's a great overview of what Silverlight 2 looks like.
  • It's a great way to see the developer workflow and Visual Studio experience developing Silverlight 2 applications.
  • It's a great summary of what's been publicly announced on Silverlight 2, plus plenty of new information. If you had a half hour to get up to speed on Silverlight 2, this is how you should spend it.

I've been working with the Silverlight 2 bits on my current project for months now, and I spent a lot of time working with Silverlight 1.1 before that. Still, I find these kind of walkthroughs to be extremely worthwhile since they communicate intangibles like the "feel" and "story" of the product.

I know that the percentage of my readers who don't already read ScottGu's blog - or wouldn't see this on DotNetKicks - is pretty low. Due to the questions and blog comments asking for information, though, I'm going to break my policy on "forwarding blog posts" - this is must read material.

UPDATE: Adam Kinney has a nice summary of Scott's post and the walkthrough. It's especially useful if you just want to see what's new.

Here are some pictures from the series which will hopefully get you interested enough to read it:

Hey, what's that XAP thing?

The finished product. What's most impressive is that this was built relatively quickly - you could have designed this in Silverlight 1.1, but it would have been a 135 part walkthrough rather than an 8 part one:

Showing the WebClient request to Digg. Hey, is that a cross-domain call?

Linq To Xml (note with IntelliSense) - the result is then bound to a DataGrid:

Posted by Jon Galloway | 1 comment(s)
Filed under:

Using Windowless Silverlight Controls To Blend HTML and Silverlight Elements

Silverlight 1.0 has no intrinsic controls. Forget about dropdowns and sliders, Silverlight 1.0 doesn't have textboxes or buttons. That doesn't mean you can't build and deploy advanced Silverlight 1.0 applications today, though. [Sheesh, that sounded like marketing-speak - sorry about that.]

There are three ways to go about getting controls for Silverlight 1.0 applications:

  • Build your own controls from scratch
  • Grab some controls from published Silverlight projects (license permitting, of course)
  • Layering transparent HTML and Silverlight controls

We'll mostly be looking at the layering approach here - looking at the following questions:

  1. How to logically split a control into HTML and Silverlight regions
  2. How to overlay tranparent HTML and Silverlight sections in a single control area
  3. Performance considerations

Just a second, I have to deal with some deserters...

Wait, This Applies For Silverlight 2.0, Too!

Oh, and I heard those restless mice scurrying for the "next post" link. "Jon", you say, "that's great, but I'm just going to ride it out. I heard Silverlight 2.0 will include controls." You do have a point there. The publicly announced Silverlight roadmap indicates that Silverlight 2.0 will "add support for core form controls (textbox, checkbox, radiobutton, etc), built-in layout management controls (StackPanel, Grid, etc), common functionality controls (TabControl, Slider, ScrollViewer, ProgressBar, etc) and data manipulation controls (DataGrid, etc)." But I think you should still read this, for two reasons:

  1. Silverlight 2.0 will have a bunch of new controls. Will it have every webby control possible? Time will tell, but I'd guess that there may be controls you'd like to have in a Silverlight 2.0 application that aren't in the box.
  2. Even if Silverlight 2.0 includes the control you want, you may want to use an HTML based control. Maybe you've got an existing site and you'd like to integrate Silverlight functionality without a full rewrite. Or, you've got a complex control or HTML structure which would be pretty difficult to rebuild in Silverlight. Or, maybe you've got some AJAX interactions in your page which are easier to wire up in HTML and JavaScript - sure, you can communicate with JavaScript and the DOM even in Silverlight 1.0, but you're still crossing domain boundaries, and if you've got functioning JavaScript and AJAX code, it might not make sense to move that interaction code to Silverlight 2.0 managed code. Finally, maybe you want to take advantage of control toolkits like the AJAX Control Toolkit, rather than duplicating these controls in Silverlight.

Composite Controls Using Transparent HTML and Silverlight Elements

The Video.Show player interface is a good example. Video.Show is a Silverlight 1.0 based "video site in a box" project which is available on CodePlex - see my previous post for more information. We made heavy use of the Silverlight / HTML layering approach to get the best of both. Take a look at the following control and take a guess at how it's constructed:

Video.Show Player interface

Here's the breakdown we went with:

Silverlight / HTML Composite

Header Section

It made sense to build the header section in HTML, since it's pretty simple and mapped to HTML controls pretty well. The owner of the video ("Jon" in the above screenshot) is hyperlinked to my member page, and the blue buttons at the top of the page make simple AJAX calls to ASMX webservices.

Lower Section

The lower section is one big Silverlight control. The media player window had to be a Silverlight, of course. The right section (with the comment form) could have been HTML, but notice the slider bar above the comment box? That's part of the player control. When you're not in "comment mode", that slider is located below the video, as seen below:

Video.Show Player Controls

When you click the "Add Comment" button, we switch into "comment mode" - hiding the playback controls and moving the slider above the comment area. Because of that, it's simplest to keep the entire lower section as a silverlight control and layer HTML controls over the top. We've done that by using CSS absolute positioning for the comment area:

div#commentForm {
display:none;
position:absolute;
height:100px;
left:500px;
top:110px;
width:500px;
}

You'll notice that display is set to "none" so the comment form isn't displayed when the page first loads. The position is set to absolute so we can position it over the Silverlight control. The Add Comment button calls showCommentForm():

<div class="button">
<a onclick="player.showCommentForm()" href="#">Add Comment</a>
</div>

showCommentForm does a lot of things, including this:

showCommentForm: function() {
//lots of other stuff
$get("commentForm").style.display = "inline";
}

The Silverlight control itself is Windowless so that the gradient background shows through. That's accomplished by setting a few values in the <object> tag (although we don't set those directly, more on that in a second). Notice that we've got the background set to transparent, and the windowless property set to true.

<object id="xamlHost0" width="900" height="412" type="application/x-silverlight">
<param value="transparent" name="background"/>
<param value="true" name="windowless"/>
<!-- a bunch of other params go here -->
</object>

As I've said before, Silverlight is implemented as an HTML object, and technically doesn't need to be displayed via JavaScript. However, for reasons I mentioned in that post, it's a good idea to use the JavaScript helper functions. Here's the JavaScript call used to load the Silverlight object:

 

Just setting the background to transparent isn't enough, the control also needs to be windowless for the transparency to be applied. Once that's done, though, the control is effectively layered over the background. So the final result is three layers:

CropperCapture[106]

Silverlight.createHostedObjectEx({
source: 'Silverlight/Player/Player.xaml?v=1',
parentElement: $get(parentId || "Player_SilverlightContainer"),
id: this._hostname,
properties: {
width: '900',
height: '412',
framerate: '24',
version: '1.0',
background: 'transparent',
isWindowless: 'true'
}

Performance Considerations of Windowless Silverlight Controls

You should be aware that using a Silverlight control in Windowless mode can have performance impacts. It can cause "tearing" during animations, and can force large areas of the screen to be redrawn when in fact minor changes have been made. That's something you'll need to evaluate - in our case, there was very little animation other than the video timeline slider moving while was the video was being played, so in our testing we didn't see any problems. However, it's something to be aware of, especially before you attempt to do something crazy like create multiple layers of transparent video objects.

If you're seeing performance issues, make sure to start with EnableRedrawRegions (a debugging switch which allows you to see what areas are actually being redrawn) and to lower your framerate as necessary.

If You Are Going To Build A Complex Silverlight Control, Don't Start From Scratch

To recap: my advice is to use HTML elements to do some of the heavy lifting in your Silverlight applications, which should hopefully reduce your need to build complex controls in Silverlight. If that doesn't work for you, though, I'd like to recommend that you don't build your new Silverlight controls from the ground up.

There are several released projects which include tool suites - starting with primitives and building up to complex controls. Scott recently mentioned the Tafiti controls (licensed under MsPL), and you can also cherrypick from CodePlex projects which include Silverlight controls. The Expression Encoder templates are based on a BasePlayer, which is available for download. However, the license for the Expression Encoder templates requires an Expression Encoder license, so it's really only useful if you're extending the Expression Encoder player templates.

The bottom line on building controls is that it's hard to get them right, and if you make use of a control someone else has built and tested, you're off to a great start.

Posted by Jon Galloway | 5 comment(s)
Filed under:

Video.Show 1.0 - A Ready To Run Solution For Hosting Video On The Web

I'm really excited to announce that Video.Show has officially been released. It's been available on CodePlex (under the liberal MsPL license) since our beta release back in November, but today it's officially been blessed as a 1.0 release. While we were really proud of our beta release, we've been really busy moving this project from a sample to something that's easier to extend and maintain. And when I say "we", I mean Mike Moser, because I moved off the project soon after we hit the beta release.

Tim Sneath sums it up really well - Video.Show was designed to be "a ready to run solution for hosting video on the web." Ready to run means that you copy the site to a computer with .NET 3.5, SQL Server Express, and Expression Encoder installed, you update two configuration settings in the web.config (your account and password for a free Silverlight Streaming account), and your site is live.

Cool Features Built on Hot Technologies

Video.ShowI've been excited about Video.Show since I started working on it in August 2007 (my first project at Vertigo), but I haven't said a whole lot about it (even after the public beta release) because I thought it would be best to wait for the official public release. Now that it's shipped, I'd like to point out some of the technical features:

  • All videos, by default, are hosted with Silverlight Streaming. That helped us deliver a "YouTube-In-A-Box" solution that can run on a lightweight server, since the video is streamed from the Silverlight Streaming content delivery network. That means you don't have to worry about disk space or bandwidth to handle video streaming; the only thing you're storing on your server is data (in a lightweight SQL Server Express database) and tiny video thumbnail images.
  • We built out the video player and "video wall" feature in Silverlight 1.0 (yep, Silverlight 1.0, which shipped back in September 2007). I'll be honest - I'd played with Silverlight 1.1 before working with Silverlight 1.0, and at first I was frustrated with the step back. But after working with it a bit, I changed my mind. Silverlight 1.0 is a solid product, and it's got a great video display system. One of the coolest bits is the "video wall" (built by Matt Hempey, of Bubble 2.0 fame), which previews videos as you mouse over them.
  • We built out a data layer on Linq To Sql running on SQL Server Express. You can swap to a full SQL Server implementation by copying the MDF file and changing your connection string, but in the interest of a smooth deployment experience, we saw that SQL Server Express was a great fit. And since the main performance challenge on this site has been outsourced to Silverlight Streaming, we found that SQL Server Express was more than sufficient for most installations. And Linq To Sql worked like a charm - I built out the original data layer, and Mike did the work to refactor this to a more extensible architecture. Bottom line - I think that our data layer provides a good example of a lightweight data layer running on Linq To Sql that effectively supports both ASP.NET and AJAX workload.
  • We leveraged the AJAX Control Toolkit to make the site interaction smoother. We didn't just use the controls, we used the animation system - for instance, when you start playing a video, the background fades to indicate the theatre lights are dimming, and that effect is powered by the AJAX Control Toolkit. We paid a lot of attention to making appropriate use of both Silverlight and AJAX, guided by whatever technology was best suited towards the task at hand.
  • We integrated the Expression Encoder to convert a variety of video formats. While you could convert the codebase to use the Windows Media Encoder, you'd miss out on a range of features which the Expression Encoder introduces. One of those features is wide media format support, including avi, mp4, asf, mpeg, dvr-ms, m2v, ts, m4v, vob, mov, and of course wmv.
  • We made use of a really cool feature in Silverlight called Timeline Markers. Timeline Markers allow you to add time-based events to your media in client code - meaning JavaScript. That means that we're able to show video comments keyed to the point in the video when they were entered. Since it's done on the client-side, you can add a comment (via AJAX) to a video, and the time-based events are immediately be added to the video as it's playing, without posting back (let alone re-encoding it). It's a little tricky to grasp the power of that feature, so I'll dig into that in more detail in a future post.
  • We made good use of the ASP.NET Membership and Profile system. Yes, those are features that have been available since ASP.NET 2.0 shipped, but I think we made really good use of them.
  • We followed best practices for the "installation experience" for the case in which a viewer doesn't have Silverlight installed. Check out Adam Kinney's post for more information on how Video.Show's installation experience looks.
  • We built the UI with CSS based theming, to allow you to re-skin it for your own use. Our CSS was tested on IE 7, Firefox 2, and Safari / Mac.

What's most important - every single technical dependency of Video.Show has been released for months. There's not a single Alpha, Beta, or CTP bits in there. Sure, most of it was in beta while we were developing the project, but Video.Show doesn't demand a smidgen of "beta guts" to install.

And, People Are Actually Using It

As Tim points out, people are already using the Video.Show site to build some really sites. Films For Learning is a great example:

FilmsForLearning

The Video.Show source is available on CodePlex; you can browse it online if you'd like.

Posted by Jon Galloway | 27 comment(s)
Filed under: ,

Getting JavaScript and ASP.NET talking (outside of AJAX)

Passing values between ASP.NET and JavaScript code is messy

A lot of effort has gone into simplifying the AJAX pattern, in which your JavaScript code calls methods on the server without requiring a full page post. You don't hear much about the synchronous case (SJAX?), though - how does your server-side code set values in JavaScript, and how do you set values in JavaScript and pass them back to the server when the page is submitted? In the diagram below - we've got AJAX covered pretty well, but what about the Rendered JavaScript case?

Server to JavaScript Communication

Parade of the Ugly Hacks

Until recently, if you had some settings in your server side code that you needed to act on in JavaScript code, you ended up using ugly hacks.

Ugly Hack #1 - Emit JavaScript strings

Emitting JavaScript code with global variables in a startup script. This requires writing out JavaScript as strings in your server-side code, which is ugly as hell.

string primateVariables = string.Format(
    "<script type='text/JavaScript>" +
        "var primateAddress='{0}';" +
        "var primateCreditRating='{1}';" +
    "</script>",
    SelectedPrimate.PrimateAddress,
    SelectedPrimate.PrimateRating
    );

Ugly Hack #2 - Make Unnecessary AJAX Calls

Using unnecessary client callbacks (a.k.a. AJAX webservices calls). The code may look clean, and it's the path of least resistance, but it's a very lazy and inefficient solution to the problem. There's no reason for your client-side code to get a value from the server via a webservice call when the value is known at the time the page is rendered. AJAX calls should be made when a user's interaction with the webpage requires you to communicate with the server. If there's information that's known when you're writing out the page, you shouldn't be making another call back to the server just because the code's easier.

Ugly Hack #3 - Muck Around With Hidden Form Fields

The idea here is that you stash values in hidden form fields which are read via JavaScript. This is probably the least ugly of the above, as it does allow for a two-way communication mechanism (as the JavaScript can modify the form value to pass it back to the server. First, we'll set the field value in our server-side code:

ClientScriptManager.RegisterHiddenField("primateViews", PrimateViews.ToString());
 
Now we can read and update the value from JavaScript:
var primateViews;
if($get("primateViews") && $get("primateViews").value != ""){
    $get("primateViews").value = parseInt($get("primateViews").value) + 1;
}
else {
    $get("primateViews").value = 1;
}
 
Back on the server, after the postback, we can check Request.Form("primateViews") to get any client-side updates. So, it all does work, but it does have some downsides, though - it's offers no type checking, and it's the equivalent of a global variable.
 
Note that Ugly Hacks 1 and 3 both are essentially setting global variables in the HTML DOM. That's not just ugly, it doesn't scale well. Say, for instance, that we want to set a PrimateCreditRating value for our control, and we choose to handle it by stashing it in a hidden form field (i.e. <input type="hidden" id="PrimateCreditRating">). Fine, now what happens when we want to drop two of these controls on a page? How about if we want to show a list of 50 primates, and use our AJAX-ified Primate Control on each? We could make our ugly hack even uglier with a naming convention (PrimateCreditRating1, PrimateCreditRating2, etc.), but this is just getting out of hand. We need to to encapsulate our settings, and we need to formalize our communications from server to client. Fortunately, someone's already got that covered...

A Better Solution - IScriptControl

ASP.NET AJAX solves this problem with the IScriptControl interface. This solution cleans up the code on both the client and server. Rather than injecting values into JavaScript strings on the server, the IScriptControl.ScriptDescriptor mechanism gives you a simple way to pass information to the client as properties of a custom JavaScript object. Now that you're able to do that, there's not reason to modify your JavaScript code at runtime, so your script can be a static file - essentially a resource. I was deep into figuring this out on my own when I got the January edition of MSDN Magazine, which included Fritz Onion's article titled Encapsulate Silverlight with ASP.NET Controls. It's a great article (although you need keep in mind that he's building on the Silverlight controls included in the ASP.NET Futures release which has since been replaced by the controls in the ASP.NET 3.5 Extensions Preview). It helped quite a a bit, but I still had to bang on it for a while to get it working. In my experience, the IScriptControl interface works well when it's working, but it's a little tough to set up.

Works on both Server Controls and User Controls

While the common usage is to create or extend a WebControl (a.k.a. a Server Control), you can also implement the IScriptControl interface on a UserControl. Don't just take my word for it, though - take a look at the ScriptUserControl, a part of the AjaxControlToolkit. Here's the class signature:

public class ScriptUserControl : UserControl, IScriptControl, IControlResolver, IPostBackDataHandler, ICallbackEventHandler, IClientStateManager

About The Sample Code

My project extends the ASP.NET Silverlight controls, which are some of the extra-special goodness that is the ASP.NET 3.5 Extensions Preview. I'm going to base my sample code on the MSDN walkthrough on Adding ASP.NET AJAX Client Capabilities to a Web Server Control, though, to keep it simple. I'm going to change a few things in the MSDN walkthrough, but it's pretty similar.

Using ScriptDescriptor

First, you'll need to do some work on the server side to implement the ScriptDescriptor interface. That's done by implementing (or overriding, if you're inheriting from a base control) the IScriptControl.GetScriptDescriptors() method, which returns an IEnumerable<ScriptDescriptor>. The simple case to demonstrate is implementing (rather than extending) a control. For this sample, let's assume we're going to extend a WebControl with a loading image, so we'll be including three control properties which will be utilized in our client-side JavaScript: ShowLoadingImage (boolean), LoadingImage (string), and DisplayTime (int). So, first, we'll set up those control properties:

[Category("Behavior"), DefaultValue(true), Browsable(true)]
public virtual bool ShowLoadingImage
{
    get { return (bool)(ViewState["ShowLoadingImage"] ?? true); }
    set { this.ViewState["ShowLoadingImage"] = value; }
}

[Category("Behavior"), DefaultValue(true), Browsable(true)]
public virtual string LoadingImage
{
    get { return (string)(ViewState["LoadingImage"] ?? string.Empty); }
    set { this.ViewState["LoadingImage"] = value; }
}

[Category("Behavior"), Browsable(true), DefaultValue((int)5)]
public virtual int DisplayTime
{
    get
    {
        object DisplayTimeSetting = this.ViewState["DisplayTime"];
        if (DisplayTimeSetting != null)
        { return (int)DisplayTimeSetting; }
        return 5;
    }
    set
    {
        if (value < 1)
        { throw new ArgumentOutOfRangeException("value", value, "DisplayTime must a positive integer representing the time duration in seconds."); }
        this.ViewState["DisplayTime"] = value;
    }
}

Great, now we need to tell the ScriptControl that the values of the above properties will need to be exposed to our JavaScript object. We'll do that by implementing IScriptControl.GetScriptDescriptors():

protected virtual IEnumerable<ScriptDescriptor> GetScriptDescriptors()
{
    ScriptControlDescriptor descriptor = new ScriptControlDescriptor("SampleCode.SampleScriptControl", this.ClientID);
    descriptor.AddProperty("loadingImage", this.LoadingImage);
    descriptor.AddProperty("showLoadingImage", this.ShowLoadingImage);
    descriptor.AddProperty("displayTime", this.DisplayTime);

    return new ScriptDescriptor[] { descriptor };
}

IEnumerable<ScriptDescriptor> IScriptControl.GetScriptDescriptors()
{
    return GetScriptDescriptors();
}

The when the ScriptControl is rendered, it writes out JavaScript call to $create(), and if the ScriptControl includes any ScriptDescriptors, those are included in the $create call. Here's how that looks in action:

  1. ScriptControl renders a JavaScript call to Sys$Component$create(type, properties, events, references, element), passing all your setting in the properties parameter in JSON syntax. Here's how that JavaScript would look if we'd added an instance of the control to our page, named it MySampleControl1, and set some property values
    Sys.Application.add_init(function() {
        $create(SampleCode.SampleScriptControl, {
            "showLoadingImage":        true,
            "loadingImage":            "http://s3.amazonaws.com/sample/load.png",
            "displayTime":            5
            }, 
            null, null, $get("MySampleControl1"));
    });
    It's important to keep in mind that you're not writing the above JavaScript; it's being rendered by the ScriptControl.
  2. $create() instantiates your object and calls _setProperties() which calls the setters for all properties which were passed in during the $create() call.

ScriptReference just loads JavaScript files

Since the ScriptDescriptors are doing the work of passing the property values to your JavaScript controls, the ScriptReference mechanism has a pretty simple job - load JavaScript files. Since we don't have to generate any JavaScript at runtime, we're free to treat our scripts as an embedded resources.

IEnumerable<ScriptReference> IScriptControl.GetScriptReferences()
{
    return GetScriptReferences();
}

protected virtual IEnumerable<ScriptReference> GetScriptReferences()
{
    ScriptReference reference = new ScriptReference();
    reference.Path = ResolveClientUrl("SampleScriptControl.js");
    return new ScriptReference[] { reference };
}

The Last Mile - How Does That JavaScript Look?

Since the ScriptDescriptors are doing the work of passing the property values to your JavaScript controls, the ScriptReference mechanism has a pretty simple job - load JavaScript files. Here's a stripped down sample - it's pretty repetitive, so don't get worried by the length:

Type.registerNamespace('SampleCode');

SampleCode.SampleScriptControl = function(element) { 
    SampleCode.SampleScriptControl.initializeBase(this, [element]);

    this._showLoadingImage = null;
    this._loadingImage = null;
    this._displayTime = null;
}

SampleCode.SampleScriptControl.prototype = {

    initialize : function() {
        //Your initialize code here - wire up event delegates
    },

    dispose : function() {
        $clearHandlers(this.get_element());
        //Your dispose code here
    },

    //Property accessors
    get_showLoadingImage : function() {
        return this._showLoadingImage;
    },
    set_showLoadingImage : function(value) {
        if (this._showLoadingImage !== value)
            this._showLoadingImage = value;            
    },    
    get_loadingImage : function() {
        return this._loadingImage;
    },
    set_loadingImage : function(value) {
        if (this._loadingImage !== value)
            this._loadingImage = value;            
    },    
    get__displayTime : function() {
        return this._displayTime;
    },
    set_displayTime : function(value) {
        if (this._displayTime !== value)
            this._displayTime = value;            
    },    
    // Your event and control code here...
}

SampleCode.SampleScriptControl.registerClass('SampleCode.SampleScriptControl', Sys.UI.Control);
if (typeof(Sys) !== 'undefined') Sys.Application.notifyScriptLoaded();

The important things to notice here is that we're declaring our class with properties which match our script descriptors. The ASP.NET AJAX $create() method will call the appropriate property setters for each matching script descriptor, so our $create() call sample above will result in the following property setter calls:

set_showLoadingImage(true);
set_loadingImage("http://s3.amazonaws.com/sample/load.png");
set_displayTime(5);

Putting It All Together

ScriptControl in ASP.NET AJAX

We started with a problem - it's hard to get property values from server-side code to JavaScript objects. Then we looked at the ScriptControl / IScriptControl solution, which does the following things for us:

  • Provides a way to keep our settings on a per-component level, so we don't run into the problems our global variable solutions hit.
  • Provides a way to wire our server-side properties to client-side properties in a way that's clearly spelled out, and easy for others to extend or maintain.
  • We're never treating JavaScript as strings. We reference our JavaScript as a file, declare how our server-side properties map to client-side properties, and the wiring up is done for us.

There's more to the subject:

No, you're crazy! (or, the problem with assuming that computer programmers have all that much in common)

CropperCapture[96]Five Non-Essential Phone Screen Questions Which Tell Me Nothing

Jeff Atwood recently linked Steve Yegge's post on Five Essential Phone-Screen Questions. My first impression was that it was horrible advice. For reference, here's the five areas which Steve considers essential in eliminating poor job candidates:

  1. Coding. The candidate has to write some simple code, with correct syntax, in C, C++, or Java.
  2. OO design. The candidate has to define basic OO concepts, and come up with classes to model a simple problem.
  3. Scripting and regexes. The candidate has to describe how to find the phone numbers in 50,000 HTML pages.
  4. Data structures. The candidate has to demonstrate basic knowledge of the most common data structures.
  5. Bits and bytes. The candidate has to answer simple questions about bits, bytes, and binary numbers.

He goes on to give some example questions, including the following:

  • What's the worst-case insertion performance of a hashtable? Of a binary tree?
  • What are some options for implementing a priority queue?
  • Format an RGB value (three 1-byte numbers) as a 6-digit hexadecimal string.
  • Tell me how to test whether the high-order bit is set in a byte.
  • Write a function to count all the bits in an int value; e.g. the function with the signature int countBits(int x)

Now, in fairness, both Jeff and Steve were careful to clarify that these aren't go/no-go questions. The idea is to use these to determine if an applicant has a total void of knowledge in a fundamental area.

However, I still believe that Steve's questions would be useless in hiring someone to work on my current projects. I don't care if a candidate can check if a high-order bit is set, to the point that I might be a little turned off by an applicant whose answer revealed they were a bit-twiddler. I've hired bit-twiddlers before, and while they interviewed well, they weren't much help in shipping applications. Worse, we're wasting valuable time talking about hexadecimal formatting when we should be covering things like database access and rudimentary knowledge of HTML and HTTP. An applicant could ace the above questions and be clueless on where to start with constructing a web application.

You see my error, don't you?

Steve Yegge works for Google. Steve and I are both professional programmers; in fact we both work on web applications. Yet, our jobs are no more related than if we were both doctors in different fields - say, a podiatrist and an orthodontist. For example, if you work for Google, you're going to be concerned with how to make your applications run against huge data sets using large, unreliable computer clusters. None of those are priorities in applications I work on, since I'm generally working against a relational database which aren't running at high volume or scale. So, Steve is thinking about how to build Google-scale applications running on Map/Reduce, while I'm working on comparatively small projects running against relational databases.1

As Dare points out, it's incorrect to view that dichotomy and try to pick a winner in a fight between Map/Reduce and Relational Databases. Both are tools, used to solve very different problems. Problems which are so different that those who solve them are essentially in different lines of work.

Different enough that Steve Yegge isn't qualified to interview people who will work on my projects (nor I, his).

Computer Programming: A Field, Not A Job Description

The field of computer programming is a wide one, a fact we seem to ignore when blogging about "the way computer programming ought to be done." It's amusing to read comments on popular blog posts (e.g. just about anything Jeff writes) and watch the arguments:

  • You're crazy! There's no way programmers should [insert topic here]! I've never had to do that in fifteen years of professional development!
  • No, you're crazy! I just coded it up in Lisp last week, and anyone who can't isn't a real programmer!

Of course, the real answer is that both people are crazy for assuming that they're colleagues.

Information Is Useless Without Context

Steve Yegge is the guy to listen to - especially if you want to know about writing Lisp in Emacs, or managing a 500KLOC Java game you wrote in your spare time. Joel Spoelsky is an undisputed expert - on running a business that produces wonderfully usable bug tracking software (on classic ASP and PHP).

And since you're here, I'll mention that my field of expertise: I specialize in ASP.NET web applications running on SQL Server, generally slanted towards the bleeding edge of Microsoft technologies. It's been a decade since I shipped production C++ code, and I haven't been paid to write PHP code in seven years. I spend an inordinate amount of time reading about what's going on outside of my speciality, but I know the limits of my expertise, and so should you. When you're reading my opinions you be aware of my background for three reasons:

  1. You should know when I'm speaking from experience (as opposed to just making stuff up)
  2. You should be aware of any bias or unspoken assumptions that I bring to an opinion, such as assuming that most non-academic applications will work with relational databases

I don't believe that we should require authors to bury their opinions in weasel words and disclaimers. Rather, as readers, we need to appreciate the author's context and bias, and intelligently translate their opinions to our context.

And It's Not Just About Differing Fields Of Expertise, Either...

I've noticed that unspoken bias and context often explains a lot of long-running arguments. For example, I had a long running argument with another developer over WinMerge vs. Beyond Compare. I'm talking about a blood feud spanning years, raging in the battleground of inexpensive file merge applications. Finally, we got on the phone and spent an hour, taking turns explaining why we thought our application was superior. When we were done, we both understood the real issue: he primarily used Beyond Compare to deploy files to a webserver, while I used WinMerge to handle source merges in Subversion. We'd come up with different answers to the question of "What's the best file diff/merge utility" based on different, unspoken assumptions as to what the utility would be used for.

The same sort of solution seems to be useful in just about any seemingly intractable argument in our field. Is there a case in which your views on Test Driven Development wouldn't apply? Your thoughts on dynamic SQL vs. stored procedures? Project management methodologies? Your decisions to use Microsoft software or GPL software (or both, or neither)? Managed code environments vs. C and C++?

1 Just for context, I think I could adequately answer just about every question on Steve's list. I'm not being defensive, I'm arguing that these questions don't come close to defining the successful developers I work with.

January 2008 Recap

I've had a policy against posting on big news that's likely to be common knowledge in the Microsoft development community, since nobody needs another post saying "Big News, Visual Studio 2008 is out today!" But I think I'm going to break that policy once a month with a digest of the big news of the month, along with things I found interesting that might not warrant a full blog post. I may write up full posts on some of these things occasionally, who knows? Right, then - on with the inaugural issue!

C# 4 to get dynamic lookup (as in, "late binding")

Charlie Calvert tells us that the .NET 4.0 CLI will allow for dynamic lookup in all languages, including C# 4: "The next version of Visual Studio will provide a common infrastructure that will enable all .NET languages, including C#, to optionally resolve names in a program at runtime instead of compile time. We call this technology dynamic lookup." Here's what the code might look like:

static void Main(string[] args)
{
    dynamic
    {
        object myDynamicObject = GetDynamicObject();
        myDynamicObject.SomeMethod();         // call a method   
        myDynamicObject.someString = "value"; // Set a field
        myDynamicObject[0] = 25;              // Access an indexer
    }
}

Network Solutions squatting domains you search on

Word got out that Network Solutions was automatically reserving all domains searched for on their WhoIs domain lookup page, taking advantage of VeriSign's 5 day grace period (during which they'd refund registration fees) to lock the domain for 5 days for free.

Here's the problem - if you looked the domain up on Network Solutions and saw it was available, it was already reserved by Network Solutions so you couldn't register it elsewhere (for instance, at GoDaddy, which charges about $30 less for yearly domain registration than Network Solutions does). If you decided to wait until Network Solutions dropped the domain 5 days later, you were likely to see the domain snatched up by domain squatters why also took advantage of the 5 day grace period, automatically registering every free domain milliseconds after Networks Solutions dropped it.

After this was discovered and verified, the ICANN decided to drop the 5 day grace period. That's good news, since it will make domain squatting less economically viable.

The .NET Framework Library source is available for debugging purposes.

Scott Guthrie has a quick overview, and Shawn Burke has a detailed post on how to set it up. This is cool, but having used Reflector and the File Disassembler plugin for a while, this isn't completely revolutionary for my day to day work. The nice additions over Reflector are the comments and the ability to step through the code when debugging. This seems like the kind of thing you wouldn't need to use often, but when you need it you really need it.

Google Desktop Search no longer searches your files by default

Not sure if this is big news or not; I've never been much of a fan of Google Desktop Search. Apparently their latest release no longer indexes the contents of you files by default, although you can still enable file indexing if you want. It's interesting the Google is backing off the file search feature, as it was the focus of their lawsuit against Microsoft which resulted in the Vista SP1 being hurried along.

IE8 ditching DOCTYPE for X-UA-Compatible

The IE team announced that they're dropping DOCTYPE for a new browser targetting system using a new meta tag, X-UA-Compatible. There's a good overview at A List Apart which explains what's changing and why. The main idea was that the existing DOCTYPE system basically gives you two options - opt in to standards compliant mode, or opt in to quirks mode. The challenge is that standards compliant mode changes with each release of IE, so what renders well in IE6 breaks in IE7 or IE8 - there's no real way to know that your HTML will render correctly in future versions of IE.

The new X-UA-Compatible tag lets you target your HTML at the rendering style of a specific browser version. Assuming other browsers support it, you'd be able to lock your rendering in with this kind of tag:

<meta http-equiv="X-UA-Compatible" content="IE=8;FF=3;OtherUA=4" />

There's been some frustration in the web standards community over this, who dislike using non-standard tags to target browsers and would prefer that browser versions solve the browser compatibility issue by fully supporting web standards like XHTML. Ian Hickson points out that this makes the testing matrix for browser vendors pretty complex, since it would require Firefox to be able to reproduce the rendering quirks of each version of IE.

New Microsoft virtualization annoucements

Microsoft bought some more virtualization technology, announced partnerships, and announced they're loosening the virtualization restrictions on low end Vista versions. I wrote about this on my Vertigo blog.

Jon Udell's Talk from CUSEC

I heard about the CUSEC conference in Montreal because my friend and co-worker Jeff Atwood was one of the speakers. Jon Udell posted his slides from his morning keynote, “Hacking the Noosphere”. His themes were "shared tools and data, social engineering, language, the semantic web, human augmentation, and Doug Engelbart’s vision of the true purpose of information technology."

Microsoft announced a proposal to acquire Yahoo for $44 billion

Yeah, this news came out on February 1, but I'm including it now rather than wait a month. Long Zheng put together a nice feature matrix which shows the overlap between Microsoft and Yahoo web properties. The Microsoft PressPass page has a link to the conference call audio and the accompanying PowerPoint. I listened to some of the audio, but I'd recommend just looking at the slides.

Larkware News (The Daily Grind) went off the air

As promised, Mike Gunderloy posted the last daily issue of The Daily Grind on December 31, 2007. He's moved on to a new blog called A Fresh Cup, which covers his experiences developing on Ruby On Rails. The Daily Grind was essential in learning my way around the .NET world, and it'll be missed. Leon's got a list of contenders for his MikeG.Next award, and between DotNetKicks and Twitter I'm feeling a less reliance on link blogs to keep up. Best of luck with your new career, Mike, and thanks again for 1305 great issues of The Daily Grind!

Scott Guthrie interviews about what Microsoft will be announcing at MIX08

Channel 9 posted an interview with Scott Guthrie about what Microsoft will be talking about at MIX 08. Part 1, Part 2

Software Updates

Notepad++ 4.7 - New release includes a lot of cool stuff, including FTP support (opens file from FTP server, uploads changes on save) and enhanced clipboard support so copy / paste of code into other applications will preserve the format and colors.

SubSonic 2.1 Beta is out, including lots of cool new features (and no breaking changes). Includes a new query tool with a much simpler syntax that feels more like a strongly-typed SQL an IDE called SubStage that lets you do things  like build your configuration and generate control markup, all by setting properties in a property grid. I got a demo from Eric Kemp, and it's really slick.

Zeitgeist

For more about what happened in January 2008, take a look at the DotNetKicks Zeitgeist page.

More Posts