Using EQUATEC FREE .NET Profiler with ASP.NET Applications

This was originally an email I sent to .NET team in my company, then decided to share as a blog post.

The problem:

  • Let’s say you have a complex application, and this application (or part of it) runs very slowly. No bug s in results, no errors or exceptions, but it just so slow! Now you want to know which part of your code is the reason, which method(s) you need to go and modify., which methods take so long to execute or consume so much memory/CPU. How would you know that?
  • Let’s say you want to improve the performance of your application in general (say add caching or such), so, you want to identify which parts of your code deserve your attention and will really make difference (so that you don’t waste your time on optimizing something that will not have big effect in performance), for  example, you might want to identify which methods are called more than others from different parts of your code. How would you do that?

How to solve it, or, what is a profiler (v. short):

It is an application that you can run along with your own program. It’ll track all method calls and how any method call other method and most importantly how long each method call will take, and how it consumes resources.


There are many .NET profilers out there.


So, what about EQATEC:

Quoting from homepage:

Spot slow code

Are you a .NET developer? Would you like your application to run faster? Then use our free profiler to spot you app’s slow code.

Point and go

No source code changes are needed. Just point the profiler to your app, run the modified code, and get a visual report.

Speedup any .NET app

As the only code profiler in the world, our profiler can even handle Compact Framework applications.




clip_image001 C#

clip_image001[1] VB.NET

clip_image001[2] Managed C++

clip_image001[3] F#

clip_image002 C or C++

clip_image002[1] Java

clip_image001[4] .NET 3.5

clip_image001[5] .NET 3.0

clip_image001[6] .NET 2.0

clip_image001[7] .NET CF 3.5

clip_image001[8] .NET CF 2.0

clip_image002[2] .NET 1.1

clip_image001[9] WinXP, Vista

clip_image001[10] Windows Mobile

clip_image001[11] Windows CE

clip_image001[12] XP embedded

clip_image001[13] PocketPC, PDA

clip_image002[3] Linux

To use it with ASP.NET application, all you need to is:

  • to put the path of the “bin” folder of your website as “App Path” (no need for source code or debug files), then it shows a list of all assemblies in it so you choose the DLL(s) you want to profile, and click “Build” at the right corner of the screen:
  • Click “Open output folder” on the bottom left corner, copy the DLLs from there to your website “bin” folder
    • Alternatively you can click “App Options” and set the output folder to “$(AppDir)” so that the generated files replace the old one
    • You need to repeat these previous steps if you build the website again using Visual Studio
  • run the website and start using it for a while
  • go to EQUATEC “Run” tab and click “Take Snapshot
  • go to the “View” tab and start reading the results

It might be important also to spot the limitations:

Known limitations

This is a list of known limitations and problems in version 2.0.

  • Blocking methods, such as Read(), will be counted as the total time, including the time the thread spends being descheduled and waiting for the call to complete. For now, you will have to recognize and judge situations like this manually.
  • No debug information is available for the profiled assemblies. It means that you cannot debug the profiled versions – but you would probably not like to do that, anyway.
  • No Visual Studio integration yet. We are looking into providing an add-in that will make it even easier to enable profiling your solution’s assembly files.
  • No full method signature is displayed yet. So if you have several overloaded methods by the same name, or use generic methods, you cannot easily distinguish them as their signature (the method’s parameter list) is not displayed anywhere.
  • Only defined methods are currently profiled, not referenced ones. So all the methods that your application itself defines will be profiled, but not System.* etc.

I hope this is useful for some of you as it was a real saver at times to me. Thank you very much!

Converting Visual Studio Website to Web Application Project

Click here to go directly to the instructions…

Background (Click above to skip if you know Web Application Projects)

In VS 2002/2003, the web project model for a website was similar to “class library” projects, where you have a .CSPROJ or .VBPROJ file that keeps track of files “included” in the project, and compiles all the pages and controls code behind to a single assembly under “bin”. Each page/control has an automatically generated .DESIGNER.CS or .DESIGNER.VB file, which contains objects mapping to the server controls in the page/control markup (the generation of those files was not always in synch with markup, and that was problematic).

