.Net ramblings
# Tuesday, 24 March 2009
Asp.Net membership, correcting username case at login
if your application has users who like to log in as "JOE BLOGGS" or "joe bloggs" when their username is actually "Joe Bloggs", you might want to ensure that they login with the correct "case" of their username.  It can cause discrepancies if you refer to the current Identity.User in your web application, for example if you use the username anywhere in your database and run reports grouped on the username, you will get multiple records for each variation on the case of the username.  It is surprisingly unintuitive to solve this problem.  Firstly you would think that Asp.Net membership would take care of this itself.  Then you would think that you could determine the correct case of the username as follows:
protected void Login1_LoggedIn(object sender, EventArgs e)
string correctUsername = Membership.GetUser(this.Login1.Username).Username;
FormsAuthentication.SetAuthCookie(correctUsername , true);

but this doesn't work because the "Username" property of the MembershipUser object does not collect its value from the AspNetDB SQL database like you would expect, instead it is filled with whatever you pass it when loading the user, this must be a bug but i'm not bothered trying to convince MS.  instead, i came up with this solution below, to directly load the AspNetUser object from a Linq DataSource of the AspNetDb database (created using SqlMetal).

protected void Login1_LoggedIn(object sender, EventArgs e)
// correct the case of the username
string Username = this.Login1.UserName;
AspNetDb db = new AspNetDb();
MembershipUser memUser = Membership.GetUser(Username); // load the MembershipUser object to get the UserID
Aspnet_User aspnetUser = db.Aspnet_Users.SingleOrDefault(z => z.UserId == new Guid(memUser.ProviderUserKey.ToString()));
if(aspnetUser != null)
Username = aspnetUser.UserName;
FormsAuthentication.SetAuthCookie(Username, true);

Tuesday, 24 March 2009 16:38:48 (GMT Standard Time, UTC+00:00)  #    Comments [1]  Asp.Net

# Friday, 27 February 2009
Crystal Reports date format (in code)
Cstr(CDate({Table.Column}), "dd/MM/yyyy")

Friday, 27 February 2009 17:47:52 (GMT Standard Time, UTC+00:00)  #    Comments [0]  .Net General | Asp.Net

