Saturday, October 27, 2007

How fast StringBuilder is ?

Subject

As we know StringBuilder builds strings faster than + operator or String.Concat() method.  Also StringBuilder with specified capacity performs faster than with default one.

But how fast StringBuilder is?

I created simple application to measure performance of different approaches of string concatenations. I will use several ways how to build a text: String.Concat(), StringBuilder with default capacity(16 character), StringBuilder with specified capacity.

 

Theory

 

Using String concatenation

Strings are immutable objects which means there is no way how to change already existing instance of string. Each time when we perform some action with string such as Trim(), Substring(), Replace(), etc it creates new object in the heap.

For example let's imagine that we have some array of strings and would like to concatenate them.

 

string[] myNameArray = new string[5]{"A", "R", "M", "E", "N"};

string text = null;

    

foreach (string s in myNameArray)

{

     text = String.Concat(text, s);

}   

 

Below you can see illustration of what exactly is happening in memory during each iteration.

 

Iteration 1:

There will be a String object ("A") allocated in the heap and a pointer will be returned back to "text" field.

image

 

Iteration 2:

By concatenating second member ("R") to already existing string we actually create new String object in a heap ("AR") and a reference to new created object will be returned to "text" field. The old object ("A") in a heap became obsolete and it will be collected by Garbage Collector and will be destroyed after.

image

 

Iteration 3:

The same story will happen with next member of array, string "M". There will be again created a new Sting object ("ARM") in a heap and the pointer of new object will be returned to "text" field. Previous object will loose its connection to pointer in the stack and object will be Garbage Collected.

image 

 

Iteration 4:

The same behavior as with the previous iteration. New object "ARME" will be created in the heap and "text" field start reference to it. As "ARM" object is not connected anymore with any pointer in the stack, it will be destroyed by Garbage Collector. 

image

 

Iteration 5:

And finally the last iteration. There will be again created new object and the previous one will be collected by Garbage Collector.

image

 

So, the conclusion is that to prepare simple string with 5 characters inside, we had to create 5 String objects, allocate memory space for each of them, where 4 objects immediately became a candidates for GarbageCollector.

 

When I was young my Mom was saying to me "I am afraid to ask you to clean anything in the kitchen, because you will create more mess around you" :D String Concatenation works pretty the same way.

 

StringBuilder with default capacity 

Ok, let's now build a sting by using StringBuilder. By default StringBuilder has 16 character capacity. It means that object in the heap will have allocated memory space for 16 characters. Which is perfect for us as we have to build a string with only 5 characters inside:

StringBuilder textSBuilder = new StringBuilder();

 

image

 

Again, we are iterating thru array and adding each member to StingBuilder:

foreach (string s in myNameArray)

{

     textSBuilder.Append(s);

}

 

Illustration below shows that all characters (strings) will be located to existing StringBuilder object, which "txtSBuilder" referencing to. There is no new object creation in the heap and there is nothing to be destroyed by Garbage Collector. So this approach should perform much faster than usual string concatenation.

 

image

 

Well, this is good, but what will happen if the string become bigger than capacity of StringBuilder. The answer is easy, in the moment when StringBuilder will reach to its capacity and will need more space, there will be created new StringBuilder object in the heap with doubled (in our case it will be 2 x 16 = 32 characters) capacity. All members of the current object will be copied to the new one and the pointer in stack will start referencing to the new object.

So, let's try to make the same operation as we did before but repeat it 4 times. Which means we need to get string of 4 x 5 ("A", "R", "M", "E", "N") = 20 characters.

 

for (int i = 0; i < 4; i++ )

{

      foreach (string s in myNameArray)

      {

            textSBuilder.Append(s);

      }

}

As you can see on illustration below, when StringBuilder object fills its capacity and need more space for adding new characters, new StringBuilder object will be allocated in the heap with double capacity than previous one (2 x 16 = 32), all chars from original object will be copied to new one and "textSBuilder" field will change reference to the new StringBuilder object. The original StringBuilder will become obsolete and will be destroyed by GarbageCollector.

 

image

 

 

StringBuilder with Specified Capacity

 

To optimize StringBuilder to perform better, it is recommended to specify capacity of StringBuilder object in the moment of instantiation. The point is that if we know how many letters will string contain, we have to specify this number as capacity for StringBuilder and it will allocate just one object with enough size for our need.

