I have been working on an idea, one that assumed that if you remember the content sent to an UpdatePanel, you can send only the difference next time you update it. That would mean that you could use only one UpdatePanel, maybe in the MasterPage, and update only changes, wherever they'd be and no matter how small.

However, I also assumed that if I set the innerHTML property of an HTML element, the value will remain the same. In other words that elem.innerHTML=content; implied that elem.innerHTML and content are identical at the end of the operation. But they were not! Apparently the browser (each flavour in its own way) interprets the string that you feed it then creates the element tree structure. If you query the innerHTML property, it uses the node structure to recreate it.

So comparing the value that you've fed it to the actual value of innerHTML after the operation, you see quoted attribute values, altogether removed attributes when they have the default value, uppercased keywords, changed attribute order and so on and so on. FireFox only adds quotes as far as I see, but you never know what they'll do next.

On the bright side, now that my idea had been torn to shreds by the browser implementation, I now have an answer to all those stuck up web developers that consider innerHTML unclean or unstructured and criticize the browsers for not being able to render as fast when using DOM methods. The innerHTML property is like a web service. You feed it your changes in (almost) XML format and it applies it on the browser. Since you pretty much do the same when you use any form of web request, including Ajax, you cannot complain.

Update: On June 20th 2009, Codeplex notified me that the patch I did for the ACT has been applied. I haven't tested it yet, though. Get the latest source (not latest stable version) and you should be fine.

The Ajax Control Toolkit has a PopupExtender module that is used throughout the library in whichever controls need to show above other controls. I wanted to use the Calendar Extender in my web site, but the calendar appeared underneath other controls. I checked it out and it had a zIndex of 1000, which should have been enough. I took me an hour to realise that in the toolkit code zIndex was a property of the div element, not of the div style!

A download of the latest version from Feb 29 shows the problem is still there. The fix? go to the PopupExtender folder in the source code, open the PopupBehaviour.js file, search for a line that looks like this:
element.zIndex = 1000;
and replace it with
element.style.zIndex = 1000;
. Now it works!

The issue is already in the AjaxControlToolKit issue tracker, but it was not addressed yet.

Update 19 February 2016:
I've done the test again, using another computer and .Net 4.6.1. The speed of filling the DataTableReplacement class given at the end of the article, plus copying the data into a DataTable object is 30% faster than using a DataTable directly with BeginLoadData/EndLoadData and 50% faster than using DataTable without the LoadData methods.

Now for the original post:

It was about time I wrote a smashing IT entry. Here is to the obnoxious DataTable object, something about I have written before of bugs and difficulty in handling. Until now I haven't really thought about what kind of performance issues I might face when using it. I mean, yeah, everybody says it is slow, but how slow can it be? Twice as slow? Computers are getting faster and faster, I might not need a personal research into this. I tried to make a DataTable replacement object once and it was not really compatible with anything that needed DataTables so I gave up. But in this article I will show you how a simple piece of code became 7 times faster when taking into account some DataTable issues.

But let's get to the smashing part :) I was using C# to transform the values in a column from a DataTable into columns. Something like this:

Name Column Value
George Money 100
George Age 31
George Children 1
Jack Money 150
Jack Age 26
Jack Children 0
Jane Money 300
Jane Age 33
Jane Children 2



and it must look like this:

Name Money Age Children
George 100 31 1
Jack 150 26 0
Jane 300 33 2



I have no idea how to do this in SQL, if you have any advice, please leave a comment.
Update: Here are some links about how to do it in SQL and SSIS:
Give the New PIVOT and UNPIVOT Commands in SQL Server 2005 a Whirl
Using PIVOT and UNPIVOT
Transposing rows and columns in SQL Server Integration Services

Using PIVOT, the SQL query would look like this:

SELECT * 
FROM #input
PIVOT (
MAX([Value])
FOR [Column]
IN ([Money],[Age],[Children])
) as pivotTable


Anyway, the solution I had was to create the necessary table in the code behind add a row for each Name and a column for each of the distinct value of Column, then cycle through the rows of the original table and just place the values in the new table. All the values are present and already ordered so I only need to do it using row and column indexes that are easily computed.

The whole operation lasted 36 seconds. There were many rows and columns, you see. Anyway, I profiled the code, using the great JetBrains dotTrace program, and I noticed that 30 seconds from 36 were used by DataRow.set_Item(int, object)! I remembered then that the DataTable object has two BeginLoadData and EndLoadData methods that disable/enable the checks and constraints in the table. I did that and the operation went from 36 to 27 seconds.

Quite an improvement, but the bottleneck was still in the set_Item setter. So, I thought, what will happen if I don't use a DataTable at all. After all, the end result was being bound to a GridView and it, luckily, knows about object collections. But I was too lazy for that, as there was quite a complicated binding code mess waiting for refactoring. So I just used a List of object arrays instead of the DataTable, then I used DataTable.Rows.Add(object[]) from this intermediary list to the DataTable that I originally wanted to obtain. The time spent on the operation went from... no, wait

