.Net ramblings
# Monday, 24 April 2006
HowTo: cancel an onbeforeunload event
if you're like me and use the onbeforeunload event in a web page to display a reminder to a user who might unintentially lose work by browsing away from the page, then you might be trying to find a way to cancel the event in the case where the user clicks the save button (they obviously don't need reminding now that they have clicked the button...)

on the internet you will find many people suggesting you use something like
window.onbeforeunload = null
but this does not work for me in IE6.  reading up in the MSDN docs for the event object i found a reference to the event.cancelBubble property, which i thought was the solution. but thanks to Orso who pointed out that setting "event.cancelBubble=true" is useless, the way to get rid of the confirm prompt is to exclude the return statement altogether, i chose to use a boolean variable as a flag to decide whether to return something or not. in the example below i add the javascript code programattically in the code behind:

	Page.ClientScript.RegisterStartupScript(typeof(String), "ConfirmClose", @"
window.onbeforeunload = confirmExit;
function confirmExit()
if(postback == false)
return ""Please don't leave this page without clicking the 'Save Changes' or 'Discard Changes' buttons."";

then my save button contains the following aspx markup:
    OnClientClick="postback=true;return true;"
this sets the 'postback' variable to true, which gets picked up in the confirmExit() function, having the effect of cancelling the event. 

hope you find this useful.  it is tested and works in IE6 and FF

Monday, 24 April 2006 17:10:13 (GMT Daylight Time, UTC+01:00)  #    Comments [16]  Asp.Net

# Wednesday, 12 April 2006
FindControl() won't find the control....
my aspx page uses a master page, so all the content is inside a ContentPlaceHolder. 
aparently Page.FindControl() only works within a single container, which is really poor functionality if you ask me. 
to complicate the situation further, my aspx page has dynamic controls inside a Panel. 
in order to access the controls of my user control, from the code-behind of the page, i first had to find the panel and then the user control, and then i could finally use that to find the controls i wanted. 
note: you don't have to use the client ID of the control ...ctrl00_blah_blah_blah_YourControlName... when you use the above method, you just use the name of the control, e.g. txtFirstName. 

Wednesday, 12 April 2006 15:27:51 (GMT Daylight Time, UTC+01:00)  #    Comments [0]  Asp.Net

# Sunday, 05 March 2006
The Microsoft Origami Project and back to hand-writing
Screenshot of origami hand-held (probably)For anyone who hasn't heard the buzz about Microsoft's Origami Project, take a look at this vido file to get a glimpse of what it is probably about.  the video is a year old but i reckon it's a fairly accurate preview of the real thing.  the thing that really struck me about the video was that people were writing hand-written notes to each other, in emails, messages etc.  What a bizarre idea.  Yeah we've had PDA's without keyboards for a long time, but they only ever had a very small user base, because of the need to learn a new form of writing that the palmtop could understand. traditional touch screen hand-writing technology is woefully slow to right messages of any length on.   if the Origami device becomes mainstream, which i think it probably will, then it is quite a departure from the way we interact with computers since they were invented. 

personally i do so much typing and so little hand-writing that i tend to think about pen + paper as an old thing i left behind many years ago.  But... when you stop to think about it, emails and 'typed' communications lose a huge amount of personality compared with traditional hand-writing.  You can't identify the writer of an email based on the style of writing, like you can with a hand-written letter from someone you know well.  emails are usually so limited in expression that we have created a whole new culture of emoticons to bridge the gap, but it's hard not to come across as cheesy and immature when you write things like :-)  :O)   :^) etc...

Screenshot of origami hand-held (probably)We've all got very good at typing, because computers understand fixed characters much better than squiggles of writing.  Typed content is also more efficient in terms of storage size, and search capabilitiy.  You still can't meaningfully scan a JPEG of a hand-written letter and be sure to get all the words out of it.  But it looks like that is the way Microsoft are headed.  It is really a massive shift if this takes off, because the modern computer experience is built around typed content.  The internet would be nothing if we had to wade through volumes of illedgible hand writing before we found the information we wanted.  Obviously this is looking at the extremes, and we'll always have typed content with us, but to me it seems like this is the first mainstream introduction of mixed text content arriving on our desktops, from the pen and the keyboard. 

