ibox, Prototype, and JSON

In my current project, I’m doing some fancy-pants stuff to lookup UK addresses via a web service, then send them to the client using JSON. On the client end, I’m displaying the results in an ibox and then sending the results back to the main form. Woah!

The first challenge was getting the ibox to open and display the form correctly. I chose to use a hidden div as my “form”, and let the ibox display it on the screen when appropriate. It all seemed to work correctly, however when I tried to read the values out of the fields on the ibox form, it kept telling me they were empty!

After a lot of mucking around, cursing, and rude gestures directed at the computer – you know, the standard debugging drill – I worked out that when you use a hidden div as your ibox, it actually *clones* the entire InnerHTML of the hidden div! So in effect, you get *two* of every field with duplicate IDs. And, since the HTML generated by ibox goes at the *end* of your document, when you call document.getElementById, you get back the *first matching element*, which will always be the one that’s still safely hidden away in your form. Handy – not!!

But never fear, the solution is actually quite simple. You just have to create an external file containing your ibox form, and then use that as the HREF in your link:


<a href="FindAddress.aspx" rel="ibox&height=400" title="Find an address">Find address</a>

Ahh, finally things started working properly! So now that I could read the postcode that the user entered, I wanted to hit a handler to…. err… “handle” the web service request. To do that, I used prototype.js – a javascript library with a whole bunch of wicked cool functionality (all of which is way beyond the scope of this article). Check it out -to execute a cross browser friendly AJAX request, you simply do this:


  var url = "Handlers/FindAddressHandler.ashx?Id=" + id;
  new Ajax.Request(url, {
    onSuccess: OnAddressFound,
    onFailure: OnError
  });

Of course, you can inline the callback functions, but I wanted to separate them for readability. Anyway, the next part was setting up the FindAddressHandler. I won’t go into too much detail here as it’s just a standard implementation of IHttpHandler which then hits a web service. The part I want to talk about though is writing back the address object using JSON. A dude named Jason Newton King has written a brilliant library called Json.NET which makes life a hell of a lot easier!

Basically, you just have to create a JsonWriter, then serialise the properties of your object that you want to send back to the client. So in my case with an Address object (stored in local variable “address”):


StringBuilder builder = new StringBuilder();
using (JsonWriter writer = new JsonWriter(new StringWriter(builder))) {
  writer.WriteStartObject();
  writer.WritePropertyName("PostCode");
  writer.WriteValue(address.Postcode);
  writer.WritePropertyName("Address1");
  writer.WriteValue(address.Line1);
  writer.WritePropertyName("Address2");
  writer.WriteValue(address.Line2);
  writer.WritePropertyName("Address3");
  writer.WriteValue(address.Line3);
  writer.WritePropertyName("PostalTown");
  writer.WriteValue(address.PostTown);
  writer.WriteEndObject();

  writer.Flush();
}

_context.Response.AddHeader("X-JSON", builder.ToString());

Easy, right? So the thing to note here, besides how simple it is to persist your object in JSON, is that I’m sending back the JSON string in a response header called “X-JSON”. Now back on the client side again – one of the bonus features of Prototype is that it automatically interprets whatever is in the “X-JSON” header, and builds your objects for you! So, here’s the code I wrote for my client-side callback:


function OnAddressFound(transport, address) {
    $("txtAddress1").value = address.Address1;
    $("txtAddress2").value = address.Address2;
    $("txtAddress3").value = address.Address3;
    $("txtPostCode").value = address.PostCode;
    $("txtPostalTown").value = address.PostalTown;

    hideIbox();
}

The first argument – transport – is the XmlHttpRequest object which was used. (You can find a great document which outlines the properties of the XmlHttpRequest object on the Apple Developer Connection website). The second argument is the object which Prototype interpreted from the X-JSON response header. You can see also that prototype implements a function – $ – which is effectively a suped-up version of document.getElementById.

Using all of these technologies together was surprisingly easy! I’m super impressed with how you can grab so many rich frameworks to enhance your websites, all for free!

Posted in Asp.Net, C#, Javascript at August 2nd, 2007. No Comments.

Skipping the Header in ItemDataBound

I often subscribe to the ItemDataBound event in a repeater to perform custom logic for each item within the repeater (for example, performing some custom calculations). When the repeater includes a header though, more often than not, you want to skip over the header row, since you don’t want to perform your custom calculations on that row. Until now, the way I did this was like this:


private void OnItemDataBound(object sender, RepeaterItemEventArgs e) {
    // skip header row
    if (e.Item.ItemIndex < 0) {
        return;
    }

    // custom logic
}

Today however, I found out there's a nicer way:


private void OnItemDataBound(object sender, RepeaterItemEventArgs e) {
    // skip header row
    if (e.Item.ItemType == ListItemType.Header) {
        return;
    }

    // custom logic
}