The time spent on the operation went from the 27 seconds I had obtained to 5! 5 seconds! Instead of 225.351 calls to DataRow.set_Item, I had 1533 calls to DataRowCollection.Add, from 21 seconds to 175 miliseconds!

Researching the reflected source of System.Data.dll I noticed that the DataRow indexer with an integer index was going through

DataColumn column=_columns[index]; return this[column];

How bad can it get?! I mean, really! There are sites that recommend you find the integer index of table columns and then use them as integer variables. Apparently this is NOT the best practice. Best is to use the DataColumn directly!

So avoid the DataRow setter.

Update July 18, 2013:

Someone requested code, so here is a console application with some inline classes to replace the DataTable in GridView situations:

class Program
{
    static void Main(string[] args)
    {
        fillDataTable(false);
        fillDataTable(true);
        fillDataTableWriter();
        Console.ReadKey();
    }

    private static void fillDataTable(bool loadData)
    {
        var dt = new DataTable();
        dt.Columns.Add("cInt", typeof(int));
        dt.Columns.Add("cString", typeof(string));
        dt.Columns.Add("cBool", typeof(bool));
        dt.Columns.Add("cDateTime", typeof(DateTime));
        if (loadData) dt.BeginLoadData();
        for (var i = 0; i < 100000; i++)
        {
            dt.Rows.Add(dt.NewRow());
        }
        var now = DateTime.Now;
        for (var i = 0; i < 100000; i++)
        {
            dt.Rows[i]["cInt"] = 1;
            dt.Rows[i]["cString"] = "Some string";
            dt.Rows[i]["cBool"] = true;
            dt.Rows[i]["cDateTime"] = now;
        }
        if (loadData) dt.EndLoadData();
        Console.WriteLine("Filling DataTable"+(loadData?" with BeginLoadData/EndLoadData":"")+": "+(DateTime.Now - now).TotalMilliseconds);
    }

    private static void fillDataTableWriter()
    {
        var dt = new DataTableReplacement();
        dt.Columns.Add("cInt", typeof(int));
        dt.Columns.Add("cString", typeof(string));
        dt.Columns.Add("cBool", typeof(bool));
        dt.Columns.Add("cDateTime", typeof(DateTime));
        for (var i = 0; i < 100000; i++)
        {
            dt.Rows.Add(dt.NewRow());
        }
        var now = DateTime.Now;
        for (var i = 0; i < 100000; i++)
        {
            dt.Rows[i]["cInt"] = 1;
            dt.Rows[i]["cString"] = "Some string";
            dt.Rows[i]["cBool"] = true;
            dt.Rows[i]["cDateTime"] = now;
        }
        var fillingTime = (DateTime.Now - now).TotalMilliseconds;
        Console.WriteLine("Filling DataTableReplacement: "+fillingTime);
        now = DateTime.Now;
        var newDataTable = dt.ToDataTable();
        var translatingTime = (DateTime.Now - now).TotalMilliseconds;
        Console.WriteLine("Transforming DataTableReplacement to DataTable: " + translatingTime);
        Console.WriteLine("Total filling and transforming: " + (fillingTime+translatingTime));
    }
}

public class DataTableReplacement : IEnumerable<IEnumerable<object>>
{
    public DataTableReplacement()
    {
        _columns = new DtrColumnCollection();
        _rows = new DtrRowCollection();
    }

    private readonly DtrColumnCollection _columns;
    private readonly DtrRowCollection _rows;

    public DtrColumnCollection Columns
    {
        get { return _columns; }
    }

    public DtrRowCollection Rows { get { return _rows; } }

    public DtrRow NewRow()
    {
        return new DtrRow(this);
    }

    public DataTable ToDataTable()
    {
        var dt = new DataTable();
        dt.BeginLoadData();
        _columns.CreateColumns(dt);
        _rows.CreateRows(dt);
        dt.EndLoadData();
        return dt;
    }

    #region Implementation of IEnumerable

    public IEnumerator<IEnumerable<object>> GetEnumerator()
    {
        foreach (var row in _rows)
        {
            yield return row.ToArray();
        }
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }

    #endregion
}

public class DtrRowCollection : IEnumerable<DtrRow>
{
    private readonly List<DtrRow> _rows;

    public DtrRowCollection()
    {
        _rows = new List<DtrRow>();
    }

    public void Add(DtrRow newRow)
    {
        _rows.Add(newRow);
    }

    public DtrRow this[int i]
    {
        get { return _rows[i]; }
    }

    public void CreateRows(DataTable dt)
    {
        foreach (var dtrRow in _rows)
        {
            dt.Rows.Add(dtrRow.ToArray());
        }
    }