Lets perform the same operation as we did before but with specifying capacity.

 

StringBuilder textSBuilder = new StringBuilder(20);

 

Illustration shows that we just created one object. No need for new object creation, no new memory allocation, no work for GarbageCollection (at least for now). 

 

image

So, this is the best way how to build a strings.

 

 

Speedometer

Now is the time for real test :)

As I mentioned before, I created small console application where I used all those approaches to see the result in "real numbers".

There are several methods which basically do the same thing: cycle specified number of times and build a string by concatenating existing string with new char(or text). Difference is that all of them use different approaches: String.Concat(),  StringBuilder(), StringBuilder(capacity). There also set some checkpoint interval in which application writes out report.

 

Here is the example of one of those methods.

/// <summary>

/// Concatenation of strings by using String.Concat method.

/// </summary>

private static void StringConcatenation()

{

     String text = null;

               

     //Reset the properties related to checkpoint.

     //Write out start time.

     OperationReportPreset("String.Concat()");          

 

     //Perform concatination specified number of times

     for(int i=0; i<OPERATION_COUNT; i++)

     {

          //Concatinate two string by using

          //String.Concat(string, string) static method

          text = String.Concat(text, textForConcatenation);

 

          //Write out checkpoint result to show

          CheckpointReport();

 

          //each concatination creates new object in a heap;

          numberOfCreatedObjects = i + 1;           

     }

               

     //Write out operation end time.

     OperationReportFinalizer();

}

Other methods are pretty the same. The difference is that they use StringBuilder().Append() functionality instead of standard concatenation.

 

Note: The whole project you can download at the end of this blog post. There is a "Source Code" link.

 

Execution

After execution I got this output:

image

Execution with String.Concat() took more than 2 minutes.

It is interesting to observe the dynamic of objects creation. First 20000 concatenations took 1 second, for next 20000 almost 3 seconds, for another 20000 more than 6 seconds. For the last 20000 operations, it took 25 seconds. Which means as bigger string becomes after each iteration as more time it needs to allocate memory for the new String object in a heap.

BTW, after all iterations there  will be 200000 objects created in the heap where 199999 are unused and obsolete.

 

Lets take a look how StringBuilder with default, not specified capacity performed: 

image

The same action has been performed in less than 1 second, almost instantly. New object creates with double size each time when StringBuilder reaches its capacity. There were only 15 objects created during whole iterations where "only" 14 are obsolete.

 

What about StringBuilder with specified capacity:

image

Well it performed with the same result - under the 1 second but only 1 object has been created in the heap.

 

 

Report

 

 

Number of operations

Total performance duration

Created unused objects for GC

String.Concat()

200000

2 min 22 sec.

199999

StringBuilder with default capacity

200000

less than 1 sec.

14

StringBuilder with specified capacity

200000

less than 1 sec.

0

 

 

The StringBuilder with default parameter performs with the same speed as StringBuilder with specified. But of course we didn't count time which GarbageCollector needs to clean up the memory from unused objects. And of course the size of those objects also very important. There are 14 obsolete objects created by "StringBuilder with default capacity" which should be removed from memory and they all together take around half megabyte of memory size.

 

My Advice

My advice is to avoid using Sting.Concat() or + operator at all. Use instead StringBuilder with specified capacity. It is much faster and cheaper approach.

 

 

Technorati Tags: , , ,

 

kick it on DotNetKicks.com 

Wednesday, August 8, 2007

Rosario - the next generation of Visual Studio available already today

 

"Rosario" is the new version of Visual Studio Team System follows "Visual Studio 2008" Team System. New generation of Visual Studio available already today. Yes yes, there is a CTP version of "Rosario" on msdn available for download. Follow the link and get an image of "Rosario" (plus some documentation) now :)

Visual Studio Team System Code Name "Rosario"

Friday, August 3, 2007

Commerce Server 2007

Commerce Server 2007 is a huge and powerful application but it is a problem to find documentation or material about it. Including the fact that there are not so many people working on Commerce Server 2007, it is a new product and there is no book, it should be a problem to start implementation.

Nikola Malovic has a couple of awesome posts on his blog site blog.vuscode.com about Commerce Server 2007. Follow the link and check them out. 

Friday, July 27, 2007

Visual Studio 2008 Beta 2

Visual Studio 2008 Beta 2 is now available on MSDN web site :). Follow the link, pick the edition and download it.

