This line of tutorials will take you through all the ASP.NET fundamentals
Architecture of ASP.Net
How an ASP.NET page is processed?
All the asp.net pages are parsed into a class definition and that class is then compiled into a.Net assembly who sole purpose is respond to request destined for the endpoint. This class is then loaded into the worker process i.e. w3wp.exe and the classes will then be created and will process the requests. These classes are created on demand and this happens for all the .aspx. So it’s safe to say that when you are writing an .aspx you are writing a class. So essentially when we are writing aspx we are just building additional classes and extending the base classes and controlling the class generation from .aspx files.
Let’s see this in action. I hope you have IIS installed on your machine. So just go to cà inetpub à wwwroot and create text file named HelloWorld.aspx and add the following content to it.
<h1> Hello World!!! </h1>
And then save it and close it. Now go to the Internet Explorer and type the following:
And you will see something like below:
Now let’s understand what going on here. Let’s first add the code as shown below to the HelloWorld.aspx. The Page Directive will set the language as C# and also the Debug to true. Also we will access the GetType().Assembly.Location method as we know we are in .NET and we will be able to track the location of the class.
<%@ Page Language=”C#” Debug=”true” %>
<h1> Hello World !!! </h1>
<h3> This Page is loaded from
<%= GetType().Assembly.Location %>
The %= is the evaluation syntax in the server side script <%= GetType().Assembly.Location %>
Now when you will refresh the page, you could see the location from where the assembly was loaded along with the name of the assembly.
you could see that C# source code files are present here and if you open them you could see the class definition present in it. As you could see the name of the class is created by replacing the . with an _ and it derives from System.Web.UI.Page which is the base class for all the aspx pages.
Now if we scroll down the file we could see how the html is parsed and the method that we wrote injects the content.
Now as we could see in the image below, we could see Interspersed script notation which is root cause of many problems in a web site so we do not want to follow this as a practice at all. This syntax is still supported but we will try to move towards other techniques for easier to maintain code.
So the types of dynamic content that we can integrate onto our page is
- Interspersed server-side script – So this is the way of dropping code onto the page but the language will be as specified in the page directive. It has to be in the language specified at the top of the page. Then we also have the evaluation syntax (GetDisplayItem) which is equivalent to Response.Write.
- Server side scripts – So we can also include server side scripts as a block with the Runat sever attribute so that it is dumped into the class definition.
Let’s just add the following code to the HelloWorld.aspx from the previous example.
<%@ Page Language=”C#” Debug=”true” %>
const int _itemCount = 10;
string GetDisplayItem(int n)
return “item #” + n.ToString();
<h1> Hello World !!! </h1>
<h3> This Page is loaded from
<%= GetType().Assembly.Location %></h3>
<% for (int i=0;i<_itemCount; i++)
<% } %>
Response.Write(“<h2>Total Number of items = ”
+ _itemCount.ToString() + “</h2>”);
When we run the page we would see something like below:
Let’s go back to the directory and have a look at the generated content once again. So what we see here is that the server side code is injected directly into the code file. So whenever we use server side scripting then that is dropped into the class directly. So we used put only those things in server side scripting that would make sense if they are in the class definition directly. So we could not directly executable code in class definition.
And the client code is added to the function definition that will write onto the screen. So the code that was part of Interspersed script is put directly into a function within our class. We could not define function here as nested function definition is not allowed in C#.
Server Side Controls
We should avoid using Interspersed scripts as it tends to clutter pages and makes the code difficult to maintain. We should try to use the preferred model for dynamic content in an ASP.NET page. This model comes from the server side controls in ASP.NET. So any control that has a runat=”server” attribute will be added to the class definition as a server side member variable, so we could manipulate these variable instead of the Interspersed scripts. The state maintained for the Server side controls is implicitly POST to the same page.
Let’s revisit our page and replace the server side scripts with server side controls. Let’s first replace the dynamic generated script with the server side control definition. We are following a common technique of populating the server side control with some content even though this content will never be displayed. So we are using a server side control named bulleted list which will display an unordered list.
Now we are going to write a method to populate this list. So we are overriding the OnLoad method which we inherited from the page base class. So we are using the already created list _displayList and clearing the items in it. Then we are iterating through the items and add the items to the _displayList.
If you will run this page now you will get an error saying that the runat=”server” controls should be placed in the form with a runat=”server” attribute. So let’s add that.
And now we run the page we will something like below.
Let’s also have a look at the class definition changes with the addition of the server side controls. The very first thing that you will notice is that the BulletedList named _displayList is added as a protected member. And the interaction with that _diasplayList member is shown below it.
In the previous section we edited the server side control at very low level but we can also use ASP.NET data binding model. So we will add a string array of the items we want to show. It has to be an Enumerable collection. It can be an array, dataset, datatable, strongly typed list class, etc. So all we need to do is the ItemsSource property to the collection we want to bind to and then exclusively call DataBind(). Let’s see the code of the same.
We will see a similar output if we run this page but instead of iterating and adding the items we have utilized the power of data binding.
Declarative Data Binding
Version 2.0 of .NET introduced data source controls. The idea behind declarative data binding is that instead of manually writing the code for data binding we hand it off to another control. In this case we will have a look at the ObjectDatSource as this lets us point the datasource to a class definition. To use it we have to specify the name of the class to use and the name of the method that will be used to retrieve the data. So now our page will not have any data access code as all that logic is separated to a separated class. So let’s write the code for this. Let’s go to the wwwroot folder and create a directory named App_Code. This is a special directory because if we place any source code files in this directory they will be implicitly complied if they are referred any of our pages. We will then add a file named ItemsDataSource.cs
We will remove all the server side code as it will be handled by this declarative data source. And then let’s wire up to the ItemsDataSource. We have added an object data source as MyDataSource and refer it in the BulletedList. So now when the list needs the data it will go and query the mentioned object data source which will in turn query the specified method in the specified class.
Code Behind V2.0
The ASP.NET version 2.0 code behind model is like shown below. We have specified in our aspx page the code behind for this page. Also we have the concept of partial class implemented for these classes.
Let’s change our code accordingly. Let’s add a new file names hellocodebehind.aspx.cs and move our code which not related to the presentation to this file.
So now we have the ability to separate the code from the view as we saw in the previous section. Let’s understand the ASP.NET page lifecycle which is shown in the image as below. This will help us understand many other things that can be done inside the page class definition. Just refer the aspx.cs class that we wrote earlier and you will see that we have overridden the OnLoad event of the page. This is one of the events that take place while processing the request for the page and this is most common of the events in which users generally tap into for doing data binding modifying controls and there values. There are many other events that occur during the complete page request process as we could see in the image below. When a request for an aspx page is made then class is constructed and its constructors will be called and then this lifecycle sequence is launched starting from the top left to the bottom right. Another event for which handler is added is very commonly is Init. This event occurs early in the lifecycle of the page but after all the controls have been loaded into the control tree. Another event is the LoadComplete event which is fired after all the server side events have been fired. Pre render is a back stop which takes place just before the rendering is sent to the client. PreInit is the only event where we can edit master pages and themes. Render event occurs when the response is sent back to the client. Once the response is sent back to the client then Unload events occurs.
Let’s talk about how we can wire up events. This is the techniques that can be used to wire up all the events in the page class. The naming convention for such events is On followed by the name of the event.
In Visual studio the standard techniques when using Visual Studio is to create a function named Page_ followed by the name of the event and .Net will implicitly add a delegate subscription. This function is called as the Auto Event Wire Up and this is the preferred model in Visual Studio.
Another way of accessing this events is to access these events as the members of the Page class. Simply .NET events defined on the System.Web.UI.Page Base class and all we need to do is use += to add a delegate.
So let’s see this in action. Let’s modify the HelloWorldCodeBehind.aspx to use the AutoEventWireUp.
Now let’s make use of Auto Event Wire up and tap into the LoadComplete event. We need to modify the HelloWorldCodeBehind.aspx.cs for this as below.
When we run this page we will see that the text is written at the top of the page.
Method Name for Implicit event subscription
The way AutoEventWireUp wire works is through the hashtable defined in the .NET. At runtime a check is made for the strings present in the code to match up with the string shown in the table below. So there is no algo for. So it’s just a set of hard wired strings that are looked for automatically when AutoEventWireUp property is set to true. This will work only if the signature also matches up with the event.
Control Event Handling
Other events that we will be handling in code are the events are raised by the controls on the page. So the recommended model for handling a control initiated event is go to the server side control in the view and add a prefix On to the event name and then set the handler for it. That handler in the code should have the correct signature of an event.
The other way to do it is use the += notation the code class to specify the handler for a particular event.
Let’s see this in action. Add a button and a label at the bottom of the HelloWorldCodeBehind.aspx file as shown below.
Now let’s go to the server side code i.e. HelloWorldCodeBehind.aspx.cs and add a handler for this button click event.
When we run the page we will see something like below.
Another feature that was added to .NET 2.0 was the suite of directories as shown below.
- App_Code directory is the place where we place the code and it automatically compiles as part of the aspx page request process.
- App_Browsers directory is used for defining additional .browser files which define the additional browser capabilities.
- App_GlobalResources directory automatically compiles .resx files into the application.
- App_LocalResources directory automatically compiles .resx files into the application.
- App_Themes directory is used for referencing themes in the site
- App_WebReferences directory is where wsdl files are placed.
The version 2.0 ships with a new compiler named aspnet_compiler.exe which helps us compile our directories manually into binary deployment files. Below is the detailed chart of all the directories and there usages.
The mechanism of shadow copying is import for the deployment, updating, etc. The idea behind it is this that we do not have to shut the site to deploy the new binaries. In classic ASP we need to shut down the server in order to release the references so that we can copy the new binaries without any errors. With version 2.0 we do not have to do that because of Shadow copying. As we can see in the diagram below when we try to access a binary what ASP.NET does is physically copies the binary to an obfuscated location and then runs so that there is no direct reference to the binary and also when the binary is updated then it updates the binary as well.
You can find the code for this post here.
Any questions, comments and feedback is most welcome.