    #region Implementation of IEnumerable

    public IEnumerator<DtrRow> GetEnumerator()
    {
        return _rows.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }

    #endregion
}

public class DtrRow
{
    private readonly object[] _arr;
    private readonly DataTableReplacement _dtr;

    public DtrRow(DataTableReplacement dtr)
    {
        _dtr = dtr;
        var columnCount = _dtr.Columns.Count;
        _arr = new object[columnCount];
    }

    public object this[string columnName]
    {
        get
        {
            var index = _dtr.Columns.GetIndex(columnName);
            return _arr[index];
        }
        set
        {
            var index = _dtr.Columns.GetIndex(columnName);
            _arr[index] = value;
        }
    }

    public object this[int columnIndex]
    {
        get
        {
            return _arr[columnIndex];
        }
        set
        {
            _arr[columnIndex] = value;
        }
    }

    public object[] ToArray()
    {
        return _arr;
    }
}

public class DtrColumnCollection
{
    private readonly Dictionary<string, int> _columnIndexes;
    private readonly Dictionary<string, Type> _columnTypes;

    public DtrColumnCollection()
    {
        _columnIndexes = new Dictionary<string, int>();
        _columnTypes = new Dictionary<string, Type>();
    }

    public int Count { get { return _columnIndexes.Count; } }

    public void Add(string columnName, Type columnType)
    {
        var index = _columnIndexes.Count;
        _columnIndexes.Add(columnName, index);
        _columnTypes.Add(columnName, columnType);
    }

    public int GetIndex(string columnName)
    {
        return _columnIndexes[columnName];
    }

    public void CreateColumns(DataTable dt)
    {
        foreach (var pair in _columnTypes)
        {
            dt.Columns.Add(pair.Key, pair.Value);
        }
    }
}


As you can see, there is a DataTableReplacement class which uses three other classes instead of DataColumnCollection, DataRowCollection and DataRow. For this example alone, the DtrRowCollection could have been easily replaced with a List<DtrRow>, but I wanted to allow people to replace DataTable wherever they had written code without any change to the use code.

In the example above, on my computer, it takes 1300 milliseconds to populate the DataTable the old fashioned way, 1000 to populate it with BeginLoadData/EndLoadData, 110 seconds to populate the DataTableReplacement. It takes another 920 seconds to create a new DataTable with the same data (just in case you really need a DataTable), which brings the total time to 1030. So this is the overhead the DataTable brings for simple scenarios such as these.

A while ago I wrote a quick post to remind me of how to use the AutoCompleteExtender, but recently I realised that it was terribly incomplete (pun not intended). I've updated it, but I also felt that I need to restructure the whole post, so here it is, with more details and more code fun.

First of all, a short disclaimer: I am not familiar with the ASP.Net Ajax javascript paradigm. If some of the things that I am doing seem really stupid, it's because I did it by trial and error, not by understanding why the code is as it is. Here it goes.

There are two ways in which to use the AutoCompleteExtender: using PageMethods or using web service methods. The details are in the previous post, I will only list the gotchas in this one.
  • PageMethods requirements:
    1. ScriptManager must have EnablePageMethods="true"
    2. The page method must have the form public static string[] MethodName(string prefixText, int count) AND THE SAME PARAMETER NAMES. If you change prefixText with text it will not work!
    3. The page method has to be public and STATIC
    4. No, it is not possible to declare the method in a web user control, it must be in the page
  • Web service requirements:
    1. The method must have the form public string[] MethodName(string prefixText, int count) AND THE SAME PARAMETER NAMES. If you change prefixText with text it will not work!
    2. The method has to be public and NOT STATIC
    3. The method must be marked as ScriptMethod
.

Now, the method can return an array different from a string array, but the only useful types there would be numerical or maybe dates. Any object that you send will ultimately be transformed into "[object Object]". There is a way to send a pair of value,text encoded in the strings, and for that you use:
AutoCompleteExtender.CreateAutoCompleteItem(text, value);

It doesn't help much outside the fact that in the client javascript events of the AutoCompleteExtender the first parameter will be the AutoCompleteExtender javascript object and the second an object with a _text and a _value properties.

One of the questions I noticed frequently on the web is: How do I show the user that there are no auto complete matches?. The easy solution is always to return at least one string in the string array that your method is returning. If there are no matches, make sure there is a "No Match" string in the list. But then the complicated part comes along: how do you stop the user from selecting "No Match" from the list? And I do have a solution. It seems that the text in the textbox is set based on the existence of a javascript object called control that has a set_text function. If the object or the function do not exist, then a simple textbox.value=text is performed. So I used this code:

string script = @"var tb=document.getElementById('" + tbAutoComplete.ClientID + @"');if (tb) tb.control={set_text:setText,element:tb};";
ScriptManager.RegisterStartupScript(Page,Page.GetType(),UniqueID+"_init",script,true);
to set the object for my textbox. And also the javascript code that looks liks this:
function setText(input) {
if (input=='No Match') return;
this.element.value=input;
}


