Tuesday, January 29, 2008

Write your own DOM friendly extension methods for HtmlElement in Volta

logo-volta

I know there are GetById, GetById<> methods in Document object. But, I often miss a method that I feel should be in Volta, which iterates through its child nodes and find an element for me. Let us say, there is a HTML like the following:

<div id="divContainer">
<
b>Some text</b>
<
div id="firstDiv">
<
i>Some more text</i>
</
div>
<
div id="secondDiv">
Okay, I gotta go now
</div>
<
div anyAttribute="anyValue">
Babye
</div>
</
div>

The most important thing is, I can not get the last div by Document.GetById, because instead of id I chose anyAttribute. So, I wrote my own extension method which can run into not only Div but also any HtmlElement, and can find me the desired HtmlElement inside the prior one with the anyAttribute and anyValue. To make my intention clear, I'd like to show how I'd like to use that extension method:

var divContainer = Document.GetById<Div>("divContainer");
var anyDiv = divContainer.Find<Div>("anyAttribute", "anyValue");

if(anyDiv != null)
anyDiv.InnerHtml += "guys!";

So, I'd like to call my extension method Find<> which will take the type I'm looking for (in this case a Div) and that HtmlElement should have an attribute "anyAttribute" that contains "anyValue". Here is how I make up the extension method:

public static class HtmlExtensions
{
public static T Find<T>(this T parent, string attribute, string value)
where T : HtmlElement
{
var element = parent.FirstChild;

while(element != null)
if (element.IsProper<T>(attribute, value))
return element as T;
else
element = element.NextSibling;

return null;
}

public static bool IsProper<T>(this DomNode element, string attribute, string value)
where T : HtmlElement
{
if (element.GetType() == typeof(T) &&
element.Attributes != null &&
element.Attributes.GetNamedItem(attribute) != null &&
element.Attributes.GetNamedItem(attribute).Value == value)

return true;

return false;
}
}

This method can iterate only one depth. Multi depth implementation can be done by running a simple DFS which is left to you guys. Note one thing, I have called one extension method "IsProper" inside another extension method, and there is no harm in it. So, this is how you can add your own extension methods to the HtmlElement.

Saturday, January 26, 2008

Appearing on Microsoft Volta team blog

Microsoft Volta team blogged about me and one of my articles: http://labs.live.com/volta/blog/Volta+How+To+Flickr+Widget.aspx

VoltaTeamBlog

[New Article] ASP.NET AJAX Best Practices

While we develop AJAX applications, we often carelessly ignore giving up bad practices, which cause effects which are not so significantly visible when the site is not so large in volume. But, it’s often severe performance issue when it is the case for sites that make heavy use of AJAX technologies such as Pageflakes, NetVibes etc.

There are so many AJAX widgets in one page that little memory leak issues combined may even result the site crash into very nasty “Operation aborted”. There are a lot of WebService calls, lot of iterations among collection so that inefficient coding in a whole lead to make site very heavy, browser eats up a lot of memory, requires very costly CPU cycles, and ultimately causes unsatisfactory user experience. In this article many of such issues are demonstrated in the context of ASP.NET AJAX.

http://www.codeproject.com/KB/ajax/AspNetAjaxBestPractices.aspx

Friday, January 25, 2008

HttpRequestFactory vs. XMLHttpRequest in Volta

HttpRequestFactory was designed for use by tiersplitting internally and was not supposed to be exposed as part of the Volta API as Danny van Velzen from Microsoft Volta team told me today. So, its better if you use XMLHttpRequest instead because this factory class might not show up in the later releases. You will find this class in Microsoft.LiveLabs.Volta.Xml namespace.  As like as JavaScript's one, in this .NET version you can also Open URL, specify method name, and of course pass credentials. You can track response text, xml, status code, status text and also you can abort.

To retrieve your content, you must subscribe to ReadyStateChange event with a HtmlEventHandler which you can find in Microsoft.LiveLabs.Volta.Html namespace and check the status code. If it is 200 that means "HTTP OK", you can take the ResponseText or ResponseXML. See this example:

string content = string.Empty;
var request = new XMLHttpRequest();

request.ReadyStateChange += delegate()
{
if (request.Status == 200)
content = request1.ResponseText;
};

request.Open("POST", "http://tanzimsaqib.com/feed/", true);

