Questions for ASP.NET Developers
NOTES ON .NET
Q1: How do I send a new page to the user?
A1: The Redirect method of the Response object is one of the most common ways to send users a new Web page:
You might also know of the similar method, Server.Transfer:
But do you know the difference between these two methods? The server-side Response.Redirect statement sends a command back to the browser to request the next page from the server. This extra round-trip is often inefficient and unnecessary, but this battle-tested standard works reliably and consistently. By the time Page2 is requested, Page1 has been flushed from the server’s memory and no information can be retrieved about it unless the developer explicitly saved the information using one of the techniques outlined later in this article.
The more efficient Server.Transfer method simply renders the next page to the browser without the extra round trip. Variables can stay in scope and Page2 can read properties directly from Page1 because it’s still in memory. This technique would be ideal if it wasn’t for the fact that the browser is never notified that the page has changed. Therefore, the address bar in the browser will still read “Page1.aspx” even though the Server.Transfer statement actually caused Page2.aspx to be rendered instead. While this bit of sneakiness can occasionally be a good thing from a security perspective, it often causes problems related to the browser being out of sync with the server. For example, if the user reloads the page, the browser will request Page1.aspx instead of the true page (Page2.aspx) that they were viewing.
In most cases, Response.Redirect and Server.Transfer can be used interchangeably. But in some cases, efficiency or usability may prompt you to use one instead of the other.
Q2: How do I pass values between pages?
A2: Context and QueryString are common ways to pass values between pages in ASP.NET. Which one is best depends on the particular circumstances.
The QueryString has been a common way of passing data around the Internet since before ASP was even invented. Before a variable value is placed on the QueryString, it should be encoded to ensure problematic characters (such as spaces and symbols) are interpreted correctly as data:
'Page1.aspx appends the user’s name to the QueryString
Dim sName As String
sName = Server.UrlEncode(txtName.Text)
Response.Redirect("Page2.aspx?Value=" & sName)
'Page2.aspx parses the value from the QueryString
Dim sName As String
sName = Request.QueryString("Value")
Response.Write("Your name is " & sName)
When the user arrives at Page2, the data is appended to the URL. Therefore, the address listed in their browser will look something like this:
The Context object isn’t as well known as the Session object, but it should be — the syntax is the same; simply replace the word “Session” with the word “Context”:
'Page1.aspx stores value in context before transferring
Context.Items("UserName") = txtName.Text
'Page2.aspx retrieves the value from Page1’s context
Dim sName As String
sName = Context.Items("UserName").ToString
Response.Write("Your name is " & sName)
One of the main differences between Context and Session is that Context only stays in scope until the page is sent to the browser. Therefore, this is one of the few examples where Server.Transfer must be used instead of Response.Redirect. Because Response.Redirect would cause the context to go out of scope, the data would be lost. Context uses server memory more sparingly than Session variables, so it’s often preferable except in cases where data needs to be stored across the user’s entire visit.
Before ASP.NET 1.0, posting data from one page to another was comparable to the QueryString (aka “get”) technique. ASP.NET 1.x made this technique less practical than it used to be because there was no longer any simple way to post data from one page to another. The new philosophy was that pages were meant to post back to themselves.
As ASP.NET 2.0 comes into focus and frees us from most cross-page posting limitations, this technique starts to become more favorable again. For example, by setting the PostBackURL property of a button control on Page1.aspx, you can have it post all form values (including any hidden text fields) to Page2.aspx. This technique requires no server-side code in Page1.aspx:
'Page2.aspx retrieves the posted form value
Dim sName As String
sName = Request.Form(“TextBox1”).ToString
Response.Write("Your name is " & sName)
Q3: How do I pass data to a user control?
A3: User controls often contain many controls within them. Sometimes it’s handy to be able to set the properties of those sub controls from within the page’s code-behind. I’ve witnessed much confusion about how to do this. Here’s a best-practice solution in three easy steps:
Step 1: In the user control’s code-behind file, create a public method or property that the page will call. In the following example, the user control contains a Label control. This example sets the encapsulated label’s Text property with the supplied parameter value:
Public Sub SetLabelText(ByVal val As String)
Label1.Text = val
Step 2: Within the code-behind class of the page, declare a strongly-typed reference to the user control:
Protected WithEvents MyControl1 As MyUserControl
This control is automatically instantiated by ASP.NET, so you don’t need the New keyword.
Step 3: Now you can call the user control’s custom method from within the page:
MyControl1.SetLabelText("Value set from page code behind")
Q4: How do I pass data back to the page from a user control?
A4: You could take an approach similar to the previous solution; that is, by calling a method on a strongly-typed reference to the page from within the user control:
However, this creates a circular reference, which is generally considered to be a questionable design decision because of object-oriented principles such as encapsulation. Such tightly coupled relationships are discouraged. One reason is that it would tie the control to this particular page, thereby limiting reuse. There are ways around that with Interfaces and such, but that’s where things start to get rather sloppy. It is considered preferable for child objects to raise events instead of directly referencing the parent. To raise an event, the event must first be declared within the user control’s class:
Public Event ButtonClicked()
Then the event can be raised to the page with a single line of code:
The page can then handle the control’s event with a simple declaration and event handler:
Protected WithEvents MyUserControl1 As MyUserControl
Private Sub MyUserControl1_ButtonClicked() _
Response.Write("User control's button was clicked.")
Q5: How do I pass a value between two user controls?
A5: This functionality can be achieved by combining the techniques for passing values to and from user controls. The page acts as the referee, permitting or denying communication between the controls as it deems appropriate. Controls can raise events to the page, which the page might decide to pass to properties or methods of other controls within the page.
Q6: How do I pass a value between an ASP.NET 2.0 page and its master page?
A6: The routine for passing data around remains similar for new ASP.NET constructs, such as Master Pages. From the aspect of passing data around, the master page acts as a control within the page. So, as with the earlier page/control techniques, to call a public method located within a page’s master page, you must cast the master reference to the exact class name:
Dim MP As MyMasterPage
MP = CType(Me.Master, MyMasterPage)
'The above 3 lines can alternatively be simplified to one:
To pass data from the master page to the page, the master page should raise an event to the page:
Public Event MasterPageButtonClicked()
Then the event can be raised to the page with a single line of code:
The page can handle the event just as if it were coming from a user control:
Private WithEvents _MyMasterPage As MyMasterPage
Private Sub MyMasterPage_ButtonClicked() _
Response.Write("Master page raised button click event.")
The only difference is that you need to assign the master page reference to the _MyMasterPage variable because ASP.NET (Beta 2) doesn’t do this for you:
MyMasterPage = CType(Me.Master, MyMasterPage)
That line of code could go in the Page_Load event — or nearly anywhere else that’s convenient.
Q7: How do I store global variables?
A7: Any good developer will tell you that global variables should be used sparingly. Even so, sometimes they are the most efficient way to get data everywhere it is needed. There are a few ways to store variable values globally in ASP.NET. The most common approaches involve use of the Application, Cache, and Session objects.
The Application object has been available since the inception of ASP, and its sturdy foundations are as reliable now as they were back then. The Application object stores data that is meant to be shared across all user sessions — so don’t put data in it that applies only to a particular user. One notable syntax quirk is the need to lock the application item before setting it. This prevents more than one page request from writing to the same item at the same time. Don’t forget to unlock the item again after you’ve set it:
'Page1.aspx places the data in Application State
Application("MyValue") = Textbox1.Text
'Page2.aspx retrieves the value from Application State
MyString = Application("MyValue").ToString
The similar (but more modern) Cache object has a simplified syntax that negates the need for manually locking and unlocking. Notice how similar the syntax is compared to the ViewState approach mentioned earlier:
'Page1.aspx Caches the value
Cache("MyValue") = Textbox1.Text
'Page2.aspx retrieves the value from the Cache
MyString = Cache("MyValue").ToString
Like the Application object, the Cache object stores data that is meant to be shared across all user sessions — so don’t put data in it that applies only to a particular user. However, the Cache object has richer functionality than the Application object. The Cache object can automatically expire cached content after specified time periods or once memory consumption has reached a peak. Cache items can also be set to expire whenever a given file changes or when a related Cache item changes. Cache values can be prioritized and automatically refreshed.
The Session object has been around since the early days of ASP. This classic and reliable technique is great for storing a user’s data during the length of their visit to your Web site:
'Page1.aspx stores the user’s name in Session state
Session("UserName") = txtName.Text
'Page2.aspx retrieves the user’s name from Session state
MyString = Session("UserName").ToString
ASP.NET tracks each user’s session, helping to ensure that one user’s data is never displayed to another user. By default, each session value is stored in server memory. If you multiply each session variable times the number of active users in your Web site you might realize that memory usage can add up very quickly. For this reason, Web applications that need to be highly scalable tend not to use session variables much, if at all. For smaller applications, the convenience of Session variables is simply irresistible.
What if you want to store variables across a user’s entire visit but for scalability reasons you don’t want to use Session variables? There’s really no simple answer, but the most obvious fallbacks are cookies and databases. Cookies are tidbits of data stored in the user’s browser; therefore, they don’t really use any server memory. However, cookies have gotten a bad rap over the years, so many users have them turned off. For this reason I recommend that you don’t rely on them. Another technique is to store the data in a back-end database and retrieve required data upon each page request. Although this conserves the Web server’s memory, it increases network and database traffic. A more complex technique is to create your own custom business objects that cache the data in ways that are efficient for your specific application.
Session state can be configured to be automatically stored in a SQL Server database, or it can be configured to be stored centrally in a state server within a server farm.
By default, a user’s session ends 20 minutes after their last page request and their data goes out of scope, freeing it from memory.
Q8: How do I store a value between PostBacks?
A8: You might have noticed that variables’ values you’ve carefully set in a page’s code-behind are wiped out when the page posts back to itself. Although this can be annoying and confusing to developers accustomed to Windows application development, it can be easily solved with a couple lines of code. Simply store the variable’s value in ViewState before PostBack, and it will be waiting there for you to retrieve after the PostBack:
'Store the value in ViewState before PostBack
ViewState("MyVariable") = MyString
'Retrieve the value from ViewState after PostBack
MyString = ViewState("MyVariable").ToString
You might be interested to know that ASP.NET stores this (and all other ViewState values) in an encoded hidden text element within the page’s form. Because this data is transferred between the client and server between each PostBack, you shouldn’t fill it with any more data than is necessary. Storing a few simple values won’t be a problem, but storing large DataSets and large structures tends to be more problematic from a performance perspective.
Q9: How do I loop through all the controls in a form?
A9: There are a variety of reasons a person may want to loop through the controls on a Form; perhaps to set a common color or to validate custom business rules. This kind of thing is not hard to do, but the logic is not entirely intuitive unless you know a few details.
You might already know that every Form has a Controls collection. From that, you might assume that you can simply loop through this collection to do what you need to all the controls in your form. You’d be wrong. A form is a complex tree of controls, and many controls can contain collections of controls themselves, such as a Panel and a Table. In fact, a form itself is nothing more than a fancy Control. (It inherits from, and extends the Control class.)
Since each tree branch can itself have N child branches, the only efficient solution is recursion. A recursive function is a function that calls itself as many times as necessary to work through any kind of hierarchical structure.
The following function uses recursion to loop through all the controls in a Form and sets the BackColor of all TextBoxes to the specified value. The function works with both Web Forms and Windows Forms.
private void SetTextBoxBackColor(Control Page, Color clr)
foreach (Control ctrl in Page.Controls)
if (ctrl is TextBox)
((TextBox)(ctrl)).BackColor = clr;
if (ctrl.Controls.Count > 0)
Private Sub SetTextBoxBackColor(ByVal Page As Control, _
ByVal clr As Color)
For Each ctrl As Control In Page.Controls
If TypeOf ctrl Is TextBox Then
CType(ctrl, TextBox).BackColor = clr
If ctrl.Controls.Count > 0 Then
Figure 1: This code loops recursively through all the controls in Form to set the backcolor of all the TextBoxes to a common color.
The function in Figure 1 can be called from pretty much anywhere in your code behind file (or Windows Form class) with a simple line such as this:
SetTextBoxBackColor(Me, Color.Red) 'VB.NET
- or -
SetTextBoxBackColor(this, Color.Red); //C#
The SetTextBoxBackColor function accepts the Form (or any other container control) as a parameter, along with the color that will be applied to the background of each TextBox within. The ForEach loop iterates through each control in the collection. If the Control is a TextBox, it applies the BackColor. If the control contains other controls, the function calls itself recursively to loop through each of those controls, and so on.
You can take these same principals and modify them in many ways as a potential solution for virtually anything you’d want to do to all your controls or to a certain kind of control. You now have the secrets you need to tinker with an entire control tree using recursion.
Q10: How do I store sensitive data securely?
A10: Here's a simple way you can make your apps appreciably more secure. Simply add the following VB .NET module to your project and call the HashData function to hash any sensitive data so it is secure from prying eyes:
Public Function HashData(ByVal s As String) As String
'Convert the string to a byte array
Dim bytDataToHash As Byte() = _
'Compute the MD5 hash algorithm
Dim bytHashValue As Byte() = _
Once your string parameter is hashed, it's computationally infeasible to determine the plain-text version. It cannot be decrypted.
Of course, this works better for some kinds of data than others. It works especially well for storing passwords in databases. When a new user signs up, simply hash his or her password and store the hashed value in the database. When the user logs in next time, hash the password and compare it to the hashed value you stored in the database. If the hashes match, admit the user.
Note, however, that if your user forgets the password, even you will not be able to decipher it. Most companies deal with this situation by auto-generating a new password and sending it to the user's registered e-mail address, or by implementing a system such as password hints or secret question/answer pairs.
If you absolutely need to be able to decrypt the data then hashing won't work. In this case you'll need to to use another encryption technique. A couple such techniques (both highly respected for their security) are Triple DES and Rijndael.
Q11: Why don't any controls show up on my page at run time?
A11: A problem people often come across when setting up a machine for ASP.NET is that the controls don't show up on the page at run time. A common symptom is that Label values show up on the page, but other controls, such as Buttons and TextBoxes, do not. Most of the time the problem is that your IIS mappings aren't set. One way this can happen is by installing IIS after the .NET Framework has been installed. Luckily, this situation is easily remedied. To repair the mappings, simply run "aspnet_regiis.exe" with the "-i" command line parameter. This program can be found within the Windows directory under the Microsoft.NET\Framework\version folder. In other words, for a .NET 1.0 Web application, you'd likely need to run this from the command prompt:
For a .NET 1.1 Web application, the default path is:
For a .NET 2.0 Web application, the default path is:
Q12: What is a Server Control?
A12: In short, a server control is any control that has the runat="server" attribute in the definition. The job of such a component is to render HTML to the output stream of a Web page. All server controls inherit directly or indirectly from System.Web.UI.Control. All the standard controls in the Web Forms tab of your Visual Studio.NET toolbox are server controls. This means that you can interact with them from the server-side code in the code-behind file of the page, manipulate properties of the control from code, call methods of the control, and respond to server-side events raised by the control.
A control dragged onto a form from the HTML tab of the Visual Studio.NET toolbox is not a server control by default, but can easily be turned it into one by right clicking on the control and selecting Run As Server Control. This action simply adds the runat="server" attribute to the control. Placing an HTML control on a page without the runat="server" attribute would render the control on the page at run time just the same as any control, but it could not be directly manipulated via server-side code. Performance benefits will be gained from not using a server control when a control doesn't need to be manipulated from server-side code, because that's one less control the server needs to instantiate.
Q13: What's the difference between HTML controls and Web controls?
A13: In the Visual Studio.NET toolbox there is a tab for HTML controls, and another tab for Web controls. Many of the controls found in the HTML tab have a similar, roughly equivalent, control in the Web controls tab. When an HTML control is dragged onto a Web form, it's represented in your ASPX with code such as this:
A Web control will look more like this:
<asp:Image id="Image1" runat="server" ImageUrl="MyImage.jpg" />
HTML controls are quick and small and require little memory. Conversely, Web controls provide more advanced functionality than HTML controls.
You'll find the HTML controls to be intuitive and familiar if you're an old-school HTML Web developer. However, you're more likely to feel at home with the extra features that Web controls provide if you have more of a Windows/ActiveX development background. Why have two sets of similar controls? Microsoft didn't want to abandon developers with either background, so it made a set of controls for each. Freedom of choice is a wonderful thing.
Be aware that HTML controls were not designed to be especially extensible. Therefore, when making your own controls, you should instead inherit from WebControl or Control.
Q14: What's the difference between User Controls and Custom Controls?
A14: There are two main categories of creatable Web controls. User controls are more simple to create, but custom controls are more simple to use. The extra effort that goes into creating custom controls pays off for the developer using the control at design time.
User controls are the natural evolution of include files, which are well known by old school ASP developers. If you're still using server-side include files in ASP.NET, it's time to leave them behind and dig into user controls, which are better in virtually every way. User controls are little more than a snippet of a Web page that can be dragged and dropped anywhere to duplicate bits of user interface and the associated functionality. (In fact, it's not difficult to convert an entire Web page into a user control.) They are object-oriented, so public properties can be added, as well as methods and events, to allow them to easily communicate with the page and other controls on the page.
User controls are saved with an ASCX file extension. Although they can be easily reused on any of the pages within the project in which they were created, there is no good way to reuse them in a different project. Another downside to user controls is that they only appear on the page at run time; at design time they appear on the page as an ugly gray box, making it difficult to envision how they'll appear to your users.
Figure 1 shows the HTML source code for a basic sidebar menu user control. A standard control like this is a navigational staple needed by virtually every page in a Web site. It would be wasteful to manually re-create such a structure over and over again for each page. Instead, simply drag this control from the Visual Studio.NET solution explorer window onto each page as needed. This example does not include any code-behind logic, but any user control can have a code-behind file of its own to contain any necessary server-side code. Figure 2 shows how the control looks on a Web page that includes a CSS style sheet to enhance the appearance.
<TABLE id="Table1" style="WIDTH: 136px; HEIGHT: 99px"
cellSpacing="1" cellPadding="1" width="136" border="1">
<asp:HyperLink id="HyperLink1" runat="server" NavigateUrl="Home.aspx">Home</asp:HyperLink>
<asp:HyperLink id="HyperLink2" runat="server" NavigateUrl="Products.aspx">Products</asp:HyperLink>
<asp:HyperLink id="HyperLink3" runat="server" NavigateUrl="Services.aspx">Services</asp:HyperLink>
<asp:HyperLink id="HyperLink4" runat="server" NavigateUrl="Contact.aspx">Contact Us</asp:HyperLink>
Figure 1: (Above) A basic reusable side menu user control can be as simple as this. This control was created completely by dragging and dropping controls from the Visual Studio.NET toolbar onto an .ASCX user control page.
Figure 2: (Above) User controls are great for defining the layout for standard sections of Web pages. When combined with style sheets, they can morph to match the look and feel of any Web page on which they are hosted.
Custom controls can do everything that user controls can do - and much more. The biggest drawback is that they are more challenging and complex to create. Drag and drop is not supported for the creation of these controls. Therefore, all the HTML they output must be generated via code. Pretty much all the articles & controls on this web site are examples of custom controls. In addition to run-time functionality without limits, custom controls support rich design-time functionality. They can appear on a page at design time the same way they'll appear at run time, or differently if preferred. They can be adjusted to change how they'll appear in the toolbox, and how the properties will appear in the properties window. If the properties window doesn't support the desired functionality, it can be extended with custom popup dialog boxes and other UI tricks. Custom controls are easily distributed and can be enhanced with help documentation and licensing functionality, allowing them to be sold to other developers.
Q15: How do I save the state of my controls between postbacks?
A15: In many cases no action is required to save the state of controls between postbacks. When encapsulating existing controls within a user or custom control, they'll often save their own state just as they do when using them directly on Web pages. However, there are circumstances that will require custom data to be saved between postbacks. Imagine a simple control that contains only a LinkButton and a Label control. To save the number of times a user has clicked on the LinkButton and display that count in the Label control, a block of VB.NET code like this can be used in the code-behind:
Private Sub LinkButton1_Click(ByVal sender As Object,
ByVal e As EventArgs) Handles LinkButton1.Click
Dim i As Integer = CInt(ViewState("ClickCount"))
i = i + 1
ViewState("ClickCount") = i
Label1.Text = "Clicks: " & i.ToString
This code saves the custom data value in ViewState, indexed under the name "ClickCount". This code sample gets any existing value out of ViewState, increments it, then puts the new value back into ViewState. Finally, the value is displayed in the Label control. Because each control is automatically given a unique naming container within ViewState, control developers don't need to worry about naming collisions between multiple instances of a control on the same page. Figure 1 illustrates the fact that each instance of a control automatically has its own unique "ClickCount" ViewState value.
Figure 1: Each instance of a control automatically gets a unique ViewState, so you needn't be concerned with giving each instance of a control a unique ViewState name.
Q16: How do I set the focus to a particular control on my page?
Perhaps it isn't known until run time which control should get the focus. In this case, code similar to the above example could be generated and output dynamically at run time via server-side code. For this, a subroutine like the one shown in Figure 1 could be used.
Dim sb As New System.Text.StringBuilder
Figure 1. This VB.NET code will set the initial focus to any control that is passed to it.
To call the method, simply execute a line of code such as this from the code-behind of a Web page:
Q17: How do I send the output of a Web control via e-mail?
A17: Assuming SMTP is configured properly on the server, the output of nearly any Web control can be captured via the output of its RenderControl method, and then sent out using the MailMessage class of the System.Web.Mail namespace. Such functionality is provided by the VB.NET method shown in Figure 2, which you can call from the code-behind class of any page.
ByVal ToEmailAddress As String)
'Get the output of the control
Dim sb As New System.text.StringBuilder
Dim sw As New IO.StringWriter(sb)
Dim tw As New HtmlTextWriter(sw)
'Send the email
Dim MailMsg As New Web.Mail.MailMessage
Dim svr As Web.Mail.SmtpMail
svr.SmtpServer = "smtp.mydomain.com"
MailMsg.To = ToEmailAddress
MailMsg.From = "email@example.com"
MailMsg.BodyFormat = Mail.MailFormat.Html
MailMsg.Subject = "Test Email"
MailMsg.Body = sb.ToString
Figure 5: This code will grab the HTML output of a control and send it to the specified e-mail address.
This code works well primarily for read-only controls, such as Labels, DataGrids, LinkButtons, etc. Editable controls such as TextBoxes don't tend to work as well because they expect to be hosted inside a form.
Of course, any network administrator will tell you that e-mail is a complex topic involving firewalls, spam filtering systems, and more. Therefore, there are plenty of ways the code in Figure 5 could fail, so (as always) you should employ error handling of one kind or another.