These being said, I think that one can use the AutoCompleteExtender and know what the hell is making it not work.

Update: The 30 September 2009 release of the AjaxControlToolkit doesn't have the error that I fix here. My patch was applied in July and from September on the bug is gone in the official release as well. Good riddance! :)

==== Obsolete post follows

I've just downloaded the 29 feb 2008 release of the AjaxControlToolKit and I noticed that the TabContainer bug that I fixed in one of the previous posts did not work anymore. So the post is now updated with the latest fix.

Fixing TabContainer to work with dynamic TabPanels

Apparently, the guys that make the Ajax Control Toolkit are not considering this a bug, since I posted it a long time ago as well as a bunch of other folks and there are also some discussions about it on some forums.

This blog post is about ASP.Net Ajax calls (Update panel and such), if you are interested in aborting jQuery.ajax calls, just call abort() on the ajax return object.

Kamal Balwani asked for my help on the blog chat today and asked for the solution for a really annoying issue. He was opening a window when pressing a button on an ASP.Net page and that window used web services to request data from the server repeatedly. The problem was when the window was closed and FireFox (the error did not appear on Internet Explorer) showed a 'Sys is not defined' error on this javascript line: _this._webRequest.completed(Sys.EventArgs.Empty);.

It was a silly error, really. There was this javascript object Sys.Net.XMLHttpExecutor and it had a function defined called _onReadyStateChange where a completed function received Sys.EventArgs.Empty as an argument. At that time, though, the page was unloaded as well as any objects defined in it. I consider this a FireFox bug, as any javascript function should not try to access an object that was unloaded already.

Anyway, going through the Microsoft Ajax library is a nightmare. I am sure they had clear patterns in mind when they designed it this way but for me it was a long waste of time trying to get my head around it. Finally I've decided that the only solution here was to abort the last Ajax request and so I've reached these two posts:

Cancel a Web Service Call in Asp.net Ajax
How to cancel the call to web service.

Bottom line, you need to use the abort function on a WebRequestExecutor object which one can get from using the get_executor function on a WebRequest object which should be returned by a scriptmethod call.

But you see, when you execute TestService.MyMethod you get no return value. What you need to do is use TestService._staticInstance.MyMethod which returns the WebRequest object required! Good luck figuring that out without Googling for it.

From then on the ride was smooth: add an array of web requests and at the window.onbeforeunloading event, just abort them all.

Here is the code for the popup window:

<body onload = "runMethod();" onbeforeunload = "KillRequests();">

function runMethod() {
   if (!window._webRequests) window._webRequests = Array();
   _webRequests[_webRequests.length]
      = TestService._staticInstance
        .MyMethod(OnSuccess, OnTimeout);
   }


function OnSuccess(result) {
   //do something with the result
   setTimeout(runMethod, 500);
   }


function OnTimeout(result) {
   setTimeout(runMethod, 500);
   }


function KillRequests() {
   if (!window._webRequests) return;
   for (var c = 0; c < window._webRequests.length; c++) {
      if (window._webRequests[c]) {
         var executor = window._webRequests[c].get_executor();
         if (executor.get_started()) executor.abort();
         }
      }
   }

A chat user asked me the other day of how does one put the tabs in the AjaxToolKit TabContainer vertically and I had no idea. I've decided to do it today and write this blog post, maybe he'll come back and he'd get the answer.

So, the request is simple: take a web site with a TabContainer in it and make it show the tabs vertically. I can only assume that the vertical tabs would go on the left and the content in the right. So I took the Internet Developer Toolbar and analysed the html output of a page with four static tabs. I added a <style> tag with CSS classes and started making changes until it worked. Unfortunately, the same setup would not work on Firefox, so I had to repeat the process using Firebug to analyse the page output. In the end this is the result:
<style>
.ajax__tab_header {
float:left;
}
.ajax__tab_body {
/*float:left;*/
margin-left:220px;
}
.ajax__tab_outer {
display:block !important;
}
.ajax__tab_tab{
/*min-width:200px;*/
width:200px;
height:auto !important;
}
</style>
.

Add this on top of your page or include it in your CSS and the tabs will appear vertically.

Now for a bit of explaining.
  • First of all this does not overwrite the CSS that the TabContainer loads because it is organized under a general ajax__tab_xp class like: .ajax__tab_xp .ajax__tab_header .
  • Then the width of 200px is arbitrary. I used it to keep the vertical tabs at the same width. I tried using min-width first, but it won't display right in Firefox.
  • Another point is about the ajax__tab_body class that I tried to set up first as float left, which would place the body div next to the tabs div, however this breaks if the body tab is wider and the content would appear underneath the tabs div. Thanks to my colleague Romeo I used the margin-left trick. 220px is enough to work in both IE and Firefox. It can be made smaller (closer to 200px)if the default IE body margin would be 0.
  • The !important keyword is placed to overwrite some settings that are already set up in the original TabContainer CSS.
  • Last issue: now the right panel will be truncated if it gets too large. You should control the overflow of that div, although, as far as I am concerned, my job is done