With VS 2005, there was a new “website” model for web projects that compiles each page/control individually as a separate assembly (or each folder, depending on optimization features), and applies this to all files in a given directory and its sub folders. This was a total mess in most “real world” projects, as VS takes so long to build the entire website, and even at deployment, you get sometimes many problems when you have pages that “reference” other pages/controls when IIS it trying to dynamically load the right assemblies to reference, and many other problems.

So, Microsoft came with a new add in to VS 2005 called “Web Application Projects“. This is typically the same old VS 2002/2003 project model with no problems in generating DESIGNER files and with integration with both IIS and ASP.NET development server that comes embedded in VS 2005/2008. It was later merged with VS 2005 SP1, and shipped as part of VS 2008 (without removing the “website” model). Note that most stuff that has to do with Microsoft like ASP.NET AJAX Toolkit Sample website and so are actually “web applications” not “websites”.

The problem

Typically, when you are converting any project from VS 2003 to VS 2005 SP1, it converts as “web application” not “website”. You can also convert a “website” to a “web application”. There’s an option “Convert to web application” to look for.

In my company, all our web projects are “web applications”, well, except that other web project I was code reviewing and helping with its deployment! After spending number of days with the brilliant team and not finding as many items to code review and getting sick of some problems at sometime in deployment, I cried to them to convert it to to “web application” (maybe I was looking for some job to be doing :D). Very confidently, I said, ” remember the option exists and I did conversion before in VS 2005. All it takes is a right click on the ‘website’ root node in solution explorer in VS 2008 and ‘Convert to web application’. It almost never causes any problems, and we have our source control anyway”.

They believed they had time to do it, so, they went to look for that menu item  “Convert to web application” and guess what ? They didn’t find it! They tried resetting VS 2008 settings and everything, and still, nothing there!!! Yeah, it was embarrassing :D :D :D

Workaround, or, how to convert a “website” to “web application” in VS 2008

Well, it turns out that the option “Convert to web application” does NOT exist for “websites”. The option “Convert to web application” does exist only for “web applications” !!!!