# Thursday, 19 February 2009
A simple Auto-Save / Keep Alive feature for Asp.Net
today i came across a situation where a user was spending a long time filling out a form.  they went past the session timeout and when they hit save they got booted back to the login screen, having lost the previous 30 minutes of work.  i looked around the net and found a few options with AJAX and what not but it doesn't make sense to keep renewing the session automatically otherwise you might as well not have a timeout, which is there for security reasons anyway.  in my case i don't actually want to save the information to the database (it's a transaction) until the user hits the Save button, i just want to keep the session alive. 

so i came up with this idea to ask the user if they want to keep their session alive with a javascript prompt every 15 minutes. if they leave their computer and don't answer the prompt, the session will time out since they won't have interacted with the web site (regardless of how they answer the prompt after the timeout).  if they answer OK to the prompt it invokes a Ping() type web service to keep the session alive.  this is the most lightweight way i could think of doing it.  i don't want to post back to the page because that will interrupt the user and make them wait for the page to reload.

there are 3 parts:

"KeepAlive" function

I put this function in a 'Util' class so pages can easily turn on the 'Keep Alive' functionality, simply call Util.KeepAlive(this);

public static void KeepAlive(Page p)
p.ClientScript.RegisterClientScriptInclude("KeepAlive", "/KeepAlive.js");

Ping.asmx (add the web service to your root folder)

public void Ping()
HttpContext.Current.Response.End(); // this makes the result easier to parse than an XML web service message

KeepAlive.js (put this file in your root folder)

var timerID = 0;	     // used to track the timer function
var interval = 1000*60*15; // 15 mins
var KeepAliveUrl = '/Ping.asmx/Ping'; // replace your web service address here
var xmlhttpKeepAlive;

function AutoSaveSubmit()
if(confirm('15 minutes of idle time has passed, do you want to keep your session active?'))

function InvokeWebService()
if (window.XMLHttpRequest)
xmlhttpKeepAlive=new XMLHttpRequest();
xmlhttpKeepAlive.onreadystatechange = xmlhttpChangeKeepAlive;
xmlhttpKeepAlive.open('GET',KeepAliveUrl + '?T=' + timerID,true);
// code for IE
else if (window.ActiveXObject)
xmlhttpKeepAlive=new ActiveXObject('Microsoft.XMLHTTP')
if (xmlhttp)
xmlhttpKeepAlive.onreadystatechange = xmlhttpChangeKeepAlive;
xmlhttpKeepAlive.open('GET', KeepAliveUrl + '?T=' + timerID, true);
return false;

function xmlhttpChangeKeepAlive()
var text;
if (xmlhttpKeepAlive.readyState == 4)
text = xmlhttpKeepAlive.responseText;
if (xmlhttpKeepAlive.status==200) // OK
if(text == 'OK') // reset the timer
timerID = setTimeout('AutoSaveSubmit()', interval);
alert('Your session has already expired.\nIf you have any information on this page you will lose it if you try to save this page now. You have 2 options to avoid losing the information on this screen.\n\nOption 1: open a new internet window and log in again to the web site, then close that window and go back to this window, at which point you will have a new session and you will be able to save the information.\n\nOption 2: Copy all the text you have typed on this page and paste it into another program (such as Word or Notepad), then log in to the web site again (click the home page) and come back to this page, and paste in the text again.\n\nTo prevent this happening in the future, click OK on the 15 minute reminder box each time it appears, this will keep your session active. If you do not answer the reminder within 10 minutes the session may expire.');
alert('Error: ' + xmlhttpKeepAlive.status + '. The session may have already expired, please try to save the page now');

You might be wondering why i append the timer code/number to the url of the web service.  The reason is because IE has a caching bug and will not actually send the XmlHttp request unless the URL is different to what it has in its history, it will just return the previous result.

Thursday, 19 February 2009 16:18:50 (GMT Standard Time, UTC+00:00)  #    Comments [10]  Asp.Net

# Sunday, 11 January 2009
SQL 2005 cannot drop user with owned schema
i notice when i backup a database and restore it to another server, the user IDs are different and i have to delete the users and add them back in to the database.  however last time i tried this the drop failed because the user owned a schema.  i right-clicked on the user's properties and the tick box for 'db_owner' was shaded in a read only state.  so i couldn't delete the user and couldn't remove their schema ownership.  took a while to figure out that the way to do this is via the Database > Security > Schemas menu, then change the schema owner back to itself, e.g. db_owner.  then the user is free to be deleted.

Sunday, 11 January 2009 15:28:04 (GMT Standard Time, UTC+00:00)  #    Comments [2]  Database

# Tuesday, 23 December 2008
HowTo: disable the Excel prompt for opening formats different than the extension
many web sites export tabular information from grids/tables into 'Excel' format. the file is not a true Excel format and actually contains X/HTML.  if the file is opened in Excel 2007 you may get a prompt that the file is in a different format than specified by the file extension.  if you regularly work with files like this, there is a way to disable this prompt, add a DWORD key called ExtensionHardening with value 0 to HKEY_CURRENT_USER\Software\Microsoft\Office\12.0\Excel\Security
it works straight away, no need for a reboot.

Tuesday, 23 December 2008 12:08:07 (GMT Standard Time, UTC+00:00)  #    Comments [0]  Asp.Net

# Wednesday, 10 December 2008
Outlook Macro to Remove Attachments
great outlook macro to strip attachments from selected emails, darin archer's blog

Wednesday, 10 December 2008 13:04:44 (GMT Standard Time, UTC+00:00)  #    Comments [0]  General

# Sunday, 26 October 2008
IIS6 Service Unavailable, after installing KB 958644
IIS went down this morning after KB 958644 was isntalled automatically last night. My sites were showing "Service Unavailable"
there were several system event logs like so:
  • A process serving application pool '.Net 2.0 App Pool' suffered a fatal communication error with the World Wide Web Publishing Service. The process id was '2960'. The data field contains the error number.
  • Application pool '.Net 2.0 App Pool' is being automatically disabled due to a series of failures in the process(es) serving that application pool.

rebooting the server did not solve the problem.  so, on further research, KB article 885654 revealed the cause of the errors, lack of registry permissions for NETWORK SERVICE.  i hadn't changed any configuration on the server so assumed it was caused by a change in that windows update package.  i dug out ProcessMonitor and set up a registry filter for w3wp.exe where the Result was ACCESS DENIED.  there were about 50 entries during the time i enabled event capture and loaded up one of the sites that uses the affected application pool.  Most of them pointed to SystemCertificates entries.  I went through each one in regedit and gave NETWORK SERVICE full control where the process attempted to Create a key, and Read only access where the process attemped to Open the key.  worked fine then.

hope this helps someone out.

Sunday, 26 October 2008 13:41:10 (GMT Standard Time, UTC+00:00)  #    Comments [0]  Asp.Net | Windows Server

# Thursday, 16 October 2008
XPath problems, SelectNodes returns no nodes
thanks to Kev for his brilliant post about solving this problem, where you know you have the correct XPath expression but .Net is not giving you any nodes :(
his solution is the correct one, an alternative approach is to remove the xmlns from the root element before you load the XmlDocument so that you can use the default empty namespace (or something like that).

Thursday, 16 October 2008 19:05:36 (GMT Daylight Time, UTC+01:00)  #    Comments [0]  .Net General

# Wednesday, 10 September 2008
Alter a column with a default value
say you wanted to change a BIT column to a NVARCHAR column, and the BIT column has a default value set to 0 or 1.  you can't run the following statement or you get a dependent object error.
alter table TABLE1 alter column COL1 NVarChar(MAX)
so i found this solution here, after you've run the query below, you can alter the column as above.

SET @df = 
  WHERE id = OBJECT_ID('dbo.TABLE1') 
   AND name = 'COL1') 
  EXEC sp_rename @df, 'df_to_drop', 'OBJECT' 

Wednesday, 10 September 2008 10:46:01 (GMT Daylight Time, UTC+01:00)  #    Comments [0]  Database

# Wednesday, 20 August 2008
Encoding issues with File.WriteAllText
i assumed that File.WriteAllText() would assume UTF8 encoding since all strings are unicode in .net by default, so i never bothered specifying the encoding in the 3rd parameter.  But it was causing me grief with accented characters, and i finally worked it out that i needed to specify UTF8 explicitly.
File.WriteAllText(filepath, text, Encoding.UTF8);

Wednesday, 20 August 2008 15:00:46 (GMT Daylight Time, UTC+01:00)  #    Comments [0]  .Net General