As a kind of disclaimer, I am not a CSS expert. If you know of a better way of doing this, please let me know.

I named this post so because I started researching something that a chat user asked me: how do you add UpdatePanels programatically to a page. You see, the actual problem was that he couldn't add controls to the UpdatePanel after adding it to the page and that was because the UpdatePanel is a templated control, in other words it contains one or more objects that inherit from ITemplate and all the control's children are part of these templates.

So, the required application is like this: A page that has a button that does nothing but a regular postback and another button that adds an UpdatePanel. Each update panel must contain a textbox and a button. When the button is pressed, the textbox must fill with the current time only in that particular UpdatePanel. If the regular postback button is pressed, the UpdatePanels must remain on the page.

What are the possible issues?
First of all, the UpdatePanels must survive postbacks. That means that you have to actually create them every time the page loads, therefore inside Page_Load. Note: we could add them in Page_Init and in fact that's where they are added when getting the controls from the aspx file of a page, but during Init, the ViewState is not accessable!
Then, there is the adding of the UpdatePanels. It is done in a Click event from a button, one that is done AFTER the Page_Load, therefore adding of an UpdatePanel must also be done there. Note: we could put the CreatePanels method in Page_LoadComplete, but then the controls in the update panel will not respond to any events, since the Load phase is already complete.
There is the matter of how we add the TextBox and the Button in each UpdatePanel. The most elegant solution is to use a Web User Control. This way one can visually control the content and layout of each UpdatePanel and also (most important for our application) add code to it!
Now there is the matter of the ITemplate object that each UpdatePanel must have as a ContentTemplate. This is done via the Page.LoadTemplate method! We you give it the virtual path to the ascx file and it returns an ITemplate. It's that easy!

Update:if you by any chance want to add controls programatically to the UpdatePanel, use the ContentTemplateContainer property of the UpdatePanel like this:
updatePanel.ContentTemplateContainer.Controls.Add(new TextBox());


Enough chit-chat. Here is the complete code for the application, the DynamicUpdatePanels page and the ucUpdatePanelTemplate web user control:
DynamicUpdatePanels.aspx.cs
using System;
using System.Web.UI;

public partial class DynamicUpdatePanels : Page
{
private int? _nrPanels;

public int NrPanels
{
get
{
if (_nrPanels == null)
{
if (ViewState["NrPanels"] == null)
NrPanels = 0;
else
NrPanels = (int) ViewState["NrPanels"];
}
return _nrPanels.Value;
}
set
{
_nrPanels = value;
ViewState["NrPanels"] = value;
}
}

protected void Page_Load(object sender, EventArgs e)
{
CreatePanels();
}

private void CreatePanels()
{
for (int i = 0; i < NrPanels; i++)
{
AddPanel();
}
}

private void AddPanel()
{
UpdatePanel up = new UpdatePanel();
up.UpdateMode = UpdatePanelUpdateMode.Conditional;
up.ContentTemplate = Page.LoadTemplate("~/ucUpdatePanelTemplate.ascx");
pnlTest.Controls.Add(up);
}

protected void btnAdd_Click(object sender, EventArgs e)
{
NrPanels++;
AddPanel();
}
}


DynamicUpdatePanels.aspx
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="DynamicUpdatePanels.aspx.cs"
Inherits="DynamicUpdatePanels" %>


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>
Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server" />
<asp:Panel ID="pnlTest" runat="server">
</asp:Panel>
<asp:Button ID="btnAdd" runat="server" Text="Add Panel" OnClick="btnAdd_Click" />
<asp:Button ID="btnPostBack" runat="server" Text="Postback" />
</form>
</body>
</html>


ucUpdatePanelTemplate.ascx.cs
using System;
using System.Web.UI;

public partial class ucUpdatePanelTemplate : UserControl
{
protected void btnAjax_Click(object sender, EventArgs e)
{
tbSomething.Text = DateTime.Now.ToString();
}
}


ucUpdatePanelTemplate.ascx
<%@ Control Language="C#" AutoEventWireup="true" CodeFile="ucUpdatePanelTemplate.ascx.cs"
Inherits="ucUpdatePanelTemplate" %>

<asp:TextBox ID="tbSomething" runat="server"></asp:TextBox>
<asp:Button ID="btnAjax" runat="server" OnClick="btnAjax_Click" />


That's it, folks!