So, here’s the deal, to do the conversion, you need to:

  • Add a new “Web Application” to your VS 2008 solution (File->Add->New Project->C#->Web->ASP.NET Web Application).
  • Afterwards, you copy all the files in the old “website” to your newly created “web application”, and override any files created in it by default
  • The next step is the most ugly, you need to “manually” add the references in your “website” to the new “web application”. I thought the VS 2008 PowerCommands toy would do this for me as it does copy references from other project types, but it didn’t. You have to do it by yourself, manually, and you have to be cautious in this step if you have multiple versions of the same assembly (like AJAXToolkit in my case) or assemblies that have both GAC and local versions or so.
  • Keep repeating the last step and trying to build the “web application”. You’ll keep getting errors like ” ‘….’ is unknown namespace. Are you missing an assembly reference? “. Make sure you have none of those except the ones where ‘….’ is replaced by the IDs of the server controls you use. In other words, keep adding references and building the project until only the errors that exist because of missing .DESIGNER.CS or .DESIGNER.VB files.
  • Afterwards, go to the “web application” root project node in VS 2008 solution explorer, and right click it, then you WILL find the option “Convert to web application”. What this option does is actually making small changes to the “@Page” and “@Control” directives of pages and controls, and creating the required .DESIGNER.CS or .DESIGNER.VB files.
  • Try building the “web application” again. If you get errors, see what references may be missing and/or go click the “Convert to web application” again. Sometimes, if there’s any error other than those caused of missing DESIGNER files, not all the pages/controls will have those DESIGNER files created for them. Fixing the non DESIGNER problem and clicking “Convert to web application” again should do the job for this.
  • Once you are done successful VS build, you should be ready to go. Start testing your web application. Optionally, you can right click the “web application” root project node in VS 2008 Solution Explorer and click “Properties” then go to the tab “Web” to set the “web application” to a virtual folder in IIS (you can create new virtual directory from there in VS). If you want to use the IIS virtual directory that the old “website” used, you need to remove that from IIS first.
  • Update: When testing your pages, pay MOST ATTENTION to classes in “App_Code” folder, especially those with NO NAMESPACE. Those can be a big trap. We had a problem with two extension method overloads in the same static class that had no namespace,one extends DateTime? (Nullable<DateTime>) and calls another overload that extends DateTime itself. Calling the other overload as extension method passed VS 2008 compilation and gave us a compilation error ONLY IN RUNTIME (With IIS). Changing the call to the other overload from calling it as extension method to calling it as normal static method (only changing the call in the same class, calls from other classes remained extension method calls) did solve this one, but clearly, it’s not as safe as it used to be in VS 2005. Especially with classes with no namespaces.
  • Update2: During the conversion, VS 2008 renames your “App_Code” to “Old_App_Code”. This new name sounds ugly, but DO NOT RENAME IT BACK. In the “web application” model, all code will be in one assembly. In runtime, the web server does not know what web project type you are using. It does take all code in “App_Code” folder and create a new assembly for it. This way, if you have code in folder named “App_Code”, you’ll end up with RUNTIME compilation errors that the same types exist in two assemblies, the one created by VS, and the one created by IIS / ASP.NET Development Server. To avoid that. leave the “Old_App_Code” with the same name, or rename it to ANYTHING EXCEPT: “App_Code”. Do not place any code in such “App_Code” folder and prefereably do NOT have a folder with such name in your “web application” at all.
    I know this since before but forgot it now as I have not used “website” model for long :(.

I hope this helps anyone to avoid my embarrassment, and still get rid of the weird errors of “website” model :).

Prevent ASP.NET Validators from Massively Increasing Page Size

This is problematic with ASP.NET AJAX. The main Script Components are NOT sent to the client when in :Legacy” mode. This is “By design” in ASP.NET AJAX, although it is a clear limitation!!

I’m investigating the problem for other solutions and will be sending an update soon.

Thank you, Iman Halawany, for making me note this. I’ve been working on WCF services and ASP.NET MVC stuff lately than normal webforms, so, didn’t realize this obvious showstopper.

To all my readers, I owe you a BIG apology.

The Problem

ASP.NET validators and ValidationSummary controls are rendered as SPAN tags that are shown and hidden based on validation state. The properties of the validators are written normally via JavaScript calls similar to these:

<script type=“text/javascript”>


var Page_ValidationSummaries =  new Array(document.getElementById(“vdsSiteLogin”));

var Page_Validators =  new Array(document.getElementById(“rfvEmail”), document.getElementById(“revEmail”), document.getElementById(“rfvName”));




<script type=“text/javascript”>


var rfvEmail = document.all ? document.all[“rfvEmail”] : document.getElementById(“rfvEmail”);

rfvEmail.controltovalidate = “txtEmail”;

rfvEmail.errormessage = “Email Missing”;

rfvEmail.validationGroup = “SiteLogin”;

rfvEmail.evaluationfunction = “RequiredFieldValidatorEvaluateIsValid”;

rfvEmail.initialvalue = “”;

var revEmail = document.all ? document.all[“revEmail”] : document.getElementById(“revEmail”);

revEmail.controltovalidate = “txtEmail”;

revEmail.errormessage = “Email is invalid”;

revEmail.validationGroup = “SiteLogin”;

revEmail.evaluationfunction = “RegularExpressionValidatorEvaluateIsValid”;

revEmail.validationexpression = “\w+([-+.’]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*”;

var rfvName = document.all ? document.all[“rfvName”] : document.getElementById(“rfvName”);

rfvName.controltovalidate = “txtEmail”;

rfvName.errormessage = “Password is missing”;

rfvName.validationGroup = “SiteLogin”;

rfvName.evaluationfunction = “RequiredFieldValidatorEvaluateIsValid”;

rfvName.initialvalue = “”;

var vdsSiteLogin = document.all ? document.all[“vdsSiteLogin”] : document.getElementById(“vdsSiteLogin”);

vdsSiteLogin.validationGroup = “SiteLogin”;





Note that this is for ONLY 3 validators, 1 validation summary and in directly a page that doesn’t use a master page, not in nested user control or such!

How about a page with over 30+ validators (yeah, those forms!!), and each with ClientID like “ctl00_cphBody_ct00_fvUserLogin_rfvEmail_” and such?

If you have ever wondered why those pages take so much time loading, this code block (multiplied per number of validators you have and their properties set) is one reason.

You cannot even take the JavaScipt in separate file that can be cached, because this is dynamically created as per the visible validation controls.

The Solution (See Above Note)

The clear alternative to setting those properties via JavaScript long block with huge ClientIDs is to put the properties in the SPAN tags of the validation controls themselves.

The reason that AS.NET does not do this by default is that this is not XHTML 1.0 Transitional compliant, because the validator properties are not XHTML attributes of the SPAN tag.

ASP.NET tries to render XHTML 1.0 Transitional markup by default. But you can change that in your web.config file by adding one line under <system.web>:


        <xhtmlConformance mode=Legacy/>


This will make the properties render in the SPAN tags themselves, saving so much code in real life scenarios.

Personally I’d recommend: DO THIS IN EVERY WEBSITE YOU HAVE (See above note)


Thanks to Paulo Morgado for mentioning this.

ASP.NET Validators Client Side APIs: MSDN List Page

If you have ever thought that the famous if(Page_ClientValidate("validationGroup")) {/*JS Code*/}  and myValidator.ValidationGroup = "validationGroup"; are sure not enough client side capabilities in ASP.NET validators, you are right.

The list of client side API for ASP.NET Validators can be found on this MSDN page "ASP.NET Validation in Depth":

Look for subtitle: "Client-Side APIs".


Thanks Simone Chiaretta for mentioning the topic, Mohamed Tayseer for sharing the topic on facebook, and Richard Cook for his comment on the post making me search for the complete list.

Unit Test Friendly File Upload In ASP.NET

The Problem

In an N-tier application, you keep your logic in a business logic tier, typically a different VS project that can be used from a website, a windows service, or desktop application, and that should be valid to writ unit tests against on its own.

But how about if your requirements say that you need to to upload some file for the business logic to work? Think of a scanned image (signed contract maybe?) or just a comma separated value file containing some emails.  Typically the business logic tier will be the place to to handle this, but how can you send the uploaded file to it? You can get the file as “HttpPostedFile” from the “Request.Files” collection or the file upload control itself, but, to receive it in the business logic, project, the easiest way is to add reference to “System.Web” dll and accept the type “HttpPostedFile” as method argument or so, and when in need to save the file physically, you call the “SaveAs” method of “HttpPostedFile” … So simple right ?

But how about unit testing? “HttpPostedFile” has no public constructor and is sealed class (you cannot inherit from). How will you write a unit test for a method that accepts “HttpPostedFile” as argument to work? You’d go finding a way to mock that or just forget about testing that particular method!!

A Simple Solution

Well, it’s more simple than you think. An “HttpPostedFile” has a property called “InputStream”, which is of type “System.IO.Stream”. Hey, that has nothing to do with “system.Web” :). You can create your own FileStream or whatever other stream in the unit test, and then only worry about other areas you want to test related to the method in your business logic.

Because I know dealing with streams is quite ugly (at least it is to me!), I wrote an example that will walk you though a sample usage of that property. I have the complete example VS solution as attached file at the end of the example code below.

The Business Logic

In a real world example, the business class will have various parameters including the file, but in this example, I have made my business class (I call it “FileLogic”) just worry about the file. It has a method that treats the stream coming to it as containing just text, reads that text and returns it. Note the type of the only method parameter

<code>/// <summary>
/// This is the simplest method ever. Read the stream whether from web upload or whatever
/// As the name implies, it treats the stream contents as text.
/// </summary>
public string ReadTextFile(Stream inputStream)
    using (var reaader = new System.IO.StreamReader(inputStream))
        return reaader.ReadToEnd();

Another example of a method in the business logic project is one that actually saves the file. Instead of just calling “SaveAs(filepath)”, you need to copy the stream yourself. Usually there’s more than one way to do so, the problem in most of the ways is determining the size of the stream. An “HttpPostedFile” knows the size of the file, but as I’m not getting the “HttpPostedFile” (and it wouldn’t sound great if I requested the file size as a method parameter!), I dealt as if I do not know the actual file size. See the code for this method:

<code>/// <summary>
/// Writes the stream context that comes to it whether from web or whatever!
///     and saves it to the path set by property called "SavingPath"
/// I meant to not make the save path a method property because 
///     in real situation that value would come most likely from 
///         configuration, DB or some other code logic
/// </summary>
public void WriteBinaryFile(Stream inputStream)
    using (var reader = new BinaryReader(inputStream))
        int bufferSize = 1024;
        byte[] buffer = new byte[bufferSize];
        int count = 0;
        int offset = 0;

        using (var writingStream = 
            new System.IO.FileStream(this.SavingPath, System.IO.FileMode.OpenOrCreate))
            while ((count = reader.Read(buffer, offset, buffer.Length)) > 0)
                writingStream.Write(buffer, offset, count);

Example: A Webforms ASP.NET Project

Before we dig into the unit test sample, let’s see how our page code will look when dealing with this business logic class.

Consider a page with controls like these:

<code> <%-- 
     Note: I used the FileUpload control of .NET 2.0 and above, 
         but I could also use something like:
     <input type="file" runat="server" id="inFileTest" />
 <asp:FileUpload runat="server" ID="upldTestFile" />

 <%-- Used a text file read operation as a simple exsample --%>
 <asp:Button runat="server" ID="btnReadFile" Text="Read text file in the page" 
     onclick="btnReadFile_Click" />

 <%-- Note that even text files can be treated as binary files :) --%>
 <asp:Button runat="server" ID="btnWriteFile" Text="Write Copy of the file (any type)" 
     onclick="btnWriteFile_Click" />

 <br />

 <%-- I'll show the read happened by referencing to it --%>
 <asp:Literal runat="server" ID="litReadFileResult" />

 <%-- I'll show the file was written by linking to it. 
         In real world, you may want to encapsulate this in an HTTPHandler 
             not expose the file itself --%>
 <asp:HyperLink runat="server" ID="lnkWriteFileResult" 
     Text="Click here to get the saved file" />