Download Visual Studio 2008 Beta 2

Sunday, July 22, 2007

Family.Show 2.0

Version 2.0 of Family.Show application which is an incredible example of WPF technology now available. You can download it at Vertigo website http://www.vertigo.com/familyshow.aspx

There are a couple of new features added to application:

· New “Family Data View” with filtering, sorting, and in-place editing

· Family Analytics including last name tag cloud, age distribution historgram and birthday list.

· Enhanced story editing with support for font name, size, alignment, bullets,  and numerical lists

· Filtering and sorting the Family List view, in the main window

· More cowbell!

· Skinnable user interface with two skins: black and silver

· Improved Windsor family sample data file with stories and images.

· Source code migrated to CodePlex

Tuesday, July 3, 2007

WinForm UI interface on WEB applications

If you get used to WinForm UI interface and would like to create a web site witn the similar design or maybe you have a goal to create two applications WinForm and Web with synchronized UI interface, the NETIKA TECH company has solution for that. NETIKA TECH provides rich GOA WinForm controls for Silverlight or Adobe Flash and entirely FREE. You can visit NETIKA TECH web pages to get full information about the product, see live demos and download for free. The GOA core library includes more the 40 controls and components:

 

  • Control, ContainerControl, ScrollableControl, Panel
  • Button, CheckBox, RadioButton, GroupBox, Label
  • TextBox, NumericUpDown
  • ImageBox, ImageList
  • ScrollBar, HScrollBar, VScrollBar
  • Form, MessageBox, Cursor
  • ListBox, CheckedListBox
  • ComboBox
  • TreeView
  • MonthCalendar
  • TabControl, Splitter
  • ToolTip, ProgressBar, Timer
  • ToolStrip, StatusStrip, MenuStrip, ToolStripButton, ToolStripComboBox, ToolStripDropDown, ToolStripLabel, ToolStripProgressBar, ToolStripSeparator, ToolStripSplitButton, ToolStripTextBox
  • XamlCanvas (Silverlight specific)
  • Rich DataGrid controls and more

 

Download the GOA WinForm

Tuesday, June 26, 2007

Hidden Development Methodologies

There are many unknown methodologies which we are touching every day during development but don't have a clue about them. Have you heard about ADD, CDD, CYAE, DBD or GMPM. Well, I did not until I visited the Berkun Blog.

Follow the link http://www.scottberkun.com/blog/2007/asshole-driven-development/ and you will be surprised. :)

Very useful information for people who are organizing and leading development.

Friday, June 22, 2007

ReSharper 3.0 has been released

JetBrains released next version of its awesome application ReSharper 3.0.

ReSharper is an add-in for Visual Studio which contains many features for .Net application development. It helps simplify the process of writing a code. Ones I stared to use ReSharper I cannot imagine working without it after. It has many features but the best from my point of view is static code analyzer which  brings you errors or warnings on the fly without compilation. Another excellent feature is searching the objects inside of solution which is much powerful and has much better interface for doing that.

With the new version ReSharper supports XAML and XML, offers C# code suggestion on the fly and much much more.

Just follow the link to check out all the features exist in ReSharper 3.0

http://www.jetbrains.com/resharper/features/index.html

 

To download a 30 days free trial version click here

Tuesday, June 19, 2007

WPF in life

This is a simple application which shows a power of Window Presentation Foundation. Just follow the link, download "ClickOnes" installation and have a fun. You gonna love it. :)

http://www.vertigo.com/familyshow.aspx

The most important part is that you can download the source code and investigate application structure.

Thursday, May 31, 2007

Incredible future in IT world

This is awesome. This is an incredible future of computer hardware. It's beeter to see than to talk about :)

Microsoft Surface

Wednesday, May 23, 2007

CLR Internals from Jeffrey Richter

Well, I was sick a couple of weeks and was not able to observe  what's going on in IT world. Now I am back and first what paid my attention was Jeffery Richter's session about CLR internals. Maybe it is not fresh seminar of him but really good and useful.
I am strongly recommending to .Net programmers to watch his session.By my opinion good .Net programmer should know what kind of stuff is rolling inside of CLR during .Net application execution and he is the BEST source for that kind of knowledge.

http://www.microsoft.com/seminar/en/DEV424_files/default.htm#nopreload=1

Monday, April 23, 2007