Sometimes you need an information like the time taken for a web page to actually reach the client. It is different from the time it takes to create the rendered content as it includes some web server overhead and the actual network transfer. IIS doesn't know anything about your code, so you can't tell it to log everything you need. How do you synchronize the information in the IIS log with the one in your own logging system?

Use the Response.AppendToLog method that will add a custom string to the end of the IIS logged cs-uri-query field. That doesn't help you much, but since you can add any string you want, you can add a key that would help synchronize the two informations.

Quick example:
string key=Guid.NewGuid().ToString();
Response.AppendToLog(" key=["+key+"]");
MyLogger.Write(myInformation,key);


Now you will only have to Regex the cs-uri-query field to find the key, then search the corresponding line in your own log. Simple! Sort of...

We were working on a project for a company that suddenly started complaining of slow ASP.Net pages. I optimised what I could, but it seemed to me that it ran pretty fast. Then I find out that some of the customers use a slow Internet connection. The only way to test this was to simulate a slow connection.

But how can one do that on IIS 5.1, the Windows XP web server? After a while of searching I realised that it was the wrong question. I don't need this for other projects and if I did I certainly wouldn't want to slow the entire web server to check it out. Because yes, changing the metadata of the server can, supposedly, change the maximum speed the pages are delivered. But it was simply too much hassle and it wasn't a reusable solution.

My way was to create a Filter for the Response of all pages. Response.Filter is supposed to be a Stream that receives as parameter the previous Response.Filter (which at the very start is Response.OutputStream) and does something to the output of the page. So I've created a BandwidthThrottleFilter object and added it in the MasterPage Page_Load:
Response.Filter=new BandwidthThrottleFilter(Response.Fitler,10000);
. It worked.

Now for the code. Follow these steps:
  1. Create a BandwidthThrottleFilter class that inherits from the abstract class Stream
  2. Add a constructor that receives as parameters a Stream and an integer
  3. Add fields that will get instantiated from these two parameters
  4. Implement all abstract methods of the Stream object and use the same methods from the Stream field
  5. Change the Write method to also call a Delay method that receives as parameter the count parameter of the Write method


That's it. You need only create the Delay method which will do a Thread.Sleep for the duration of time it normally should take to transfer that amount of bytes. Of course, that assumes that the normal speed of transfer is negligeable.

Click to see the whole class code

When one wants to indicate clearly that a control is to perform an asynchronous or a synchronous postback, one should use the Triggers collection of the UpdatePanel. Of course, I am assuming you have an ASP.Net Ajax application and you are stuck on how to indicate the same thing on controls that are insides templated controls like DataGrid, DataList, GridView, etc.

The solution is to get a reference to the page ScriptManager then use the method RegisterPostBackControl on your postback control. You get a reference to the page ScriptManager with the static ScriptManager.GetCurrent(Page); method. You get the control you need inside the templated control Item/RowCreated event with a e.Item/Row.FindControl("postbackControlID");

So, the end result is:

ScriptManager sm=ScriptManager.GetCurrent(Page);
Control ctl=e.Item/Row.FindControl("MyControl");
sm.RegisterPostBackControl(ctl);


Of course, if you want it the other way around (set the controls as Ajax async postback triggers) use the RegisterAsyncPostBackControl method instead.

Special thanks to Sim Singh from India for asking me to research this.

I am going to quickly describe what happened in the briefing, then link to the site where all the presentation materials can be found (if I ever find it :))

The whole thing was supposed to happen at the Grand RIN hotel, but apparently the people there changed their minds suddenly leaving the briefing without a set location. In the end the brief took place at the Marriott Hotel and the MSDN people were nice enough to phone me and let me know of the change.

The conference lasted for 9 hours, with coffee and lunch breaks, and also half an hour for signing in and another 30 minutes for introduction bullshit. You know the drill if you ever went to one of such events: you sit in a chair waiting for the event to start while you are SPAMMED with video presentations of Microsoft products, then some guy comes in saying hello, presenting the people that will do the talking, then each of the people that do the talking present themselves, maybe even thank the presenter at the beginning... like a circular reference! Luckily I brought my trusted ear plugs and PDA, loaded with sci-fi and tech files.

The actual talk began at 10:00, with Petru Jucovschi presenting as well as holding the first talk, about Linq and C# 3.0. He has recently taken over from Zoltan Herczeg and he has not yet gained the necessary confidence to keep crouds interested. Luckily, the information and code were reasonably well structured and, even if I've heard them before, held me watching the whole thing.

Linq highlights:
  • is new in .NET 3.0+ and it takes advantage of a lot of the other newly introduced features like anonymous types and methods, lambda expressions, expression trees, extension methods, object initializers and many others.
  • it works over any object defined as IQueryable<T> or IEnumerable (although this last thing is a bit of a compromise).
  • simplifies our way of working with queries, bring them closer to the .NET programming languages and from the just-in-time errors into the domain of compiler errors.
  • "out of the box" it comes with support for T-Sql, Xml, Objects and Datasets, but providers can be built (easily) for anything imaginable.
  • the linq queries are actually execution trees that are only run when GetEnumerator is called. This is called "deffered execution" and it means more queries can be linked and optimised before the data is actually required.
  • in case you want the data for caching purposes, there are ToList and ToArray methods available