Sure, given that both ways work equally well, it seems as though the difference is for aesthetics only (i.e it's nicer to read); but there are actually two other big advantages:

  1. It is not tied into the implementation of the repeater - that is, it does not rely on the header row index being less than zero; and
  2. You can use the ListItemType enumeration to detect many different types of items - for example, the Footer row for performing summary calculations.

Posted in Asp.Net, Uncategorized at July 31st, 2007. No Comments.

Internet Explorer script tag failure for valid xhtml

Boy, what a day!

I was working on the weirdest bug with a colleague today where we were receiving a javascript “Object expected” error when we migrated a page into our new ASP .Net Master Page format.

We thought we hadn’t made any breaking changes, all we had done was move the <script> tags into the MasterPage file from the content page.

That didn’t work, so we created a header content place holder in the master page <head> element and in the content page put back the <script> includes. That didn’t work either.

We then included the <script> tags in both the master and content page. That seemed to work. Very odd.

In the end after many attempts to figure out what was going wrong, we found the problem was with how MSIE parses <script> tags, it cannot use self closing tags or an empty element – ie. <script … />.

It has to have the <script></script> tag.

For more info check out quirksmode.org.

Posted in .Net, Asp.Net, Javascript at January 11th, 2007. 1 Comment.

Sql timeout – a trap for young players!

I was talking to one of the guys at work about Sql timeouts. He had a long running operation – about 40 seconds – so to compensate for this, he set the timeout on his connection string to one minute:


<connectionStrings>
  <add name="cs"
    connectionString="Data Source=localhost;Initial Catalog=MyDB;Connection Timeout=60;"
</connectionStrings>

Sure looks OK, but as it turns out, this wasn’t working for him. The reason is actually quite straightforward – the Connection Timeout property is used to specify how long the application will wait to establish a connection to the server before giving up and throwing an exception. In most cases (where connections are properly managed), the connection will be returned almost instantaneously, hence changing this value is usually not required.

Instead, the timeout that he needed to change was the CommandTimeout on the SqlCommand object which was being passed to the database.


  SqlCommand command = new SqlCommand();
  command.CommandTimeout = 60;

As the MSDN doco states, this property "Gets or sets the wait time before terminating the attempt to execute a command and generating an error". And sure enough, once he changed this value to 60, everything was dandy.

Posted in Asp.Net, Sql Server at December 22nd, 2006. 1 Comment.

Using Resharper Reformat Code on aspx pages

Today, I spent some time trying to debug an error I was getting with some of my ASP .Net 2.0 pages.

All of sudden IIS wouldn’t load my pages saying that they did not extend System.Web.UI.Page, when on inspection of the codebehind file I was sure they did.

The problem was that I ran a Resharper 2.0 – Reformat Code (ctrl-alt-f) on my web application with the shorten references item checked. This changed the way in which the page directive worked on the aspx page.

Following is an example that illustrates what the file was originally defined as and what the reformat did to it to cause the application to blow up.

Original syntax


<%@ Page language="c#"
               Codebehind="default.aspx.cs"
               AutoEventWireup="True"
               Inherits="Com.CompanyName.Default"
               EnableSessionState="False"
               EnableViewState="False"%>


  
    Don't use reformat code with shorten references checked.
  
		


Resharper Reformat


Resharper Reformat Code Syntax


<%@ Page language="c#"
        Codebehind="default.aspx.cs"
        AutoEventWireup="True"
        Inherits="Default"
        EnableSessionState="False"
        EnableViewState="False"%>
<%@ Import namespace="System.Web.UI.WebControls"%>
<%@ Import namespace="Com.CompanyName"%>


  
    Don't use reformat code with shorten references checked.
  
				


The reformatted syntax takes the namespace of the Inherits attribute in the Page directive shortening it to “Default” from “Com.CompanyName.Default”. To do this, it has imported the “Com.CompanyName” namespace into the aspx page.

Now because .Net 2.0 defaults non-namespaced elements to the global namespace, the designer file, no longer belongs to the Com.CompanyName namespace however the codebehind page still does.

This causes the conflict throwing the error.

The error message

A trap for young players.

Posted in .Net, Asp.Net, Development, Uncategorized at December 22nd, 2006. 1 Comment.

Accessing Properties/Methods of a Page through an embedded UserControl

Sometimes it’s necessary to access a method/property on a Page from the UserControl code.

Eg.

We have a Page that has a label on it. A UserControl is embedded in that page. The UserControl has a DropDownList of values. When the value in the DropDownList is changed, we want the UserControl to change the value of Page’s label to reflect the selected value of the drop down list.

Now because the UserControl is associated with the Page using aggregation and there is no reference back to the Page instance it becomes a little tricky to do this.

We could pass a reference to the label in the UserControl but once we do that, we are creating a tighter coupling between the Page and UserControl thus making it difficult to re-use the UserControl for Pages that don’t have a label that needs modification.

Don’t worry though! The Event Handler (or Observer) pattern is very handy and comes into play to enable a communication mechanism that gets around the coupling problem.

In the UserControl declare a public property that accepts and returns an EventHandler delegate.

Eg.



public class ExampleUserControl : UserControl {

	protected DropDownList automobileTypes;
	private EventHandler automobileChangeHandler;

	public EventHandler AutomobileChangeHandler {
		get { return automobileChangeHandler; }
		set { automobileChangeHandler = value; }
	}

Now call the declared EventHandler at the appropriate execution point.

Eg.



	...
        ...

	private void InitializeComponent() {
 	     this.Load += new System.EventHandler(this.Page_Load);
             automobileTypes.SelectedIndexChanged += new EventHandler(automobileTypes_SelectedIndexChanged);
	}

	private void automobileTypes_SelectedIndexChanged(object sender, EventArgs e) {
		if (AutomobileChangeHandler != null) {
			AutomobileChangeHandler(automobileTypes.SelectedValue, e);
		}

	}

In the Page class create a method to be executed by the UserControl’s event handler. Define the logic that the UserControl’s event is to trigger on the Page object.

Eg.



public class ExamplePage : Page {

	protected Label name;
	protected ExampleUserControl euc; 

	private void ExampleUserControl_Changed(object sender, EventArgs e) {
		name.Text = String.Format("You have selected - {0}", sender as string);
	}

        override protected void OnInit(EventArgs e) {
		InitializeComponent();
		base.OnInit(e);
	}

	private void InitializeComponent() {
		this.Load += new System.EventHandler(this.Page_Load);
		euc.AutomobileChangeHandler += new EventHandler(ExampleUserControl_Changed);
	}

	#endregion
}

Thus allowing a UserControl to trigger events in the page object, without explicitly knowing about the class in which the UserControl resides.

Posted in .Net, Asp.Net, C#, Development at December 6th, 2006. 2 Comments.

Formatting using Eval

I can never remember the syntax to format a string when using the Eval statement, so once and for all I decided to try and commit it to memory by writing it down here.

In a DataBound control, you can use Eval to evaluate a public property on the DataItem that is being bound to the control. For example, if your DataItem has a public property called Name, you may use this statement to output the value of the property:

<%# Eval("Name") %>

The Eval method also has an overload which takes a format string. So far as I can figure, this format string is used in a similar vain to String.Format, whereby you supply the formatting string by numbered parameters. (Aside: The numbering system seems pretty pointless to me, since you’d almost always have only a single parameter to pass, wouldn’t you?).

Anyway – to get to the point – you can use the format string as follows: Presuming your DataItem has a property called “StartDate” which returns a DateTime, you can format the DateTime in the format “1 Nov 2006″ using the following code:

<%# Eval("StartDate", "{0:dd MMM yyyy}") %>

Posted in Asp.Net, C# at November 20th, 2006. No Comments.

function $

A while back, Bender sent me a link to a prototype.js file that pretty much claimed to be a web developers best friend. It certainly has some interesting features, and one that I really liked was the “$” function. Basically, the developer had written the function to return you an array of the elements that you asked for by id. So in effect, if you wrote -

var elements = $("txtName", "txtPhone", "txtCountry");

- then you would be returned an array containing a reference to each of those form elements (presuming that they exist, of course ;-))

Well that’s all fine and dandy, but more often than not I find myself trying to find elements in that are declared as: runat=”server”. And if those elements are nested in a UserControl, then you have to know how their id will be transformed at runtime by ASP.NET (for example, “txtName” may become “ctl00_main_sidebar_txtName”). So, with this in mind, I wrote my own version of the $ function which took care of this situation for me:


/*
 * Find an element based on the provided strings
 *
 * elementId:   Server-side id of the element to find (e.g. "txtName")
 * tagName:     The runtime tag of the element (e.g. "input")
 * elementType: The runtime value of the "type" attribute for the element,
 *              if it exists (e.g. "text")
 */
function $(elementId, tagName, elementType) {
    if (!tagName || tagName == "") {
        return document.getElementById(elementId);

    } else if (tagName) {
        var elements = document.getElementsByTagName(tagName, "gi");
        var typeRegex = elementType && elementType != "" ? new RegExp(elementType) : null;

        for (var i = 0; i < elements.length; i++) {
            if (typeRegex) {
                if (!elements[i].type || !typeRegex.exec(elements[i].type)) {
                    continue;
                }
            }

            if (elements[i].id && elements[i].id.indexOf(elementId) >= 0) {
                return elements[i];
            }
        }
    }

    return null;
}

It’s possibly not the most efficient piece of code that you’ll ever come across, but it does the job perfectly.

Posted in Asp.Net, Javascript at November 16th, 2006. 1 Comment.
Quickduck logo