However, you cannot fetch cross domain content by XMLHttpRequest. The Volta compiler creates client side JavaScript XMLHttpRequest and lets developers write code in .NET friendly way. So, I do not think there is any way to retrieve cross domain content in Volta, and leaving us on the same old HttpRequest class.

Friday, January 18, 2008

[New Article] Building a Volta Control : A Flickr Widget

This is my first article which is based on the first CTP of Volta considering its current limitations. You will see how you can create a Volta control that the compiler can convert into an AJAX Widget without requiring us writing a single line of JavaScript code: http://dotnetslackers.com/articles/aspnet/BuildingAVoltaControlAFlickrWidget.aspx

Monday, January 14, 2008

ASP.NET AJAX Best Practices: Avoid String concatenation, use Array instead

Don't you think the following block of code has written keeping every possible good practice in mind? Any option for performance improvement?

function pageLoad()
{
var stringArray = new Array();

// Suppose there're a lot of strings in the array like:
stringArray.push('<div>');
stringArray.push('some content');
stringArray.push('</div>');

// ... code edited to save space

var veryLongHtml = $get('divContent').innerHTML;
var count = stringArray.length;

for(var i=0; i<count; ++i)
veryLongHtml += stringArray[i];
}



Well, as you see the innerHTML of the div has been cached so that browser will not have to access the DOM every time while iterating through stringArray, thus costlier DOM methods are being avoided. But, inside the body of the loop the JavaScript interpreter has to perform the following operation:



veryLongHtml = veryLongHtml + stringArray[i];



And the veryLongHtml contains quite a large string which means in this operation the interpreter will have to retrieve the large string and then concatenate with the stringArray elements in every iteration. One very short yet efficient solution to this problem is using join method of the array like the following, instead of looping through the array:



veryLongHtml = stringArray.join(''); 



However, this is very efficient than the one we were doing, since it joins the array with smaller strings which requires less memory.

ASP.NET AJAX Best Practices: Avoid String concatenation, use Array instead

Don't you think the following block of code has written keeping every possible good practice in mind? Any option for performance improvement?

function pageLoad()
{
var stringArray = new Array();

// Suppose there're a lot of strings in the array like:
stringArray.push('<div>');
stringArray.push('some content');
stringArray.push('</div>');

// ... code edited to save space

var veryLongHtml = $get('divContent').innerHTML;
var count = stringArray.length;

for(var i=0; i<count; ++i)
veryLongHtml += stringArray[i];
}



Well, as you see the innerHTML of the div has been cached so that browser will not have to access the DOM every time while iterating through stringArray, thus costlier DOM methods are being avoided. But, inside the body of the loop the JavaScript interpreter has to perform the following operation:



veryLongHtml = veryLongHtml + stringArray[i];



And the veryLongHtml contains quite a large string which means in this operation the interpreter will have to retrieve the large string and then concatenate with the stringArray elements in every iteration. One very short yet efficient solution to this problem is using join method of the array like the following, instead of looping through the array:



veryLongHtml = stringArray.join(''); 



However, this is very efficient than the one we were doing, since it joins the array with smaller strings which requires less memory.

How to solve: Server Controls can't be accessed in View's code-behind in ASP.NET MVC

It's still long way to go for a final release of ASP.NET MVC, the one I've been using right now is just a December CTP. But, like me you might be experiencing this confusing problem. The server controls that you put in a View (ViewContentPage) can not be found in code-behind page. The reason behind it is - the Views don't have a back-end designer code file. I believe it's just a bug or they could not find time to fix/look into it. I'm sure it will be fixed in any of the upcoming versions.

To enable this, switch to Solution Explorer, right click on the View you are interested in, and choose Convert to Web Application. Now, you will find the server controls in code-behind file.

Saturday, January 12, 2008

ASP.NET AJAX Best Practices: Introduce function delegates

Take a look at the following loop. This loop calls a function in each iteration and the function does some stuffs. Can you think of any performance improvement idea?

for(var i=0; i<count; ++i)
processElement(elements[i]);



Well, for sufficiently large array, function delegates may result in significant performance improvement to the loop.



var delegate = processElement;

for(var i=0; i<count; ++i)
delegate(elements[i]);



The reason behind performance improvement is, JavaScript interpreter will use the function as local variable and will not lookup in its scope chain for the function body in each iteration.

Friday, January 11, 2008

ASP.NET AJAX Best Practices: Introduce DOM elements and function caching