In the grand scheme of things, i actually think typed content will be a blip on the radar of the way we record text information.  For thousands of years we've been writing things down, and i can't think of any good idea for why that should all be thrown out the window, except technology limitations.  It looks like Microsoft are challenging those limitations.

Sunday, 05 March 2006 12:44:07 (GMT Standard Time, UTC+00:00)  #    Comments [0]  General

# Friday, 03 March 2006
Compiling Asp.Net 2.0 to a single assembly
I wanted to install my web application assembly into the GAC, but this is made more complicated by the multitude of assemblies produced by VS when i publish the web site.  On the newsgroups, i found some talk of a tool called Merge_Aspnet.exe but i couldn't find it anywhere.  Eventually i found it as a download on MSDN, it is bundled as part of the Web Deployment Projects.  You install it, and then right-click your project in VS and you should see a new menu item "Add Web Deployment Project".  I am baffled as to why they didn't just add a new project type in the list of projects under "Deployment".  There is a link to "Search online templates" so i think it should really be available there.  but it looks like MS did a hack just to add in a new item to the project context menu.  but it works... so i'll stop complaining. 

Friday, 03 March 2006 15:43:20 (GMT Standard Time, UTC+00:00)  #    Comments [0]  .Net General | Asp.Net

# Saturday, 18 February 2006
HowTo: Get Write Access to an ApplicationData folder in ASP.NET
In a web application i'm working on, i needed to get write access to a folder, and preferably not the temp folder because the data should be kept reasonably safe from being deleted accidentally.  If it was a windows-forms application this would be easy, i would just use Application.UserAppDataPath.  So i thought for asp.net, i could use Environment.SpecialFolder.ApplicationData but this maps to the folder for the current user logged on to Windows, not the process running the web site, or the authenticated web site user.  So i just skip up 2 parent directories from that, and use the current Principal.WindowsIdentity to find the actual process running ASP.NET, and then deduce the correct folder, which by default will have write permissions for Asp.Net.

Here is the code:
string Username = Path.GetFileName(System.Security.Principal.WindowsIdentity.GetCurrent().Name).Replace(" ", "");
string UserAppFolder = String.Format(@"{0}\{1}\Application Data", Directory.GetParent(Directory.GetParent(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)).FullName).FullName, Username);

By the way, the use of Path.GetFileName is entirely intentional, it solves the case where the current user is "NT Authority\Network Service" by yielding "Network Service", which is what we are interested in.  

This will hopefully come in handy for my 'zero configuration' idea for the application.  Next time you need a write folder, it may be a good idea to use this instead of making users specify write permissions for a custom folder. 

Saturday, 18 February 2006 19:11:26 (GMT Standard Time, UTC+00:00)  #    Comments [2]  Asp.Net

# Friday, 17 February 2006
FtpWebRequest with ProgressBar [C# Ftp]
Screenshot of upload operationhi,
i was delighted to see .Net 2.0 has an excellent class for working with FTP.  looking back i can't believe it wasn't part of 1.1. 

i noticed there was no built-in support for reporting the progress of an FTP operation to a user interface.  I needed this functionality in an app i'm working on so i built a class and i'm posting it here in case anyone is interested.

The class FtpProgress inherits from BackgroundWorker, so you just drag an FtpProgress component onto your form, hook up events for Completed and ProgressChanged, and your laughing.  There is a mini class called FtpSettings which stores all the connect info etc to pass in as a paramter to the RunWorkerAsync() method.

I have a variable called 'ChunkSize' which determines the size of each buffer written to the FtpWebRequest output stream.  It is set to 4k by default, and you can increase this if you want for very fast networks but i don't think it will make much difference.  I think the overhead is negligible.

Download the source code and demo application [30 k].

It only does upload, so if you want download functionality, you can do the mirror-image of the upload code, i.e. instead of writing buffers to the output stream, read it from the input stream, or however that would work :) 