How to create an Add-in for Visual Studio?

If you are planning to create your own Add-in for Visual Studio, I found a very good source written by Jon Rista - Writing a Visual Studio 2005 Add-in.
Follow the link below and you'll see explanation and will have ability to download source code (C#).

http://www.codeproject.com/useritems/LineCounterAddin.asp

Monday, April 16, 2007

Bible for Refactoring.

Have you seen how code “smells”? If not yet, strongly suggesting you to read the book of Martin Fowler “Refactoring: Improving the Design of Existing Code”. That is another bible for software developers. Many if not all of us are cleaning the code, changing structure, making refactoring based on code style we like.

This book explains why refactoring is so important and brings refactoring to the level of systematization, makes strong agreement between developers to "when" and "how" to refractor the code. Shows how to simplify communication between developers by using terms which contains definition of “problem” and “solution”.

I would like add myself that refactoring should be a part of the software development cycle and the book helps to make it happened.

So, read a book and you will see how your code code “smells” :).

Autor's web site
Amazon

Saturday, April 14, 2007

ASP.NET: Monitoring of web page life cycle

 

I wrote simple code which is showing order of execution of events and protected methods related to the page life cycle.

I simply added output messages into the  each event and protected method of Page and Control (UserControl which is located on that page). This is an example how I used it:

...

protected void Page_Init(object sender, EventArgs e)
{
    Container.messageCollection.Add("P: Page_Init");
}

...

protected override void OnInit(EventArgs e)
{
    Container.messageCollection.Add("P: Before base.OnInit");
    base.OnInit(e);
    Container.messageCollection.Add("P: After base.OnInit");
}

etc.

After filling a collection I just write messages out in order how they were added.

 

And this is an output result:

1: P: Before base.OnPreInit

2: P: Page_PreInit

3: P: After base.OnPreInit

4: C: Before base.OnInit

5: C: Page_Init

6: C: After base.OnInit

7: P: Before base.OnInit

8: P: Page_Init

9: P: After base.OnInit

10: P: Before base.OnInitComplete

11: P: Page_InitComplete

12: P: After base.OnInitComplete

13: P: Before base.OnPreLoad

14: P: Page_PreLoad

15: P: After base.OnPreLoad

16: P: Before base.OnLoad

17: P: Page_Load

18: P: After base.OnLoad

19: C: Before base.OnLoad

20: C: Page_Load

21: C: After base.OnLoad

22: P: Before base.OnLoadComplete

23: P: Page_LoadComplete

24: P: After base.OnLoadComplete

25: P: Before base.OnPreRender

26: P: Page_PreRender

27: P: After base.OnPreRender

28: C: Before base.OnPreRender

29: C: Page_PreRender

30: C: After base.OnPreRender

31: P: Before base.OnPreRenderComplete

32: P: After base.OnPreRenderComplete

33: C: Before base.OnUnload

34: C: Page_Unload

35: C: After base.OnUnload

36: P: Before base.OnUnload

37: P: Page_Unload

38: P: After base.OnUnload

 

First "C" letter or red color are messages from UserControl side. Messages with "P" letter or blue color represent page cycle in Page level.


So, now you can see an order how events in page and contol occure during page life cycle.

ASP.NET: Monitoring of web page life cycle

 

I wrote simple code which is showing order of execution of events and protected methods related to the page life cycle.

I simply added output messages into the  each event and protected method of Page and Control (UserControl which is located on that page). This is an example how I used it:

...

protected void Page_Init(object sender, EventArgs e)
{
    Container.messageCollection.Add("P: Page_Init");
}

...

protected override void OnInit(EventArgs e)
{
    Container.messageCollection.Add("P: Before base.OnInit");
    base.OnInit(e);
    Container.messageCollection.Add("P: After base.OnInit");
}

etc.

After filling a collection I just write messages out in order how they were added.

 

And this is an output result:

1: P: Before base.OnPreInit

2: P: Page_PreInit

3: P: After base.OnPreInit

4: C: Before base.OnInit

5: C: Page_Init

6: C: After base.OnInit

7: P: Before base.OnInit

8: P: Page_Init

9: P: After base.OnInit

10: P: Before base.OnInitComplete

11: P: Page_InitComplete

12: P: After base.OnInitComplete

13: P: Before base.OnPreLoad

14: P: Page_PreLoad

15: P: After base.OnPreLoad