Then there were two back-to-back sessions from my favourite speaker, Ciprian Jichici, about Linq over SQL and Linq over Entities. He was slightly tired and in a hurry to catch the plain for his native lands of Timisoara, VB, but he held it through, even if he had to talk for 2.5 hours straight. He went through the manual motions of creating mappings between Linq to SQL objects and actualy database data; it wouldn't compile, but the principles were throughly explained and I have all the respect for the fact that he didn't just drag and drop everything and not explain what happened in the background.

Linq to SQL highlights:
  • Linq to SQL does not replace SQL and SQL programming
  • Linq to SQL supports only T-SQL 2005 and 2008 for now, but Linq providers from the other DB manufacturers are sure to come.
  • Linq queries are being translated, wherever possible, to the SQL server and executed there.
  • queries support filtering, grouping, ordering, and C# functions. One of the query was done with StartsWith. I don't know if that translated into SQL2005 CLR code or into a LIKE and I don't know exactly what happends with custom methods
  • using simple decoration, mapping between SQL tables and C# objects can be done very easily
  • Visual Studio has GUI tools to accomplish the mapping for you
  • Linq to SQL can make good use of automatic properties and object initialisers and collection initialisers
  • an interesting feature is the ability to tell Linq which of the "child" objects to load with a parent object. You can read a Person object and load all its phone numbers and email addresses, but not the purchases made in that name


Linq to Entities highlights:
  • it does not ship with the .NET framework, but separately, probably a release version will be unveiled in the second half of this year
  • it uses three XML files to map source to destination: conceptual, mapping and database. The conceptual file will hold a schema of local object, the database file will hold a schema of source objects and the mapping will describe their relationship.
  • One of my questions was if I can use Linq to Entities to make a data adapter from an already existing data layer to another, using it to redesign data layer architecture. The answer was yes. I find this very interesting indeed.
  • of course, GUI tools will help you do that with drag and drop operations and so on and so on
  • the three level mapping allows you to create objects from more linked tables, making the internal workings of the database engine and even some of its structure irrelevant
  • I do not know if you can create an object from two different sources, like SQL and an XML file
  • for the moment Linq to SQL and Linq to Entities are built by different teams and they may have different approaches to similar problems


Then it was lunch time. For a classy (read expensive like crap) hotel, the service was really badly organised. The food was there, but you had to stay in long queues qith a plate in your hand to get some food, then quickly hunt for empty tables, the type you stand in front of to eat. The food was good though, although not exceptional.

Aurelian Popa was the third speaker, talking about Silverlight. Now, it may be something personal, but he brought in my mind the image of Tom Cruise, arrogant, hyperactive, a bit petty. I was half expecting him to say "show me the money!" all the time. He insisted on telling us about the great mathematician Comway who, by a silly mistake, created Conway's Life Game. If he could only spell his name right, tsk, tsk, tsk.

Anyway, technically this presentation was the most interesting to me, since it showed concepts I was not familiar with. Apparently Silverlight 1.0 is Javascript based, but Silverlight 2.0, which will be released by the half of this year, I guess, uses .NET! You can finally program the web with C#. The speed and code protection advantages are great. Silverlight 2.0 maintains the ability to manipulate Html DOM objects and let Javascript manipulate its elements.