The code behind for such page with our custom logic class (in a sample manner still), would look like this:

<code>/// <summary>
/// Created for the "ReadTextFile" method
/// </summary>
protected void btnReadFile_Click(object sender, EventArgs e)
    if (!upldTestFile.HasFile) { /* Call whatever error msg method and, */ return; }

    var fileLogic = new FileLogic();
    litReadFileResult.Text =
        "The text file contents are: "
            + fileLogic.ReadTextFile(upldTestFile.PostedFile.InputStream);
    litReadFileResult.Visible = true;

/// <summary>
/// Created for the "WriteBinaryFile" method
/// </summary>
protected void btnWriteFile_Click(object sender, EventArgs e)
    if (!upldTestFile.HasFile) { /* Call whatever error msg method and, */ return; }

    //Save the file to "sample.text" under the website root (referenced as "~/"
    string relativeSavePath = "~/" + upldTestFile.FileName;

    var fileLogic = new FileLogic();

    // Converting path to phyical then setting it in the business logic class
    //  The physical path typically does not yet exist, as we'll create new file to it
    fileLogic.SavingPath = Server.MapPath(relativeSavePath);


    lnkWriteFileResult.NavigateUrl = relativeSavePath;
    lnkWriteFileResult.Visible = true;

I’d say that this part is not much different than it’d be if we were passing the “HttpPostedFile” object complete.

