Archive for May, 2010

URL Rewriting Configuration File Updates Not Taking Effect

May 20, 2010

We have this little XML file called redirect.config which contains details of dead links in our app. and the corresponding new ‘live’ link that should be served in its place.

Our Web Content team was saying that updates to this file were not being recognised by the app. I mucked around with the file for a while checking format, making sure the xml was well-formed, then I deleted my Browser cache, stripped out all records in the XML file except the new (non-working) one but alas nothing worked. Also, existing redirections still worked although the redirection.config was empty except for one record. Then I restored the file to its original state and, although in practice I had changed nothing, the redirection suddenly kicked in.

Puzzling, but the problem was now out of my hair – until today, when the problem recurred on a different domain and stubbornly stayed there. So I had to figure it out for real. I went to lunch thinking, ‘Something is cached. I’ll restart the Application Pool on the Web Server’.

When I got back, from lunch the redirections were working. My colleague told me she has restarted the Application Pool but didn’t know why it worked.

Investigating the problem properly for a change I found the redirect.config file was being read by a method which was invoked during IHTTPModule.Init. Yes, the config file (really just an xml data file) was being used as data for a custom HTTPModule and was being read during HTTPModule Initialisation. So, when is a HTTPModule Initialised ? Here’s a great link ‘IHttpModule Gotchas’ by UK Programming legend Dominic Pettifer which explains all.

The basic deal is that the .NET runtime will create a certain number of HTTPApplication objects on Application startup. It keeps these in a pool. For each HTTPApplication object, .NET runtime creates an instance of each custom HTTPModule registered in the web.config. That’s when IHTTPModule.Init is called. When a HTTPRequest comes in, that Request is served by one of the HTTPApplication Objects in the Pool which is then put back in the Pool.

The consequence for me is that updates to my redirect.config file are never read until a new HTTPApplication object is created and therefore a new instance of my HTTPModule is created. So I was basically correct. The redirect data was being cached – inside the pooled HTTP Application objects.

The fix – re-create the Application Pool.

And that’s why my redirects started working out of nowhere: the .NET Runtime according to its internal algorithms decided to create a new instance of the HTTPApplication object for my app., hence the redirect.config file was reloaded via IHTTPModule.Init.

No more ulcer. So, as Sunil Wettimuny famously said: I go now.

Visual Studio 2005 ‘Could Not Load Type Global.asax’ and ‘Cannot Copy Assembly After Build Because It Is Being Used By Another Process’ and ‘Control Name is not a member of Page Name’

May 18, 2010

Had a berserk time trying to load one of our corporate websites for the first time on a new DEV machine. It was an exemplary Journey Of Pain which I will now share with you.

The web site comprises 12 projects. Even after I loaded them down from Visual Source Safe into a solution and put in the necessary references to each other via Add Reference I still had a kaleidoscope of errors and warnings which no one here had ever seen before. My colleague performed a ‘Clean Solution’ which miraculously removed a lot of the warnings and errors.

Learning Point #1: When downloading a non-trivial solution from Visual Source Safe, do a Clean Solution after adding in all the references. There is some forum chat that says a Rebuild All will do the same thing, but I found in practice that Clean Solution cut out a lot of warnings and errors which Rebuild All did not.

I was now left with Cannot Load Type Global.asax.

Opening up the Global.asax.vb page I found some unresolved references, so I added those, then rebuilt, but still got Cannot Load Type Global.asax., A bit of Googling told me that Cannot Load Type Global.asax meant by main dll was not being generated. So I excluded Global.asax.vb from the project to see if anything was being covered up and did a rebuild.

That rebuild revealed a squillion errors. Specifically, I got a Cannot Load Type on every single one of the User Controls (ASCX files), plus cannot copy assembly after build because it is being used by another process . Googling the Cannot Copy Assembly After Build error I found that this can occur because hostingEnvironment shadowCopyBinAssemblies=”false” was set in web.config. I commented out that entry and lucked out on it working. Cannot Copy Assembly After Build was deaded.

Next thing was to add references to 3rd party DLLs required by the solution. The DLLs were not in our Source Control so i had to hunt them up on the Web. these Dlls were referenced in our Web.Config file and not directly anywhere else, but they came out as obvious errors during the build.