We have seen DOM caching before and function delegation is also a kind of function caching. Take a look at the following snippet:
for(var i=0; i<count; ++i)
$get('divContent').appendChild(elements[i]);

As you can figure out the code is going to be something like:

var divContent = $get('divContent');

for(var i=0; i<count; ++i)
divContent.appendChild(elements[i]);

That is fine, but you can also cache browser function like appendChild. So, the ultimate optimization will be like the following:

var divContentAppendChild = $get('divContent').appendChild;

for(var i=0; i<count; ++i)
divContentAppendChild(elements[i]);

Thursday, January 10, 2008

ASP.NET AJAX Best Practices: Problem with switch

Unlike .NET languages or any other compiler languages, JavaScript interpreter can not optimize switch block. Especially when switch statement is used with different types of data, it's a heavy operation for the browser due to conversion operations occur in consequences, it's an elegant way of decision branching though.

Wednesday, January 9, 2008

ASP.NET AJAX Best Practices: Avoid using Array.length in a loop

In one of my earlier posts, I talked about DOM element accessing in a loop but forgot to talk about a very common, yet performance issue in AJAX. We often use code like the following:

var items = []; // Suppose a very long array 
for(var i=0; i<items.length; ++i)
; // Some actions

It can be a severe performance issue if the array is so large. JavaScript is an interpreted language, so when interpreter executes code line by line, every time it checks the condition inside the loop, you end up accessing the length property every time. Where it is applicable, if the contents of the array does not need to be changed during the loop's execution, there is no necessity to access the length property every time. Take out the length in a variable and use in every iteration:

var items = []; // Suppose a very long array 
var count = items.length;
for(var i=0; i<count; ++i)
; // Some actions

Tuesday, January 8, 2008

Make web.config work in Volta

Ever wondered how to make web.config work in Volta first CTP release? Simply add a web.config file and add content to it? Unfortunately this is not the case in Volta at least in the first CTP. Five steps to get it done:

  1. Add a web.config file
  2. Add content to simply by copying from other web.config file
  3. Right click on web.config from the Solution Explorer and then Properties
  4. Choose Build Action to Embedded Resource
  5. In your Volta Page Designer CS file, add the following line of code:
[assembly: VoltaFile("web.config")]



 

ASP.NET AJAX Best Practices: Avoid getters, setters

Make minimum use of setters and getters if possible. Such accessors look like .NET like kind of beautiful properties, but these create new more scopes for JavaScript interpreter to deal with. If applicable, try directly setting/getting the private variable itself rather implementing methods for getters, setters.

Monday, January 7, 2008

ASP.NET AJAX Best Practices: Reduce scopes

It's not pretty common. But, if you ever encounter such code, be sure it's a very bad practice. Introducing more scopes is a performance issue for JavaScript interpreter. It adds a new scope in the ladder. See the following sample scope:

function pageLoad()
{
scope1();
function scope1()
{
alert('scope1');
scope2();

function scope2()
{
alert('scope2');
}
}
}



Introducing more scopes enforces the interpreter to go through new more sections in the scope chain that it maintains for code execution. So, unnecessary scopes reduce performance and it's a bad design too.

Sunday, January 6, 2008

ASP.NET AJAX Best Practices: Avoid using your own method while there is one

Avoid implementing your own getElementById method that will cause script to DOM marshalling overhead. Each time you traverse the DOM and look for certain HTML element requires the JavaScript interpreter to marshalling script to DOM. It's always better to use getElementById of document object. So, before you write a function, make sure similar functionality can be achieved from some other built-in functions.

Friday, January 4, 2008

ASP.NET AJAX Best Practices: Careful with DOM element concatenation

It's a very common bad practice. We often iterate through array, build HTML contents and keep on concatenating into certain DOM element. Every time you execute the block of code under the loop, you create the HTML markups, discover a div, access the innerHTML of a div, and for += operator you again discover the same div, access its innerHTML and concatenate it before assigning.

function pageLoad()
{
var links = ["microsoft.com", "tanzimsaqib.com", "asp.net"];

$get('divContent').innerHTML = 'The following are my favorite sites:'

for(var i=0; i<links.length; ++i)
$get('divContent').innerHTML += '<a href="http://www.' + links[i] + '">http://www.' + links[i] + '</a><br />';
}