The Unit Test

So, that’s what we have been hassling, complicating code, and dealing directly with streams for its sake!

As our application will not necessarily be a file sharing application, we’ll be in need for the file as part of a bigger operation. A unit test will not be only concerned with the file upload task, but also the rest parts of the business operation our method intends to do. However, in this sample, I’ve decided to make it just test the file uploading functionality, and included really simple ways in the unit test.

Instead of the file upload, I used a physical file that I get its path from a method called “GetTestFilename” (I could have used configuration file, static property or else for the file stream, or used any other kind of stream still).

See how the test methods look in this example (using NUnit):

<code>/// <summary>
/// Checks method "ReadTextFile" to see whether it gets the same text as sent file
/// </summary>
public void TestReadTextFile()
    var fileLogic = new FileLogic();
    var sampleFileInfo = new System.IO.FileInfo(GetTestFilename());
    string correctResult = sampleFileInfo.OpenText().ReadToEnd();
    string testResult = fileLogic.ReadTextFile(sampleFileInfo.OpenRead());

    Assert.AreEqual(correctResult, testResult);

/// <summary>
/// Checks whether method "WriteBinaryFile" creates the file
/// </summary>
public void TestWriteBinaryFile_FileExists()
    var fileLogic = new FileLogic();

    string newFilename = System.IO.Path.GetTempFileName();
    fileLogic.SavingPath = newFilename;

    var sampleFileInfo = new System.IO.FileInfo(GetTestFilename());