Silverlight 2.0 highlights:
  • Silverlight 2.0 comes with its own .NET compact version, independent on .NET versions on the system or even on operating system
  • it is designed with compatibility in mind, cross-browser and cross-platform. One will be able to use it in Safari on Linux
  • the programming can be both declarative (using XAML) and object oriented (programatic access with C# or VB)
  • I asked if it was possible to manipulate the html DOM of the page and, being written in .NET, work significantly faster than the same operations in pure Javascript. The answer was yes, but since Silverlight is designed to be cross-browser, I doubt it is the whole answer. I wouldn't put it past Microsoft to make some performance optimizations for IE, though.
  • Silverlight 2.0 has extra abilities: CLR, DLR (for Ruby and other dynamic languages), suport for RSS, SOAP, WCF, WPF, Generics, Ajax, all the buzzwords are there, including DRM (ugh!)


The fourth presentation was just a bore, not worth mentioning. What I thought would enlighten me with new and exciting WCF features was something long, featureless (the technical details as well as the presenter) and lingering on the description would only make me look vengeful and cruel. One must maintain apparences, after all.

WCF highlights: google for them. WCF replaces Web Services, Remoting, Microsoft Message Queue, DCOM and can communicate with any one of them.

If you don't want to read the whole thing and just go to the solution, click here.

I reached a stage in an ASP.Net project where a I needed to make some pages work faster. I used dotTrace to profile the speed of each form and I optimized the C# and SQL code as much as I could. Some pages still were very slow.

Now, I had the idea to look for Javascript profilers. Good idea, bad offer. You either end up with a makeshift implementation that hurts more than it helps, or with something commercial that you don't even like. FireFox has a few free options like FireBug or Venkman, but I didn't even like them and then the pages I was talking about were performing badly in Internet Explorer, not FireFox.

That got me thinking of the time when Firefox managed to quickly select all the items in a <select> element, while on Internet Explorer it scrolled to each item when selecting it, slowing the process tremendously. I then solved that issue by setting the select style.display to none, selecting all the items, then restoring the display. It worked instantly.

Can you guess where I am going with this?

Most ASP.Net applications have a MasterPage now. Even most other types of sites employ a template for all the pages in a web application, with the changing page content set in a div or some other container. My solution is simple and easy to apply to the entire project:

Step 1. Set the style.display for the page content container to "none".
Step 2. Add a function to the window.onload event to restore the style.display.

Now what will happen is that the content will be displayed in the hidden div, all javascript functions that create, move, change elements in the content will work really fast, as Internet Explorer will not refresh the visual content in the middle of the execution, then show the hidden div.

A more elegant solution would have been to disable the visual refresh of the element while the changes are taking place, then enable it again, but I don't think one can do that in Javascript.

This fix can be applied to pages in FireFox as well, although I don't know if it speeds anything significantly. The overall effect will be like the one in Internet Explorer table display. You will see the page appear suddenly, rather than see each row appear while the table is loaded. This might be nice or not nice, depending on personal taste.

Another cool idea would be to hide the div and replace it with a "Page loading" div or image. That would look even cooler.

Here is the code for the restoration of display. In my own project I just set the div to style="display:none", although it might be more elegant to also hide it using Javascript for the off chance that someone might view the site in lynx or has Javascript disabled.
function addEvent(elm, evType, fn, useCapture)
// addEvent and removeEvent
// cross-browser event handling for IE5+, NS6 and Mozilla
// By Scott Andrew
{
if (elm.addEventListener){
elm.addEventListener(evType, fn, useCapture);
return true;
} else if (elm.attachEvent){
var r = elm.attachEvent("on"+evType, fn);
return r;
} else {
alert("Handler could not be removed");
}
}

function initMasterPage() {
document.getElementById('contenuti').style.display='';
}

addEvent(window,'load',initMasterPage);

Update: this problem appeared for older versions of AjaxControlToolKit. Here is a link that says they fixed this issue since 21st of September 2007.

You are building this cool page using a TabContainer or some other AjaxControlToolKit control and everything looks smashing and you decide to add the UpdatePanels so that everything would run super-duper-fast. And suddenly the beautiful page looks like crap! Everything works, but your controls don't seem to load the cascading style sheet.
What is happening is that you make a control visible using update panels and so the CSS doesn't get loaded. I don't know exactly why, you would have to look into the AjaxControlToolKit source code and find out for yourself.

I found two fixes for this. The first is the nobrainer: add another TabContainer or AjaxControlToolKit control in the page, outside any updatepanels, make it visible, but set its style.display to 'none' or put it in a div or span with style="display:none". The second is the AjaxControlToolKit way. In the Page_Load event of the page or user control that contains the TabContainer or AjaxControlToolKit control add this line:
ScriptObjectBuilder.RegisterCssReferences(AjaxControlToolKit control);

This is part of the ExtenderControlBase class in AjaxControlToolKit, which is inherited by most if not all of their controls.

Now it should all work wonderfully.

Most programmers use the ViewState to preserve data across postbacks and the Session to preserve data for a user. There are cases when you want to preserve data across users. Maybe you are using an IHttpHandler and you want to send information through a key between your application and the handler. Or maybe you want to keep data that is resource consuming to acquire, but used by more users of the same application. Here is where Cache comes along.

There are two things you need to pay attention to when you are using the Cache:
  • While using the syntax Cache[key] is very simple and consistent with the ViewState, Session or other dictionaries you are used to, you need to be aware that in case of the server freeing memory, the cache items will be removed based on priority. Try to use Cache.Add or Cache.Insert with CacheItemPriority.NotRemovable when you are sure you don't want this to happen. The Absolute and Sliding expirations will still work.
  • I've read somewhere that HttpContext.Current.Cache does not work across users. It's like another Session object. Use HttpRuntime.Cache instead. I also looked in the ASP.Net source code and I found out that HttpContext.Cache returns HttpRuntime.Cache, so I don't see how these two properties could behave any differently. HttpRuntime is much easily usable, though, since it works in situations where HttpContext.Current is null