.Net ramblings
# Saturday, 10 September 2005
Mapping .html pages to Asp.Net

I was doing an upgrade on a web site recently, and all the pages were .html pages.  I wanted to add some .Net functionality, but didn't want to change all the urls, for bookmarks, search engines etc.  As well as scaring off the client with the strange ".aspx" file extensions.  yes- many irish companies are still technophobic. 

Add an IIS mapping for .html

i remember how to change mappings for a file extension in IIS (web site properties > home directory > configuration), so i did this for .html pages by adding a mapping for .html to aspnet_isapi.dll (copy the full path from the mapping for .aspx). 

Add a HttpHandler to the application web.config file

when i did the above, my .net code was ignored and rendered as plain text.  i found out this was because the web application (at the .net level) wasn't configured to handle .html files as .aspx files. this is what i added to my web.config to get it working:

<configuration> <system.web> <httpHandlers> <add verb="*" path="*.html" type="System.Web.UI.PageHandlerFactory" /> </httpHandlers> </system.web> </configuration>

now the whole application works with full .net functionality, overcoming all those migration problems usually associated with .net upgrades.

Saturday, 10 September 2005 14:38:39 (GMT Daylight Time, UTC+01:00)  #    Comments [0]  Asp.Net

# Friday, 09 September 2005
An asp.net button that disables itself automatically after clicking.

Some users of a web application i wrote insist on clicking buttons more than once, probably out of impatience. this often causes duplicate key exceptions with the database, because the first time they clicked the button the record was created, and the second time they clicked it, an exception is thrown, so they get the error screen and don't know what they did wrong. 

i wanted to write a button control that would disable itself automatically and re-enable itself once it was finished.  i couldn't find any good samples out there.  javascript is obviously the answer, and the solution i came up with is quite simple.  here's the code: currently only works with .Net 1.1:

	/// <summary>
/// A button control that disables itself when clicked, and changes the text to "Please wait..."
/// This is to prevent duplicate clicks by impatient or novice users.
/// It requires the button to be placed in a server form.
/// </summary>
[DefaultProperty("Text"), ToolboxData("<{0}:SmartButton runat=server></{0}:SmartButton>")]
public class SmartButton : Button

/// <summary>
/// Add an 'onClick' attribute to disable the button when it is clicked, and submit the form,
/// invoking the postback.
/// The onClick code handles the case where __EVENTTARGET is registered on the page, in which case
/// this variable is set to the button ID, and the form is submitted.
/// The other case is where __EVENTTARGET does not exist on the page, i found this sometimes
/// occurred on pages with only one button. In this case, the form is simply submitted, and the
/// button_click event will be raised by virtue of the default submit button in the form.
/// </summary>
protected override void Render(HtmlTextWriter output)
string onClick = "if(this.form != null && this.form.__EVENTTARGET != null){ this.form.__EVENTTARGET.value='" + this.UniqueID + "'; this.disabled = true; this.value = 'Please wait...'; this.form.submit(); } else this.form.submit(); ";
if(this.Attributes["onclick"] != null) // prepend the existing onClick attributes
onClick = this.Attributes["onclick"].ToString() + onClick;
this.Attributes.Add("onclick", onClick);

protected override void OnClick(EventArgs e)
// do the OnClick code first
base.OnClick (e);