//There should be one more method for checking the file contents are the same
// Skipped for sample!

ASP.NET 2.0 Themes: Learn how to use them today!

This is ported from my old weblog. Originally published June 22, 2006

First, I assume here that you know themes and read about them, but are a bit afraid or unfamiliar with using them. If you don’t know what are Themes and skins in ASP.NET 2.0, check their section on MSDN as well as this great article (another one).

Do you know that…

  • Do you know that you can provide intellisense to skin files in VS2005? Simply go to Tools menu, click Options, and from the tree in the left, expand the node "Text Editor" to  click it’s sub node "File Extension". In the "Extension" text box, write "skin", and select "User Control Editor" from the "Editor" drop down, click add, and then OK.
  • Do you know that ANY stylesheet existing in the folder of the current "Theme" or "StylesheetTheme" is inked on rendering? Not just the stylesheet with the same name of the Theme, and not only when you’re using the theme as "StylesheetTheme" as some believe.
  • Do you know what differences exist between setting a theme using the Page Theme" property and the Page "StylesheetTheme" property?
    • If you have the same property on a control in the page and the same type of control in the skin file with different values, the value used will be the value in the page if you’te setting the theme via the "Theme" Page property, and will be the one in the skin file if you’re using "StylesheetTheme"
      The bottom line is that a "Theme" is applied AFTER page controls properties are set, while a "StylesheetTheme" is applied before setting control properties in the page.
    • If you set the your theme by using the "Pages" "Theme" property in web.config, you’ll NOT see the effect of the theme in design time in VS 2005. Setting "StylesheetTheme" makes the effect appears in design time.
  • Do you know that to change the theme of the page programmatically, you have to set it before the "Init" event of the page? (i.e in the "PreInit" event).

Making real use of themes

Have you been in the famous template graphics problem?

  • You have a template (lets say a Masterpage) used in all site pages.
  • The designer gives you the website design with some images in it of course, and one or more stylesheet file(s), which you need to reference in your template.
  • Of course, not all the site pages are in the same folder.
  • On your development box; either you’re using IIS or ASP.NET development server, the site i likely to be a virtual folder, while on the production server, the site is likely to be on the root of some domain.
  • You don’t know how to reference the images/stylesheet(s) in the template.
    1. You can’t make them relative to the page, as simply not all the pages are in the same folder.
    2. You can’t use root relative paths, as the root of the site on your machine is simpley not the root of the site on the live server.
    3. You want to reduce the number of server side images used in your side, for the performance, so, you aren’t just into mking a server side control just to make ASP.NET take care of the paths.
    4. You (and your designer) hate the ugly lines like
      <img src='<%= Page.ResolveUrl("~/images/myImage.gif")%>’ alt="Just a sample" />
      hint: "~" is used to refer to the root of the ASP.NET application, whether a virtual directory or a root.

A new solution other than described in point 3,4 comes with ASP.NET themes.

  1. You can just apply a default theme to all your site (ie. by writing it in web.config)
  2. If your designer is that geek he should be, he’ll be doing most of his work in a stylesheet, move that stylesheet to the folder of the theme you use.
  3. Any relative url in CSS is relative to the CSS file itself not the page using it.. As the stylesheet will be linked from a consistant place, just put the graphics folder(s)beside your CSS file(s), to be linked from there.
  4. Use a skin file with the same filename as the skin folder name, inside which, apply all server controls styles.

Of course, as you see in point 4, this doesn’t solve it completely. You’ll still need to use server side controls where CSS doesn’t just fit.

An interop hint!

No.. No unmanaged stuff here :-D. I mean by interop, your interop with your cool designer ;-).

Let’s imagine this scenario:

  1. There’re many listing pages (i.e, in site admin) with many grids that should have the same design applied.
  2. Your designer gives you only a sample HTML table with a CSS class for the table, the odd rows and the even (alternate) rows, with corresponding CSS file of course.
  3. You don’t want to go through the "___Style" properties of each grid to set the CSS classes. You want to set a single property (like a CSS class or something) on the entire grid. You tell your designer and he just doesn’t see why he should bother!