16: P: Before base.OnLoad

17: P: Page_Load

18: P: After base.OnLoad

19: C: Before base.OnLoad

20: C: Page_Load

21: C: After base.OnLoad

22: P: Before base.OnLoadComplete

23: P: Page_LoadComplete

24: P: After base.OnLoadComplete

25: P: Before base.OnPreRender

26: P: Page_PreRender

27: P: After base.OnPreRender

28: C: Before base.OnPreRender

29: C: Page_PreRender

30: C: After base.OnPreRender

31: P: Before base.OnPreRenderComplete

32: P: After base.OnPreRenderComplete

33: C: Before base.OnUnload

34: C: Page_Unload

35: C: After base.OnUnload

36: P: Before base.OnUnload

37: P: Page_Unload

38: P: After base.OnUnload

 

First "C" letter or red color are messages from UserControl side. Messages with "P" letter or blue color represet page cycle in Page level.


So, now you can see an order how events in page and contol occure during page life cycle.

Monday, April 9, 2007

.NET 2.0. Access file in Design Time mode.

Most of programmers who are dealing with ASP.NET know how to access files on the server. The common way how to do this is to use HttpContext.Current.Server.MapPath static method and get physical path of the file by passing virtual. But what if we need for instance to read some data from text file which located in our project in Design Time mode. Server.MapPath won't help us so much as our application is not hosted by IIS or Cassini and HttpContext didn't fill yet. How to get physical path of the file then?  Thanks to .Net 2.0 it is simple.

 

For instance let's try to get physical path of the file (sample.txt) stored in the root directory of project thru server control .

 

To achieve our goal we need three players ISite,  IWebApplication and IProjectItem.

ISite - Gets information about the container that hosts the current control when rendered on a design surface.
We have this property available in control level (Control.Site). Be aware Site property is filled only in design time mode and not available when application hosted under the IIS or Cassini.

IWebApplication - IServiceProvider based interface which provides access to Web application in Design Mode.
By using this service we have ability to access items in our projects and reading web.config file in Design Mode.

 

IProjectItem - Provides an interface for an item that is retrieved at design time.
Contains such information as physical path, virtual path, name etc

 

Step 1.
First we have to get IWebApplication service from the list of running services.

IWebApplication webApp = (IWebApplication)Site.GetService(typeof(IWebApplication));

 

Step 2.
Get project item by calling appropriate method.

IProjectItem item = webApp.GetProjectItemFromUrl("~/sample.txt");

 

Step 3.
Then just get information about physical path from property of IProjectItem interface.

string filePhysicalPath = item.PhysicalPath;

 

That is it. Easy isn't it, but big headache for the programmers who need that and doesn't know about it. :) 

Sunday, April 8, 2007

Community Server: Google Indexing

Due to fact that Community Server stores context of blogs in SqlServer, google won't index them.

How to make google to start indexing your blogs on Community Server? Dan Bartels created an Add-on which is dynamically creates sitemap for google. Follow by the link and download files with installation extraction.

http://communityserver.org/files/folders/add-ons/entry547382.aspx

Installation procedure takes 5 minutes.

Tuesday, April 3, 2007

How to determine Design Time mode in ASP.NET

 

During creating of Custom Controls sometimes programmers are dealing with implementation of code which should run only in Design Time mode. And the main question is, how to determine in ASP.NET whether your code is running in Design Time mode or not?

I can offer several approaches for checking that.

DesignMode property

First and obvious decision is to use DesignMode property of Control class. It is a Boolean value which returns true in case when your code in running in Visual Studio.

But this approach has two disadvantages:

1.  What if you need to determine design time mode not in control implementation but in some class which is part of your WebSite project. In that case access to DesignMode won’t be such easy ;)

2.  DesignMode property is new one in .Net Framework 2.0 and not exists in 1.1

There are several ways how to avoid this problem.

HttpContext

We can check HttpContext object against null value. During design time mode HttpContext object is empty which means we can write something like this:

public bool IsDesignMode
{
    get { return System.Web.HttpContext.Current == null; }
}

HostingEnvironment

Second approach is to use IsHosted static property of HostingEnvironment object which provides functionality to manage application within application domain. During design time application is not hosted.

public bool IsDesignMode
{   
    get{ return !System.Web.Hosting.HostingEnvironment.IsHosted; }
}

Site