// then reset the enabled + text values to their original state
int insertAt = Math.Max(this.Page.Controls.Count-1, 0); // never insert at -1 if there are no controls on the page
this.Page.Controls.AddAt(insertAt, new LiteralControl(String.Format(@"
if(document.getElementById('{0}') != null)
document.getElementById('{0}').disabled = false;
document.getElementById('{0}').value = '{1}';
", this.UniqueID, this.Text)));

Friday, 09 September 2005 15:41:29 (GMT Daylight Time, UTC+01:00)  #    Comments [2]  Asp.Net

# Saturday, 27 August 2005
A 'Progress-Task-List' control

I decided to write this control when i realised there are some cases where a progress bar is not enough, even with a label that gets updated for each new stage of a list of operations.

Sometimes you want the user to see what's coming next, what has already been done, and the ProgressTaskList control does just that.  it's nothing new of course, often used in installers and the like, but there didn't appear to be any .Net control like this.

I've submitted the control to code-project (URL to follow), which is where any updates will be posted.  If you have comments or suggestions, it's best to put them on the code-project site please.

I'm quite pleased with the way it turned out.  The code is very simple, and i couldn't find any bugs having done lots of testing.

As you can see in the screenshot to the left, it handles scrolling quite well, and automatically jumps to the current task when it is starting a new one.

To use it you just specify TaskItems as a string[] and call Start() to set it off. Then call NextTask() every time a task is finished to advance it to the next task. 

You can download the source here (30Kb) if you like, but check on code-project for updates.

Saturday, 27 August 2005 01:28:29 (GMT Daylight Time, UTC+01:00)  #    Comments [0]  .Net Windows Forms

# Friday, 19 August 2005
Tortilla EspaƱola: the real deal

Ever since i went to Malaga in Southern Spain 10 years ago, i have tried and failed to reproduce the authentic taste of the amazing "Tortilla EspaƱola", the Spanish Omelette.  I remember paying about a euro for a large tortilla that would be perfectly acceptable to eat for breakfast, lunch or (and!) dinner.
fortunately, i came across a recipe online today that i am posting here for future reference.  although i am fairly handy with the old omelettes in general, this was a real find, in particular the discovery that you fry the potatoes in lots of olive oil, which makes them go soft and gives a lovely soft texture to the whole tortilla.
You can see it on it's original location here, i'm only copying it here in case that url ever disappears or goes down.

Spanish TortillaServes four as a main course; twelve as a tapa.

  • 1 and 3/4 cups vegetable oil for frying (or plain olive oil)
  • about 5 medium-sized potatoes, peeled
  • 2 tsp. coarse salt
  • 2 or 3 medium-sized onions, diced
  • 5 medium cloves garlic, very coarsely chopped
  • 6 large eggs
  • 1/8 tsp. freshly ground black pepper

In a 10 or 11 inch non-stick skillet (should be at least 2 inches deep), heat the oil on medium high. While the oil is heating, slice the potatoes thinly, about 1/8 inch. Transfer to a bowl and sprinkle on the 2 tsp. of salt, tossing to distribute it well.

When the oil is very hot (a potato slice will sizzle vigorously around the edges without browning), gently slip the potatoes into the oil with a skimmer or slotted spoon. Fry the potatoes, turning occasionally (trying not to break them) and adjusting the heat so they sizzle but don't crisp or brown. Set a sieve over a bowl or else line a plate with paper towels. When the potatoes are tender, after 10 to 12 min., transfer them with the skimmer to the sieve or lined plate.

Add the onions and garlic to the pan. Fry, stirring occasionally, until the onions are very soft and translucent but not browned (you might need to lower the heat), 7 to 9 min. Remove the pan from the heat and, using the skimmer, transfer the onions and garlic to the sieve or plate with the potatoes. Drain the oil from the skillet, reserving at least 1 Tbs. (strain the rest and reserve to use again, if you like) and wipe out the pan with a paper towel so it's clean. Scrape out any stuck-on bits, if necessary.

In a large bowl, beat the eggs, 1/4 tsp. salt, and the pepper with a fork until blended. Add the drained potatoes, onions, and garlic and mix gently to combine with the egg, trying not to break the potatoes (some will anyway).

Heat the skillet on medium high. Add the 1 Tbs. reserved oil. Let the pan and oil get very hot (important so the eggs don't stick), and then pour in the potato and egg mixture, spreading it evenly. Cook for 1 min. and then lower the heat to medium low, cooking until the eggs are completely set at the edges, halfway set in the center, and the tortilla easily slips around in the pan when you give it a shake, 8 to 10 min. You may need to nudge the tortilla loose with a knife or spatula. (I found i had to turn it down very low to keep it from burning)

Set a flat, rimless plate that's at least as wide as the skillet upside down over the pan. Lift the skillet off the burner and, with one hand against the plate and the other holding the skillet's handle, invert the skillet so the tortilla lands on the plate (it should fall right out). Set the pan back on the heat and slide the tortilla into it, using the skimmer to push any stray potatoes back in under the eggs as the tortilla slides off the plate. Once the tortilla is back in the pan, tuck the edges in and under itself (to neaten the sides). Cook until a skewer inserted into the center comes out clean, hot, and with no uncooked egg on it, another 5 to 6 min.

Transfer the tortilla to a serving platter and let cool at least 10 min. Serve warm, at room temperature, or slightly cool. Cut into wedges or small squares, sticking a toothpick in each square if serving as an appetizer.

If the idea of cold tortilla doesn't get you going, you should try it, it might surprise you like it did me.  I didn't even like eggs when i got hooked on tortillas :)

Many thanks and all credits to Sarah Jay for sharing this great recipe.
By the way, it's incredibly filling because of all that oil, so eat about half as much as you'd think, then wait a while to see how you get on!  no wonder the spaniards have so many siestas, eating tortilla all the time would knock anyone out.

Friday, 19 August 2005 16:34:36 (GMT Daylight Time, UTC+01:00)  #    Comments [2]  General

HowTo: Clear a stuck print job in Windows

MS Word crashed in the middle of a print job, and the document was stuck in the print queue, not obeying commands to delete or cancel it, even after reboots.
To fix this, i opened c:\windows\system32\spool\PRINTERS and deleted all the files there.  If the files are locked and won't delete, stop the Print Spooler service first and then delete the files.
This worked for me!

Friday, 19 August 2005 13:41:49 (GMT Daylight Time, UTC+01:00)  #    Comments [1]  General | Windows Server

# Tuesday, 09 August 2005
FIX: Server 2003 won't shutdown because of 'logged on users'
i encountered problems trying to shut down or reboot my windows server 2003 while logged in via remote desktop.  i initiate a shut down from the start up menu, and it logs me off and quits the RD session, but doesn't power off.  If i try and connect in again with RD, it shows me a blank screen on the server for a few seconds, and then quits with no error message.

if i try running "shutdown -s" then i click OK to the message that the computer is shutting down in 30 seconds, but it never does. system log entry: "Application popup: System Shutdown : The system is shutting down. Please save all work in progress and log off. Any unsaved changes will be lost. "

finally, if i push the power button it doesn't complete the shut down either. (i have 'shutdown' selected in power management for when the button is pressed).  i do see an event ID 26 in the system log at the time i pressed the button, with the message 'Application popup: Windows : Other people are logged on to this computer. Shutting down Windows might cause them to lose data. Do you want to continue shutting down?'.  this is a bit useless because the server has no mouse/keyboard/monitor, and i have no way to interact that message except using remote desktop (which doesn't even show that message on screen if i am logged in via RD), and i want to force a software shutdown without being asked questions i can't answer!

finally i found a work around to use the command line tool shutdown.exe with some more severe arguments.  This saves my raid array re-synching from hard-resets.

To Reboot:
shutdown.exe -r /t 10 /d p:1:1 /c "Maintenance, Planned"
To Shutdown:
shutdown.exe -s /t 10 /d p:1:1 /c "Maintenance, Planned"

Tuesday, 09 August 2005 09:31:10 (GMT Daylight Time, UTC+01:00)  #    Comments [2]  Windows Server

# Tuesday, 02 August 2005
How to properly use the javascript string replace function

i've seen a ton of different approaches to people using the javascript string function, including some homemade versions. 

the javascript replace function uses regular expressions, so it doesn't work like the C# or VB functions.  (i hoped it would)

what is also unusual for c# programmers is that the pattern you pass into the function does not get wrapped in quotes.

example: to replace all single-quotes in a string variable (called s) with the ` character:

s = s.replace(/'/gi, '`');

if that looks like gobbledegook i'll explain. the first / character starts the pattern, and the ' character is what we want to replace. the second / character ends the pattern and allows us to include options for the regex parser. g means global and i means ignore case.

i'm really only posting this so i'll remember it myself!

Tuesday, 02 August 2005 13:43:45 (GMT Daylight Time, UTC+01:00)  #    Comments [1]  General

# Monday, 01 August 2005
Scrollable DIV css code, useful for big checkboxlists etc
	height: 9em;
	overflow: auto;
	border: 1px solid #666;
	background-color: #e8e8e8;

I ran into a problem designing a web app that had a few checkboxlists, and when the real data got imported, the checkboxlists took up most of a page with all the entries!  this is obviously no good, but the app still needed a checkboxlist rather than a single-select dropdownlist, so i found this css code that you can apply to a DIV wrapped around the checkboxlist.  you can set a width if you like but i just let it fill whatever container the div is already in. 

works in firefox and IE6 in windows, didn't try on anything else. 

Monday, 01 August 2005 14:59:54 (GMT Daylight Time, UTC+01:00)  #    Comments [1]  Asp.Net

# Thursday, 30 June 2005
Crystal Reports for .Net, locked file when exporting to PDF with a crHtmlText field

i made a simple change to a crystal report in the VS designer, by changing the text format for a text box to crHtmlText instead of crStandardText.  little did i realise this would break the report altogether and cause it to fail when i try to export as a PDF.  i had forgotten i did this change at all and thought it was a permissions issue, but not at all, crystal reports is just crap.

my advice is don't use crHtmlText

Thursday, 30 June 2005 15:50:42 (GMT Daylight Time, UTC+01:00)  #    Comments [0]  Asp.Net

IIS6 basic authentication (challenge/response) with PHP not working

i spent ages trying to figure this out.  i set up a secure folder on a php site, and turned off anonymous access in IIS on the folder.  i have it set to basic authentication, and given a windows user account RX permissions on the folder.  so a visitor gets prompted to login with a username/password when they try to access it.  even when i enter the correct details, i am not allowed in, i get 403.1 access denied due to ACL or whatever.

i found out it was because i hadn't given my new user read/execute permissions on the php-cgi.exe file in the PHP folder.  this solved it. hope this helps someone out there who runs into the same problem.

Thursday, 30 June 2005 15:48:38 (GMT Daylight Time, UTC+01:00)  #    Comments [1]  Windows Server