A solution to that repeated scenario (I’ve gone through and saw with MANY designers) in ASP.NET 2.0 using themes would be:

  1. Of course implementing a site wide theme, and adding the stylesheet file there.
  2. Adding a skin file with other filename than the theme folder name.
  3. Setting the "___Style" and "CssClass" properties of the controls you need (i.e: GridView).
  4. Setting the "SkinID" property on all the corresponding controls in the pages (i.e all the GridView controls that should use that design) to the filename of the new skin file (this will be our single value we need to set on the entire grid)

Of course, the same way can be used to solve similar problems.

Finally, I know that developers hate to see much talk without code or at least screenshots. I’m considering putting some code with this soon, but, I’m likely to forget or not have time, so, I hope this one doesn’t annoy you that much as it’s now

GridView DataBinding Events

This is a well commented example for a GridView with implementation of RowDataBound and DataBound events. I also demonstrate in it some of the important properties of GridView, like the slight differences when dealing with Grid Paging, Rows, Cells, and Columns. I prefered to heavily comment the code than to write separate paragraphs describing it as I do believe that the code is what gets the idea in a direct way.

The example is a simple page that uses SqlDataSource to connect to a SQL Server 2005 Express database and show the results on a GridView with paging capability.


Many parts of the code don’t show the best practices for their situation and those are only included for demonstration purpose as they are not the main focus of the example.

Let’s start with the code behind of the page:

As it’s the most important part

 * The sample is provided AS IS without any warranty
 * All rights reserved (C) 2005, Mohamed Meligy
 * Distribution of this code without this note is prohibited.
//Default "using" set of a new System.Web.UI.Page Visual Studio 2005 template:
using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
/// <summary>
/// To test the GridView behavior in action,
/// you need to have SQL Server Express installed (comes by default with VS2005),
/// and Northwind database attached to it
/// (attaches by default when you select "Quickstart Tutorials"
/// from the .NET Framework 2.0 SDK Programs menu, and choose to install them).
/// Alternatively, change the ConnectionString property of the SqlDataSource
/// to point to another installed instance
/// of SqlServer 2000 or SqlServer 2005 that has Northwind database attached.
/// </summary>
public partial class GridViewSamplePage : System.Web.UI.Page
    protected void Page_Load(object sender, EventArgs e)
        //Limiting redundancy of useless execution.
        //You do no need to check IsCallback if you
        // don't have controls with Callback Enabled.
        if (!IsPostBack & !IsCallback)
            //This makes performing paging and sorting uses AJAX.
            EmployeesGridView.EnableSortingAndPagingCallbacks = true;
            //Small number so that I can see many pages out of
            // 9 rows only (The total Rows Count of Northwind's Employees DataTable).
            //Also selected it in a way that last Page Rows Count will be
            // different than other pages.
            EmployeesGridView.PageSize = 2;
            if (!IsPostBack)   //Just to prove the AJAX thing.
                PostBackStatus.Text = "Not PostBack";
            else   //Never happens, as I don't require a PostBack.
                PostBackStatus.Text = "Page Is PostBack";
    /// <summary>
    /// Executes when the databinding is complete
    /// </summary>
    protected void EmployeesGridView_DataBound(object sender, EventArgs e)
        //I'll use it to show which set of Rows I'm showing in the page.
        EmployeesGridView.ShowFooter = true;
        //Similar to: EmployeesGridView.FooterRow.Visible = true
        //Stretching the first cell to fill the whole FooterRow:
        //Removing all non needed cells,
        // from the end to start
        // (so that the Cells collection is not recreated with every Removal).
        for (int cellNum = EmployeesGridView.Columns.Count - 1; cellNum > 0; cellNum--)
        EmployeesGridView.FooterRow.Cells[0].ColumnSpan = EmployeesGridView.Columns.Count;
        EmployeesGridView.FooterRow.Cells[0].HorizontalAlign = HorizontalAlign.Center;
        int startIndex = EmployeesGridView.PageIndex != EmployeesGridView.PageCount - 1 ?
        //Not in last page.
        EmployeesGridView.PageSize * EmployeesGridView.PageIndex
        //EmployeesGridView Rows Count is Count of the Rows of the current page, so,
            // unless Paging is Disabled, this is not total Rows Count.
            //gridViewTotalCount is declared and assigned at the end of this code.
        : gridViewTotalCount - EmployeesGridView.PageSize + EmployeesGridView.Rows.Count;
        EmployeesGridView.FooterRow.Cells[0].Text =
                ("Showing Employees {0} to {1} of {2}",
                startIndex + 1,
                startIndex + EmployeesGridView.Rows.Count, gridViewTotalCount);
    TableCell myCell = null;
    protected void EmployeesGridView_RowDataBound(object sender, GridViewRowEventArgs e)
        //I'll add that to every Row bound in the GridView.
        myCell = new TableCell();
        //Note that for the header, footer, and separator rows, DataItemIndex is -1
        myCell.Text = e.Row.DataItemIndex.ToString();
        //Note that when you add the cell,
        // this does NOT increase the GridView Columns Count.
        //The past lines will affect also HeaderRow, FooterRow, and even Pager,
        // you'll see when you run that this is not a desired behavior.
        //You can limit your code on condition. This is the recommended way.
        if (e.Row.RowType == DataControlRowType.DataRow)
            //Do your UI logic now for data binding,
            // much similar to DataGrid ItemDataBound.
            //Example: changing color of text
            // for normal and alternative rows ONLY by code.
            if (e.Row.RowIndex % 2 == 0)
                e.Row.Style["color"] = "#0000ff";
                e.Row.Style["color"] = "#00bb00";
            //This is the EmployeeID Cell
            e.Row.Cells[0].Text =
                "I'm alternative employee with code: " + e.Row.Cells[0].Text;
            //Another sample change making use of the DataItem:
            // This is specific to our case where the GridView is bound to
            // first DataTable in the DataSet returnd by the EmployeesSqlSource.
            // This is when SqlDataSource DataSourceMode = DataSet (Default)
            DataRowView rowView = (DataRowView)e.Row.DataItem;
            e.Row.Cells[EmployeesGridView.Columns.Count - 1].Text =
                int.Parse(rowView["Extension"] as string).ToString("###-##");
    int gridViewTotalCount;
    protected void EmployeesSqlSource_Selected
        (object sender, SqlDataSourceStatusEventArgs e)
        //GridView has no way of telling total Rows Count when paging is enabled.
        gridViewTotalCount = e.AffectedRows;