Next approach is to use System.Web.UI.Control.Site . It gets information about a container which hosts the current control when rendered on a design surface . And in our case the code can look like this:

public bool IsDesignMode
{
    get { return Site!=null; }
}

I tried all approaches during control implementation and all of them are working fine.

Asp.Net: How to debug custom controls in Design Time mode.

If you are planning to create WebControlLibrary you will certainly need to debug the code not only in normal runtime but also in Design Time mode. In case of error in a code in design time usually you see rectangle with an exception message. But of course you need to step thru the code to fined the bug. But how to do that ? Is there a way to debug a code during design time?

I am glad to say “YES”, it is possible and easy.

It will be much easy and clear if we do it together step by step in concrete example.



First of all lets create a test WebControlLibrary project.






Then right click on project and select property.


In the property window navigate to Debug section and switch radio button from “Start Project” (set by default) to “Start external program” and browse for devenv.exe executable of Visual Studio which you are using.




Close the property window and for testing purposes set a breakpoint in RenderContent method.




To start debugging right click on project and select “Debug --> Create New Instance”





Debug process will create an instance of Visual Studio. To test behavior of control you can choose one of your existing web projects or create new one. For now I will create fresh WebSite project. Notice that original version of Visual Studio is in Debug mode. During creation or opening web project I am suggesting to turn off any Add-ins if you are using in Visual Studio. Sometimes those tools are raising exceptions and I don’t see reason to use them during testing of design time behavior of custom control.











Now it will be maybe easier to add our assembly to the Toolbox and use it from there. It will automatically add reference of our assembly. By using Drag and Drop technique it will automatically register assembly on a page .


On Toolbox right click and select “Choose Items”.




Navigate for our assembly by using “Browse” button. Make sure that you are picking debug version of assembly (by default it will be located in Debug folder inside of Bin).




After clicking “OK” on “Choose Toolbox Items” window our custom control (or controls if you have several in project) will appear in Toolbox window of Visual Studio.






Now just find it there, drug and drop to the web page. Switch from “Source” mode of your page editor to “Design” and “the magic will appear” :)



Now add breakpoints you need, step thru code, do the stuff you are usually doing during debugging. Next time you can just run "Debug-->Create New Instance" and just choose created WebSite project.

I hope this information will help you to create nice, professional controls without any bugs :).

Have a fun.








Friday, March 9, 2007

What is the difference between Implicit and Explicit interfaces?

Hi if you want to find out the answer to that “guru” question and also to have really good understanding of how C# is working under the hood, understanding IL, Garbage Collector, Type Reflection, Late Binding, Attribute-Based Programming, Object Serialization etc, I am recommending to read Andrew Troelsen’s book Pro C# 2005 and the .NET 2.0 Platform”.




PART 1 ■ ■ ■ Introducing C# and the

.NET Platform

CHAPTER 1 The Philosophy of .NET
CHAPTER 2 Building C# Applications

PART 2 ■ ■ ■ The C# Programming Language
CHAPTER 3 C# Language Fundamentals
CHAPTER 4 Object-Oriented Programming with C#
CHAPTER 5 Understanding Object Lifetime
CHAPTER 6 Understanding Structured Exception Handling
CHAPTER 7 Interfaces and Collections
CHAPTER 8 Callback Interfaces, Delegates, and Events
CHAPTER 9 Advanced C# Type Construction Techniques
CHAPTER 10 Understanding Generics


PART 3 ■ ■ ■ Programming with .NET Assemblies


CHAPTER 11 Introducing .NET Assemblies
CHAPTER 12 Type Reflection, Late Binding, and Attribute-Based Programming
CHAPTER 13 Processes, AppDomains, Contexts, and CLR Hosts
CHAPTER 14 Building Multithreaded Applications
CHAPTER 15 Understanding CIL and the Role of Dynamic Assemblies


PART 4 ■ ■ ■ Programming with the .NET Libraries


CHAPTER 16 The System.IO Namespace
CHAPTER 17 Understanding Object Serialization
CHAPTER 18 The .NET Remoting Layer
CHAPTER 19 Building a Better Window with System.Windows.Forms
CHAPTER 20 Rendering Graphical Data with GDI+
CHAPTER 21 Programming with Windows Forms Controls
CHAPTER 22 Database Access with ADO.NET


PART 5 ■ ■ ■Web Applications and XML

Web Services

