Creating a decent API for client side script registration

I’ll start my post with a question:
What’s the difference between ScriptManager.RegisterClientScriptBlock and ScriptManager.RegisterStartupScript methods?


Well, the only way to find out is not by looking at the method names but rather to look in MSDN. According to MSDN the former registers your script after the <form> element while the latter is registering your script just before the </form>. Now, let me ask you this – how the word “Startup” can be interpreted as “end of page”?


So OK, the naming is really bad but what’s even worse are the arguments of these methods:


public static void RegisterClientScriptBlock(Control\Page control\page, Type type, string key, string script, bool addScriptTags);
public static void RegisterStartupScript(Control\Page control\page, Type type, string key, string script, bool addScriptTags);


Now, most of us write this code 95%(+) of the times:


ScriptManager.RegisterClientScriptBlock(this, this.GetType(), “some stupid key”, “the script here, finally…”, true); //like someone is stupid enough to give false – if you have a full script, why not putting it inside myFile.js and add it to the header?


I don’t understand the real need behind creating a “unique” key from the type+key given to this method. Why not creating a unique key each and every time? You need to create a simple API for the common (90%) tasks. I almost never actually asked about IsClientScriptBlockRegistered. But enough complaining, time to write a few bits & bytes.


I tried to play with the API a little and here is what I came up with (it’s merly the beginning, I’ll update on my progress during the week):


PageClientSideExtender clientSide = new PageClientSideExtender(Page);


// A better approach, IMHO, to ScriptManager API
clientSide
  .RegisterScript(“alert(‘run at the beginning of the page’);”)
  .AddScriptTags()
  .RunAtTheBeginningOfThePage();

clientSide
  .RegisterScript(“<script>alert(‘run at the end of the page’);</script>”)
  .RunAtTheEndOfThePage();

//let’s register something like:
// var width = 300;
clientSide.RegisterLocalVariable<int>(“width”).SetValue(“someValue”);

//let’s register something like:
// var data = ‘width:300;height:500’;
clientSide.RegisterLocalVariable<string>(“data”).SetValueFormatted(“width:{0};height:{1}”, 300, 500);

// Let’s register to the onload of the <body> and trigger a nice alert
clientSide.Body.Load += ClientSideScriptHelper.CreateHandler(“alert(‘run on body onload! cool ah??’);”);


//Or:

clientSide.Body.Load += delegate { return “alert(‘another message shown after the page onload event was raised. sweet!’);”; };




The Fluent interface gives it a nice “read-the-code-like-a-story” look&feel which makes things really easy to understand. There is no thinking here, the code says it all.


Another rant I have is that all of the API examples I’ve demonstrated so far are implemented although not fully tested as using Microsoft classes requires a lot of work in order to abstract. The funny thing is that they(Microsoft) have decoupled things in the new Microsoft ASP.NET Ajax library(System.Web.Extension.dll) but they made everything internal!  You have IPage, which is really useful abstraction to the Page class, sitting there as an internal member. I had to come up with some heavy abstraction to make things play nice together.


To sum up, I would really appreciate YOUR feedback about the API and any kind of suggestion or things that you would like to see in future API. I’ll release the code later this week with a short demo to get you going.

 

Oren Ellenbogen