However, as you know accessing DOM element is one the costliest operation in JavaScript. So, it's wise to concatenate all HTML contents in a string and finally assign to the DOM element. That saves a lot of hard work for the browser.



function pageLoad()
{
var links = ["microsoft.com", "tanzimsaqib.com", "asp.net"];
var content = 'The following are my favorite sites:'

for(var i=0; i<links.length; ++i)
content += '<a href="http://www.' + links[i] + '">http://www.' + links[i] + '</a><br />';

$get('divContent').innerHTML = content;
}

Thursday, January 3, 2008

ASP.NET AJAX Best Practices: Use more "var"

Less use of "var" can result into wrong calculation as well as mistake in logic control. And also JavaScript interpreter finds it hard to determine the scope of the variable if var is not used. Consider the following simple JavaScript code:

function pageLoad()
{
i = 10;
loop();
alert(i); // here, i = 100
}

function loop()
{
for(i=0; i<100; ++i)
{
// Some actions
}
}



Here you see, the loop uses the variable i used before in pageLoad. So, it brings a wrong result. Unlike .NET code, in JavaScript variables can go along with the method calls. So, better not confuse the interpreter by using more "var" in your code:



function pageLoad()
{
var i = 10;
loop();
alert(i); // here, i = 10
}

function loop()
{
for(var i=0; i<100; ++i)
{
// Some actions
}
}

Make HTML controls discoverable in Volta Control

 

When a Volta control is rendered, the ID attribute of the generated HTML is changed to something like _vcId_1_DivName which is inconvenient to find from code. But the ID attribute stays the same in case of Volta Page, so it is discoverable by ID like this:

Div divContent = Document.GetById<Div>("divContent");


However, if you add HTML controls to the control like the following, the ID is not changed during the rendering:



public VoltaControl1() : base("VoltaControl1.html")
{
InitializeComponent();

Button btnClick = new Button();
btnClick.InnerText = "Click!";
btnClick.Id = "btnClick";
this.Add(btnClick);
}


If you don't prefer this way and seriously want to write your own HTML in the control's html page, you might find the following snippet useful. But, remember in this case you will use name attribute of the html element instead of ID.



// Usage: var element = GetElementByName(Document.GetElementsByTagName("div"), "divWidget");
private HtmlElement GetElementByName(HtmlElementCollection elements, string name)
{
foreach (var element in elements)
{
DomAttribute nameAttribute = element.Attributes.GetNamedItem("name");
if (nameAttribute != null)
if (nameAttribute.Value == name)
return element;
}

return null;
}

Wednesday, January 2, 2008

Making cross domain AJAX call using Volta

Making a cross domain AJAX call in Volta is piece of cake. Volta compiler generates necessary client codes to make it work. Here is a snippet that can make an AJAX call to some Url and fetch data:

public void DownloadPhotos()
{
IHttpRequest request = HttpRequestFactory.Create();
request.AsyncSend("POST", URL, string.Empty,
delegate(string response)
{
OnPhotosLoaded(new PhotosLoadedEventArgs(response));
});
}



Both IHttpRequest and HttpRequestFactory classes can be found in the Microsoft.LiveLabs.Volta.MultiTier namespace. AsyncSend method performs the asynchronous call and calls back the delegate defined where OnPhotosLoaded event is fired to notify the subscriber of this event that the data has just arrived.

Tuesday, January 1, 2008

Namespace Alias Qualifier - to get rid of crazy coding

Let us say somebody in your company loves crazy coding and really do not bother about his/her codes affect others. (S)He put class name System and a constant Console and now wondering how come a simple Console.WriteLine does not compile:

class System
{
int Console = 10;

static void Main(string[] args)
{
Console.WriteLine("Hello World!"); // Compile time error
System.Console.WriteLine("Hello World!"); // Compile time error
}
}


Making use of global::System.Console must solve your problem:



class System
{
int Console = 10;

static void Main(string[] args)
{
global::System.Console.WriteLine("Hello World!");
global::System.Console.WriteLine("Hello World!");
}
}

However, ever thought of a scenario where there can be same class name under two different namespaces? Here comes the role of Namespace Alias Qualifier. In namespace declaration by "using", aliases can be assigned to namespaces so that they might be useful in later part of the code as shorthand and most importantly will solve the problem of ambiguity:

using sys = System;
using mine = MyProject.Process;
...
...
sys.Console.WriteLine(mine.Console["width"]);