here is all the code you need to start an Upload, and report progress:
private void btnUpload_Click(object sender, EventArgs e)
// create a new FtpSettings class to store all the paramaters for the FtpProgress thread
FtpSettings f = new FtpSettings();
f.Host = this.txtHost.Text;
f.Username = this.txtUsername.Text;
f.Password = this.txtPassword.Text;
f.TargetFolder = this.txtDir.Text;
f.SourceFile = this.txtUploadFile.Text;
f.Passive = this.chkPassive.Checked;
f.Port = Int32.Parse(this.txtPort.Text);

private void ftpProgress1_ProgressChanged(object sender, ProgressChangedEventArgs e)
this.toolStripStatusLabel1.Text = e.UserState.ToString(); // the message will be something like: 45 Kb / 102.12 Mb
this.toolStripProgressBar1.Value = Math.Min(this.toolStripProgressBar1.Maximum, e.ProgressPercentage);

Friday, 17 February 2006 18:09:05 (GMT Standard Time, UTC+00:00)  #    Comments [29]  .Net General | .Net Windows Forms

# Thursday, 02 February 2006
Using Xml DOM with MetaBase.xml
For some reason i can't get SelectNodes to work with the IIS 6 MetaBase.xml file.  It just doesn't return any matches.  I think the structure may be non-standard or too complex, or else i'm not using it right.  but in any case, I worked around the problem by opening the file with File.OpenText and using Regex to parse out the nodes i'm interested in, namely the IISWebServer nodes.

string MetaBase = "";
using(StreamReader sr = File.OpenText(ConfigurationManager.AppSettings["MetaBasePath"].ToString()))
MetaBase = sr.ReadToEnd();

foreach(Match m in new Regex(@"(?x:)<IIsWebServer[^>]*>.*?</IIsWebServer>", RegexOptions.IgnoreCase).Matches(MetaBase))
XmlDocument doc = new XmlDocument();
string IisCode = "", ServerBindings = "", ServerComment = "";
XmlElement node = doc.DocumentElement;
// now you can access the node attributes

Thursday, 02 February 2006 13:38:34 (GMT Standard Time, UTC+00:00)  #    Comments [0]  .Net General | .Net Windows Forms | Asp.Net | Windows Server

CheckBoxList: Select All / None client-side script
<script language="javascript" type="text/javascript">
function Select(Select)
for (var n=0; n < document.forms[0].length; n++)
if (document.forms[0].elements[n].type=='checkbox')
return false;

Select <a href="#" onclick="javascript:Select(true)">All</a> | <a href="#" onclick="javascript:Select(false)">None</a>

Thursday, 02 February 2006 13:25:33 (GMT Standard Time, UTC+00:00)  #    Comments [7]  Asp.Net

# Monday, 30 January 2006
Fix: Unable to validate data, MachineKey.GetDecodedData
i kept getting these sporadic error messages on my web applications and i could never figure out why. 
Unable to validate data at
System.Web.Configuration.MachineKey.GetDecodedData(Byte[] buf, Byte[] modifier, Int32 start, Int32 length, Int32& dataLength) at
System.Web.UI.LosFormatter.Deserialize(String input)
searching the net just reveals a troop of similarly frustrated users without solutions.  but today i found the actual reason why, and the work-around.
this excellent post on experts-exchange has the answer.  apparently it happens when users leave a page open for a long time, and then cause a post back.  something to do with the machine key being automatically generated and it changes before the user causes the postback, and it can't validate it then. 
the fix is to set a static machine key. 
There is a kb article with some code to generate a key for you, + instructions.  


Monday, 30 January 2006 22:53:44 (GMT Standard Time, UTC+00:00)  #    Comments [13]  .Net General | Asp.Net

ADOX + Excel: bogus worksheets
a web site i'm working on imports excel documents, and does some processing on them for importing into a database.  I use the code from this post to do the importing, and it works nicely.  I recently came across a problem where i was encountering duplicate records, and it took me ages to figure out why.  Apparently a 'named range' of cells in a worksheet is treated as a Table by ADOX.  so you get more than you bargain for when you iterate through the tables in the resulting DataSet. 
I was able to work around the problem by discarding any tables that do NOT end in the dollar $ character.

Monday, 30 January 2006 15:30:12 (GMT Standard Time, UTC+00:00)  #    Comments [1]  .Net General | Asp.Net | Database