DropDownList in ASP.NET does not retain control state

I’m not a huge fan of ViewState because I’m obsessed when it comes to page speed and ViewState just seems to cluster my webpage with sometimes unwanted info. So I tend to switch viewstate off and guess what, dropdownlist does not retain the selection the user has made before postback!

This, to me, is a serious design flaw within the Microsoft .Net framework because a DropDownList should retain its control state just like a checkbox and not rely on viewstate information being available. It happens that textboxes are able to save their control state even with ViewState off but not DropDownList. Why is that, I wonder?

Anyway, the workaround for this problem if you have turned off ViewState in your application is to request the selection the user has made from the dropdownlist through the request.form variables by passing in the ID of the select box as follows:


public static string GetSelectedValueFromDropDown(System.Web.UI.WebControls.DropDownList listBox)
 {
 return HttpContext.Current.Request[listBox.UniqueID];
 }

Hopefully Microsoft will fix that in a future release 🙂

Ajax file upload with JQuery

Working with AJAX makes websites more interactive as no postback is required but if you need to perform file uploads, then this can become very tricky. At the moment, the XMLHttpRequest object does not support sending files to the server. So real ajax file upload is not possible but there are a few hacks that gives the impression that file upload is being handled by the ajax framework. The most common way of faking ajax file upload is through the use of a hidden iframe. What happens is that the hidden iframe submits the multipart/form-data and the server sends the response back to the iframe. However it is easier to use a plugin of some sort instead of going into the intracacies of building something that someone else has already done.

Using ASP.NET HttpHandler for file uploads

Before I started doing ajax file upload, I used the ajax method of the JQuery’s library to fire off a request to an httphandler in asp.net but the context.Request.Files would always be zero. This meant that no files were being sent to the server and it gave me an index out of bound error. This is how I learnt that ajax does not currently handle files and I began to explore new ways to upload files through javascript.

There are many plugins available but I wanted something that most users will already have on their system. Most people already have javascript installed on their machines and working with that was a better option than having flash based upload plugins. My second requirement was that I needed something very lightweight that would only do the functionality that I need and not offer many more that I would not really use. So I ended up checking a plugin which is called Ajax File Upload.

AjaxFileUpload.js