This left me with 96 errors along the line of Cannot Load Type whatever.ascx along with a generous sprinkling of ‘ControlName’ is not a member of ‘PageName’.

Attribute Blocks

These turned out to be sourced from the same basic issue: the aspx.designer file was not being recognised by the Code Behind file – they were not linking together as if they did not belong to the same Partial Class. Unusually the designer files were not nested below the ascx file along with the aspx.vb (code behind file). I spent ages trying to force these designer files to regenerate without flat out deleting them or converting to a Web Application Project and then hit the post by hennehelene in this ASP.NET forum thread which prescribed a weird alchemy, namely to include a CodeFile attribute to the aspx.vb file, compile then remove the CodeFile Attribute and compile again.

HenneHelene’s solution works for me because my pages had the same basic markup as hers: A CodeBehind attribute, an Inherits attribute, but no CodeFile attribute. I was thus able to add then remove the CodeFile attribute as described above, but I subsequently returned the CodeFile attribute back to the page because I didn’t want any future developer encountering the same issue.

The presence of the CodeBehind attribute without the CodeFile attribute suggests that the web site I was loading originally began life as a .NET 1.1 application

Codebehind is a .NET 1.1 Page Attribute which is retained in.NET 2.0 for backwards compatibility. CodeFile is the corresponding .NET 2.0 attribute.

Cross-Browser Styling For hr Tag

May 7, 2010

The innocuous hr tag renders quite differently across IE, Chrome and Firefox. In particular, on the last two mentioned browsers the hr was rendering with an indented border, which it didn’t in IE.

Searching for a cross-browser way to style hr I ended up at this very helpful forum post from HTML Help Central, entitled ‘Google Chrome With hr, but then had to tweak it a bit so that it worked across my browser family.

Here’s the final result for which I was awarded the VC, DSM, OBE and P-K4:

hr
{
border-top:1px #dbdee4 solid;
height: 1px;
border-bottom:0;
border-left:0;
border-right:0
}

Of course you can substitute #dbdee4 for any colour you desire. Maybe try ‘Off Puce’. Puce, specifically, is the color of the belly of a flea.

WebForms Validation Summary Use StartUpScript to Generate Error Message Box Without Using Client-Side Validation

May 4, 2010

Scenario

I wanted to use ValidationSummary.ShowMessageBox to show a popup containing the error message from all failed validations but I had some CustomValidator controls and didn’t want to write complex client-side validation function for each one of them.

I needed a way to get the ErrorMessages from each CustomValidator and all my other Validators into a MessageBox without writing any custom client-side validation routines

Solution

The solution is to collect all the error messages from the Validators into a string and use ClientScript.RegisterStartUpScript to show the errors. This solution comes via a semi-genius post from the well-known Missourian Programming legend bdukes. All I have done is translate it into VB.NET. Here’s the C# original from Stack Overflow thread Elegant way to make CustomValidator work with ValidationSummary Messagebox

”’ Registers a javascript to display error messages from validation as the Page loads from a postback.
Private Sub RegisterServerValidationMessageScript()
If (Page.IsPostBack) Then
Page.Validate()
If (Not Page.IsValid) Then
‘errormessage holds the script
Dim errorMessage As StringBuilder = _
New StringBuilder(“alert(‘Validation Error. \r\n\r\n”)
Dim i As Integer
‘ Add error message from all failed validators
For i = 0 To Page.Validators.Count – 1
Dim validator As IValidator = Page.Validators(i)
If (Not validator.IsValid) Then
If Not errorMessage.ToString().Contains(validator.ErrorMessage) Then
errorMessage.Append(“- ” + validator.ErrorMessage)
If (i < Page.Validators.Count – 1) Then
errorMessage.Append("\r\n")
End If
End If
End If
Next

errorMessage.Append("');”)
If Not Page.ClientScript.IsStartupScriptRegistered(“validationAlert”) Then
Page.ClientScript.RegisterStartupScript(Me.Page.GetType(), _
“validationAlert”, errorMessage.ToString(), False)
End If
End If
End If
End Sub

I just call the above function from Page_PreRender Event Handler.

Almost No Known Side Effects
The side-effect to the above code is that it is called on every Postback, so you will get the alert popup appearing on every Postback while you have validation errors. But what I like about it is that any time I add a new Validator, its error message is automagically added to the alert popup. So that’s less maintenance for me.

Hope that rings your bells.