Now to the page XHTML source:

<%@ Page Language="C#" AutoEventWireup="true" 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
<html xmlns="">
<head id="PageHeader" runat="server">
    <title>GridView Sample</title>
    <form id="ServerForm" runat="server">
        Postback Status:
            <asp:Label ID="PostBackStatus" runat="server"></asp:Label>
            <asp:GridView ID="EmployeesGridView" runat="server"
                AutoGenerateColumns="False" AllowPaging="True"
                DataSourceID="EmployeesSqlSource" DataKeyNames="EmployeeID"
                    <asp:BoundField DataField="EmployeeID"
                        HeaderText="EmployeeID" InsertVisible="False"
                        ReadOnly="True" SortExpression="EmployeeID" />
                    <asp:BoundField DataField="LastName"
                        HeaderText="LastName" SortExpression="LastName" />
                    <asp:BoundField DataField="FirstName"
                        HeaderText="FirstName" SortExpression="FirstName" />
                    <asp:BoundField DataField="Title"
                        HeaderText="Title" SortExpression="Title" />
                    <asp:BoundField DataField="BirthDate"
                        HeaderText="BirthDate" SortExpression="BirthDate" />
                    <asp:BoundField DataField="PostalCode"
                        HeaderText="PostalCode" SortExpression="PostalCode" />
                    <asp:BoundField DataField="Extension"
                        HeaderText="Extension" SortExpression="Extension" />
                    <div style="text-align: center">
                        No Data Available.
            <asp:SqlDataSource ID="EmployeesSqlSource" runat="server"
"Data Source=MELIGYSQLEXPRESS;Initial Catalog=Northwind;Integrated Security=True"
"SELECT [EmployeeID], [LastName], [FirstName], [Title], [BirthDate], [PostalCode], [Extension] FROM [Employees]"

Samples of the output of the code:

Hope that you like it.