This ajax file upload script (http://www.phpletter.com/Demo/AjaxFileUpload-Demo/) does exactly what I need but the lack of documentation has made me spent hours trying to figure out how it works. The first problem that I had with it was that my web app was going to send the uploaded file to an http handler which would send back json output confirming whether the upload was successful or not.


$("#btnUpload").click(function () {
 //var filename = $("#myfile").val();
 $.ajaxFileUpload({
 url: "/PostFileHandler.ashx",
 secureuri: false,
 fileElementId: 'myfile',
 dataType: 'json',
 success: function (data, status) {
 $("#result").html(data.msg);
 },
 error: function (data, status, e) {
 alert("My Custom Error: " + e);
 }
 });
 });

As you can see, I’m already telling the ajax file upload plugin that I’m expecting json output and in my http handler, I was outputting json by having context.Response.ContentType = “application/json” but that did not work and that’s how I spent literally hours trying to fix the problem. Everytime I tried uploading something, a dialog would pop up asking me to download a file from my http handler and when I inspected the content of that file, it had the json output in it. So the plugin was not handling the output correctly. The solution was to change the output response in the handler to context.Response.ContentType = “text/html” which made everything worked but is undoubtedly wrong.

The second problem is that if you try to upload anything greater than 4Mb, you will get the error XML tag name mismatch (expected hr) because the plugin can’t handle it. The solution is to check beforehand the size of the file the user is trying to upload but that ain’t possible with javascript/jquery and you’ll have to use something like flash to get this information.

I’m not sure whether I’ll be sticking to this ajax file upload pluging because of the security issue it poses. Ideally, you don’t want the file to be sent to your server if the size is too big and the reason for that is because it will eat your bandwidth, memory and will be stored in a temp folder on your drive (although it would be deleted afterwards). With flash based uploads, you can restrict what is sent to your server beforehand and prevent denial of service attacks (DoS) by preventing the workload from reaching your server scripts.

Dynamic controls, viewstate and postback

When using dynamic controls, many people will encounter all sorts of different problems that can take hours or days to solve. It is therefore essential to understand how asp.net handles events, postback and viewstate.

Dynamic control disappears on postback

If you have a user control which contains a text box, a literal control and a submit and you add the control programmatically, chances are that when the user control’s submit button is clicked, the user control will disappear instead of showing the value of the textbox in the literal. This happens because the user control (.ascx) is hosted by the page (.aspx) and the parent page does know of its existence unless you have used the declarative syntax in your markup. Here’s the html for  a page called Slave.aspx


<%@ Page Language="C#" AutoEventWireup="true" MasterPageFile="~/MasterPage.master" EnableViewState="true" CodeFile="Slave.aspx.cs" Inherits="Slave" %>
<%@ Register Src="~/FirstControl.ascx" TagName="FirstControl" TagPrefix="gis" %>
<%@ Reference Control="~/WebUserControl.ascx" %>
<asp:Content ID="content1" ContentPlaceHolderID="ContentPlaceHolder1" runat="server">
<hr />
<h2>slave page</h2>
For the slave...
<gis:FirstControl ID="FirstControl" runat="server" />
<asp:HiddenField ID="hf" Value="0" runat="server" />
<asp:PlaceHolder ID="ControlHolder" runat="server" />
<hr />
</asp:Content>

<gis:FirstControl ID=”FirstControl” runat=”server” /> is the declarative syntax here but that’s not dynamic loading. FirstControl has a button and a checkbox and when the checkbox is checked and the submit button clicked, it will load dynamically another user control, in this case, WebUserControl.ascx. Below is the markup for FirstControl.ascx:


<%@ Control Language="C#" AutoEventWireup="true" CodeFile="FirstControl.ascx.cs" Inherits="FirstControl" %>
<<%@ Reference Control="~/WebUserControl.ascx" %>
<hr />
<h3>First Control</h3>
<asp:CheckBox ID="chkMaster" runat="server" />&nbsp;&nbsp;<asp:Button ID="btnFirstSubmit" Text="First Submit" OnClick="btnFirstSubmit_Click" runat="server" />
<hr />

And here’s the code behind for FirstControl.ascx:


protected void btnFirstSubmit_Click(object sender, EventArgs e)
 {
 if (chkMaster.Checked)
 {
 // show the other control
 WebUserControl wuc = (WebUserControl)LoadControl(typeof(ASP.gis), null);
 PlaceHolder holder = (PlaceHolder)FindControlRecursive(Page, "ControlHolder");
 holder.Controls.Add(wuc);
 }
 }

When the submit button on the FirstControl.ascx (provided the checkbox is checked), the user control will dynamically load the WebUserControl.ascx which contains a textbox, a submit button and a literal to print out the name in th e textbox. The WebUserControl is loaded properly but when its submit button is clicked, it will disappear on postback.

Solution: The reason for this is that the parent page (Slave.aspx) does not know of its existence. Therefore we need to make the page aware of it. When you load a dynamic control, you need to keep track of it, whether through ViewState or Hidden Form Field. I’ve used a hidden form field in this instance and here’s the code in the FirstControl.ascx file:


protected void btnFirstSubmit_Click(object sender, EventArgs e)
 {
 if (chkMaster.Checked)
 {
 // show the other control
 WebUserControl wuc = (WebUserControl)LoadControl("~/WebUserControl.ascx");
 wuc.ID = "wuc";
 PlaceHolder holder = (PlaceHolder)FindControlRecursive(Page, "ControlHolder");
 holder.Controls.Add(wuc);

 HiddenField hf = (HiddenField)FindControlRecursive(Page, "hf");
 hf.Value = "1";
 }
 }

Important thing to note here is that we need to make sure that we assign a unique ID to the dynamic control. And here’s the code behind for Slave.aspx:


protected void Page_Load(object sender, EventArgs e)
 {
 if (hf.Value == "1")
 {
 WebUserControl wuc = (WebUserControl)LoadControl("~/WebUserControl.ascx");
 wuc.ID = "wuc";
 ControlHolder.Controls.Add(wuc);
 }
 }

So to prevent the dynamic control from disappearing, you need to keep track of whether you’ve added it or not and load it if you have.

Loading a dynamic user control without specifying the path

If we want to load our control when some action is performed and not have it sit there and go through the asp.net life cycle for no reason, then we need to add a reference to the user control in the parent page. Now LoadControl is the method we’re after and it has 2 overloads. The first one requires a path to the user control and that works flawlessly. The second one takes a strong type and a parameterised object.

Casting the control to the right type

If you have properties on the control, you will need to cast it to the right type. Otherwise your properties won’t be available to you. The following code does not give me the intellisense for the public properties on WebUserControl because it’s been casted as a generic UserControl.

UserControl myUserControl = (UserControl)LoadControl(“~/WebUserControl.ascx”);

To access these public properties, you will need the following code:

WebUserControl myUserControl = (WebUserControl)LoadControl(“~/WebUserControl.ascx”);

Remember that you need to reference the WebUserControl in the parent page, otherwise you’ll get a compile time error:

<%@ Reference Control=”~/WebUserControl.ascx” %>

Dynamically loading the control by type

If you want to do the following, you will not see your control loaded:

WebUserControl myUserControl = (WebUserControl)LoadControl(typeof(WebUserControl), null);

This is because when you use the path to the user control, asp.net will fire off all the events that the control has missed until it catches with the current event. So if you’re adding a user control in the button click event, the init and load event have already passed, so the newly added control need to catch with the events until it is in sync. The workaround is to strongly type the user control and you do this by adding the ClassName attribute to the control’s markup as follows:


<%@ Control Language="C#" AutoEventWireup="true" ClassName="gis" CodeFile="WebUserControl.ascx.cs" Inherits="WebUserControl" %>
<hr />
<h3>Web User Control</h3>
<asp:Literal ID="litSomething" runat="server" /><br />
<asp:Literal ID="litText" runat="server" /><br />
<asp:TextBox ID="txtName" runat="server" />
<asp:Button ID="btnSubmit" Text="Submit from user control" runat="server" OnClick="btnSubmit_Click" />
<hr />

Notice the ClassName=”gis” in the code above. Now you would assume that you can do something like this:

WebUserControl myUserControl = (WebUserControl)LoadControl(typeof(gis), null);

But that won’t work because the ClassName “gis” cannot be found as it resides in the ASP namespace. Here’s how to do it properly:

WebUserControl myUserControl = (WebUserControl)LoadControl(typeof(ASP.gis), null);

You will get “System.MissingMethodException: Constructor on type ‘ASP.gis’ not found.” if you try to pass in parameters though:

WebUserControl wuc = (WebUserControl)LoadControl(typeof(ASP.gis), new object[] { “hey you” });

For some reason asp.net is unable to get the overloaded constructor for the user control even though it’s private. From what I’ve read, only the parameterless constructor is called.

Where to add dynamic controls? Page_Init, Page_Load?

You can add them whenever you want but if you don’t add it in Page_Init, the control will not be able to participate in ViewState as the loading of view state comes before page load.

Events available to User Control

You can use Init, Load and PreRender.

Application pool recycling – The not so obvious reason

If your application pool is recycling for no reason, it could be a problem for your visitors because the loading time of your webpages will be increased. Nobody likes slow websites and this can discourage people from coming to your site and this is why you need to fix the problem as soon as possible.

On one of my sites hosted on a Windows 2008 R2 server, I’ve got a dedicated app pool for a website. However I’ve noticed that the application was recycling quite often and this impacted the load time of the website. When any page from the website is loaded for the first time, the web app does a number of things including caching of certain data and loading some necessary classes for it to function properly. This needs to be done only once and any further HTTP requests should be fast from then onwards.

Drilling down into the problem, I found that the application pool has a default timeout setting of 20 mins. This means that if no requests are made within 20 mins, the app pool will be shut down. This is only good if you have a lot of app pools running and running low on memory. However for a low traffic site where you don’t necessarily have visitors within every 20 min interval, your app pool will recycle and the next visitor that you get will see the page load really slowly because startup methods are being called by your web app. To prevent this from happening, you need to set the Idle Time-out (minutes) property in the app pool to zero (0).

You should also set the Regular Time Interval (minutes) to 0 to avoid your application from recycling at specific period of times. It’s also a good idea to enable Event logging for when your application pool is being recycled so that you can easily know if there’s any problem with your website.

Configuring IIS 7.5 logging in Windows 2008

Raw log file for your website gives you the facility to see who’s been accessing your webpages with information on the client IP address, the time the request was made, the referrer, time taken to process the request and so much more. That’s why it is essential to have logging enabled for your site.

In Windows 2008, you can choose among different log file formats (IIS, NCSA, W3c and Custom). If you go to the IIS Management Console, you will see “Logging” under IIS features and when you double click on it, you will have a couple of options to choose from. IIS and NCSA do not allow you to change what is being logged but with the other two formats you can. W3C format is the preferred format for many people. With that format chosen for your log files, you can select which fields you want to get logged for each HTTP request by clicking on the “Select Fields” button next to the file Format. The log files are saved in the following directory by default:

C:\inetpub\logs\LogFiles

You can also choose how often a new log file is created by selecting the best option for Log File Rollover. For high traffic sites, you can have it daily or hourly but if you have a moderate traffic, going with the monthly log is the way forward. You should also check the option for “Use local time for file naming and rollover” to make it easier for you to distinguish between the various log files created.

Custom IIS logging

If you want to re-arrange the fields in your log file, you will have to go with Custom logging. For example, if you wanted the client IP address to come before the date and time of the http request, then only custom logging will allow you to do that. You cannot also change the name of the log file name, it is in the format of u_exYYMMDD.

Although custom logging for IIS gives you a lot of flexibility in terms of what gets logged and many more, there’s a major drawback to that approach and that is performance.  The IIS worker process handles custom logging and the HTTP.sys kernel-mode cache is disabled for IIS which degrades performance (see this link for more information).

Combining ASP.NET website into a single assembly

With a Web Application Project (WAP), you get a single assembly when you build your project. However with an ASP.NET Website, the output is spread among many dll files. The closest you will get is having all your classes in the AppCode folder in one assembly and the other classes in separate assemblies. Depending how many files you’ve got in your website, this can amount to a lot and I think having one single assembly is better for a number of reasons, the primary one being deployment onto a production server.

Instead of converting my ASP.NET website to a Web Application Project, I decided to use the aspnet_compiler.exe to build the website output and use aspnet_merge to merge the assemblies together. This means that everything for the website will be in one single assembly but note that other assemblies that you’re referring to will stay the same such as log4net, nhibernate etc.

You will need to go to Visual Studio Command Prompt to issue the following commands:

aspnet_compiler -v TestWeb -p “C:\Projects\TestWeb” “C:\Projects\TestWebCompiled”

aspnet_merge “C:\Projects\TestWebCompiled” -o Gis

This will first compile your website files and then merge the assemblies. You may encounter the following error when you use the aspnet_merge tool though:

aspnet_merge: error occurred: An error occurred when merging assemblies: ILMerge.Merge: ERROR!!: Duplicate type ‘FooterControl’ found in assembly ‘App_Web_xd23ggdz’.

In my case, it was because I had two web controls with the same name. I had to delete one of them but you can just rename yours and it should work fine afterwards.

There’s a great video at http://www.asp.net/general/videos/how-do-i-use-the-aspnet_mergeexe-utility-to-merge-assemblies showing you how to use the both the asp.net compiler and the asp.net merge tool.

The only thing I need to figure out now is how to remove certain files/folders from being compiled.

Designing an email notification system in asp.net

I’m currently working on a Question/Answer website and users are notified of new answers to a question they’ve subscribed. Similarly emails are sent out when there are new comments to an article for which you’ve subscribed. The other types of emailing present in the system is when a user registers for the first time and an activation email is sent out to them or when they send a request to reset their password through a “Forgotten Password” link or when the administrator wants to send out an email to every member (kind of a broadcast or newsletter thing).

To me, the registration and password reset email need to be sent straight away for a good user experience. So this can be done synchronously as soon as the registration form is completed or the password reset button is clicked. However when a user adds a new answer/comment, you cannot have the same worker process handle the notification, that is, send emails to subscribed users to tell them there’s a new answer/comment. This will be bad experience for the user who submitted the answer/comment because the request will be blocked until the emailing is done and if you have to notify 100 users, this can take a really long time.

There are a few things which can be done though such as getting the email sending to be done asynchronously, relaying the emails from IIS SMTP to the mail server or using MSMQ (Microsft Messaging Queue) to queue up the emails.

Sending emails asynchronously in C#

With .net 4.o framework, it has become even more easy to send emails asynchronously. You will need to have the Async property to true in the Page directive and use SendAsync instead of Send on the smtp object (you need to hook up the delegates as well but I’m not going into that for the time being).

What happens then is that the worker process which served the http request will be returned to the application pool once the async method is hit and another thread will be processing the asynchronously event. Once it is complete, the response is then sent to the user. The advantage of doing this is that you free up worker processes to serve other http requests instead of starving the thread pool. When your async job is finished, another worker process will be grabbed to finish off the request which had the async method.

The main disadvantage of the async page is that the user who initiated the request will have to wait until the async event completes before he sees any response. If you’re doing heavy work (as in emailing 100 people), then the user can get really frustrated and leave and that’s not very good for user experience. Http requests need to be quick and process intensive tasks need to be done by a background thread.

What we really need is a fire and forget method and that can be achieved with a background thread (see this link http://www.jdconley.com/blog/archive/2009/01/14/fire-and-forget-email-webservices-and-more-in-asp.net.aspx). Context switching is an expensive task though and the problem with this approach is that the thread will go into unmanaged code, so you will need to be careful what it’s doing.

IIS SMTP relay to remote mail server

Using the System.Net.Mail library is great but communicating through the SMTP protocol is an expensive task. First a connection has to be established with the remote mail server and then the destination email address needs to be checked and if it exists, then the delivery of the email can be done. Now imagine doing that for a large amount of emails. It will take a really long time. Therefore it is much easier to use PickupDirectoryFromIis or SpecifiedPickupDirectory for the SmtpDeliveryMethod.

If you use Network delivery, then the email will be sent through the smtp protocol but if you use PickupDirectoryFromIis, then the email is saved as a file in the \inetpub\mailroot\pickup folder with the .eml extension. Email files are easier to process and since you’re not connecting to the remote mail server and simply saving the emails as files, you will find it much quicker to process.

Once in the pickup folder though, you will need a certain process to deliver the emails. You can get IIS Smtp to deliver the emails directly or have it relay to your remote mail server.  The latter is the better approach since your mail server can do the spam checking and authentication and will not be blacklisted by other email servers.

IIS SMTP on Windows 7 and Windows 2008

It is important to note that Windows 7 does not come with a version of the IIS SMTP server. With Windows 2008 though, you can get the SMTP installed by going into Features and adding it but it runs in IIS6 mode and not IIS7 or IIS7.5. Therefore you will need to have IIS6 running on your server even if you use IIS7/7.5 for your websites.

The IIS SMTP service should be used as an email relay in the sense that email dropped in the pickup folder are forwarded to the actual email server (smtp) for processing.

Using Microsoft Messaging Queue (MSMQ) to notify users through email

A queuing system is a good way to send email as MSMQ can help with that. Basically, instead of sending the emails directly to the mail server through the network, you save the messages in a queue with MSMQ. They will stay in the folder they’re saved and another process (eg a windows service) can read that folder and process the emails (deliver them). The main advantage to this is that you do not overwork your CPU as in 100% at peak times and 0% during non-peak hours but rather use the CPU in a more efficient manner because the work is queued up and can be processed when resources becomes available.

The following link is a good start (http://dotnetslackers.com/articles/aspnet/Sending-email-from-ASP-NET-MVC-through-MVC-and-MSMQ-Part2.aspx).

Conclusion

The mechanism behind sending mass emails to users who have subscribed to a particular service is very important because you do not want your users to wait a long time because there’s a slow process which has been triggered by some action they’ve taken on your website. For the user, things must be quick and it is therefore important to have background tasks run on a different thread than the calling thread.

Using multiple or nested forms in ASP.NET

While the convenience of having just one form in asp.net is great, there are times when you actually need to have multiple forms such as when you want to give a search functionality on your website or have a form post to another page without getting into the intricacies of PreviousPage and the like.

It is must be noted that asp.net allow just 1 form with the runat attribute which is visible at any given time. This means two things – first you can have multiple forms on the same webpage provided only one of them has the runat attribute or you can have multiple forms with the runat attribute provided only of them is visible at any given time (the others must be invisible so that asp.net renders just one form tag for you).

Nested forms in asp.net

So now that you know that you can have many forms in your asp.net page and have decided to have a search facility at the top and maybe another form to post comments to a different page, it is important to remember that the forms cannot be nested, otherwise it wouldn’t work as expected. So make sure that you’re closing your form tag before opening another one!

Another thing worth mentioning is that when you’re posting to a different page with a simple html form, you need to provide both the ID and Name attribute of the element you wish to retrieve the value of from the other side. So if on Page A you have a textarea, don’t forget the name attribute because this is necessary for Request.Form to retrieve the value of your textarea.

Preserving the case of table names in MySql on Windows

Windows is case insensitive, so table “test” and “Test” refers to the same table. However if you want to preserve the case sensitivity of the your table names on a Windows machine, you should set the option lower_case_table_names to 2 in the MySql configuration file. You can check the value by running the following SQL command:

SHOW VARIABLES;

Scroll down to lower_case_table_names and the value will most likely be set to 1. Now to change that value, you will either have to modify my.ini or my.cfg file found in your installation of MySql (C:\Program Files\MySql\MySql Server 5.1 0r C:\Program Files (x86)\MySql\MySql Server 5.1). Try searching for lower_case_table_names and change the value to 2 or just append the following in the my.ini file:

lower_case_table_names = 2;

Now you will need to restart the MySql service for the changes to take effect. Note that tables which have previously been created won’t be affected by this change. Only new tables will preserve their case sensitivity rather than having their case lowered.

After making the change, if you still find that some tables are not preserving their case (same problem that happened to me), then you will need to do rename the table to something else and then back to its original name. Say you created a table called ‘Article’ and you find that it’s showing as ‘article’, then do the following:

RENAME TABLE `Article` to `Article2`;
RENAME TABLE `Article2` to `Article`;

This will solve the problem.

Inserting content into a webpage from iframe code behind in JQuery

Here’s the situation: A user clicks a button on a webpage and an iframe pops up (facebox which similar to lightbox). Now I want to inject some html from the asp.net code behind of the iframe into the parent window. I’m using JQuery to achieve this and this simple line of code does the trick:


parent.$("#MessageDiv").append("hello world");

That works fine except when you’re trying to insert a string which contains line breaks. I’m not talking about html line breaks here but windows line breaks as in new line and carriage return (\n\r). The problem is that because the string will span on several lines, the expression will be unterminated. Have a look at the following to understand what I’m trying to say more clearly:

hello world

how are you?

The above text is represent as “hello world\n\rhow are you?”. When that is written in a javascript script, it will become like this:

document.write(“hello world

how are you?);

To make this work, you need to remove the line breaks as follows:


string myContent = "hello world\n\rhow are you?";

myContent.Replace("\n", "").Replace("\r", "");

This will keep all your content on one line and make the javascript work as intended.