CHAPTER 23 ASP.NET 2.0 Web Pages and Web Controls
CHAPTER 24 ASP.NET 2.0 Web Applications
CHAPTER 25 Understanding XML Web Services


Control’s identifiers in ASP.NET 2.0: ID, ClientID, UniqueID, AssosiatedControlID

“What is the difference between ID, ClientID, UniqueID and AssosiatedControlID identifiers of the control?” -

I’ve heard this question a lot of times from .Net developers . That is why I decided to start my blogs with the simple but common subject, about the difference between identifiers of web control in ASP.NET.

Web controls contain several identifiers : ID, UniqueID, ClientID and AssosiatedControlID. What are they?


“Theory”

ID is a unique identifier of element which helps us to access programmatically to the controls properties, methods and events. Each control on the page should contain unique value of the ID property. In Visual Studio value of ID property will be set automatically after dragging and dropping element from toolbox to the page. Property is not readonly and can be changed by programmer to have more explainable name. In case of missing ID compiler will not generate an error and control will be generated on a page but access to control will be lost.

ClientID is an identifier of the rendered element on html level. It helps us to access the element by script languages or css. ClientID is a read only property and generates automatically. Common usage of this property is when we are programmatically creating script code from code behind level and need to specify the ID of element in the script’s code.

For instance:

protected TextBox txtMyTextBox;


protected void Page_Load(object sender, EventArgs e)
{
StringBuilder sb = new StringBuilder();
sb.Append("<script>");
sb.Append("function MyFunction()");
sb.Append("{");
sb.AppendFormat("document.getElementById('{0}').value = 'Test'; ", this.txtMyTextBox.ClientID);
sb.Append("}");
sb.Append("</script>");


Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "CustomKey", sb.ToString());
}


UniqueID is an identifier which generated automatically by ASP.NET to identify control within a page as there can be several controls with the same ID included in different containers. UniqueID generates based on ID of container and ID of control. ASP.NET accesses to Page’s element through UniqueID of the element.


“How does it work”

I think it is time to code a little bit. Let’s create a new web project and on default page add Label control with ID=”MyLabel”.

<asp:Label ID="MyLabel" runat="server" Text="My Label on a page "/>

Then in Controls folder let us to add new User Control called MyUserControl.ascx and add Label control inside of the user control and set ID of the Label control to “MyLabel”.

<%@ Control Language="C#" AutoEventWireup="true" ... %>

<asp:Label ID="MyLabel" runat="server" Text="My Label in user control"/>


Let add this user control into the page where previous Label controls is located. Now we have two elements on a page “MyLabel” and “MyUserControl “ (which contains another “MyLabel “ control).

<body>
<form id="form1" runat="server">
<div>
<asp:Label ID="MyLabel" runat="server" Text="My Label on a page"></asp:Label>
<br />
<br />
<uc1:MyUserControl ID="MyUserControl1" runat="server" />
</div>
</form>
</body>



Let’s to set a breakpoint in Page_Load level of page initialization and investigate identifiers of the Label controls which we have on a page: one is located directly on a page and the second one inside of UserControl. As you can see ID property of the both controls are the same like we set.





There is no issue with this as server identifies control by UniqueID and not ID. You can see it in next image. UniqueID of the Label which was set directly on the page has the same value as ID but Label control located in MyUserControl has UniqueID which ASP.NET generates by concatenation of container’s ID and control’s ID divided by “$” sign (in ASP.NET 1.1 it is “:”).



The same story with a ClientID. In case whether control located in some kind of container ASP.NET generates ClientID based on container ID and control ID divided by “_” sign.



Here is the result of rendered html code :








“What about AssosiatedControlID”

In ASP.NET 2.0 Label web control contains a new property, AssociatedControlID, which points to another input control such as a TextBox control. When the property is set, generated tag of the Label control will be not <span> but <label> For attribute of <label> element assumes the clientId of the associated control as the value.

ASP.NET code:



<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
<asp:Label ID="Label1" runat="server" AssociatedControlID="TextBox1" Text="Label Text" />


Generated Html code:

<input name="TextBox1" type="text" id="TextBox1" />
<label for="TextBox1" id="Label1">Label Text</label>


The result of rendering is that after clicking on label assosiated textbox control will get focus.




“Summary”

It is very important to understand the difference between identifiers as you will use them almost everywhere during web development.