giovedì 20 dicembre 2007

ResolveUrl not resolving

Since the .net conversion of SkakkiNostri, we were facing a rare and strange problem.
When the user clicks the quick Search button, it is internally redirected to a more specialized page using the line:

Response.Redirect(ResolveUrl("~/search_users.aspx?quickValue=" + txtUser.Text), true);

This line was causing 404 errors, with the ResolveUrl call apparently not doing what it has to do: the user was redirected to http://www.skakkinostri.it/~/search_users.aspx?quickValue=something.

Can you spot the problem?

Hint: today, while skimming through the error list I noticed something strange. All of these error reports were for users that contained unicode characters. Lots of them, like in the word "•]•·´º´·» .:. rO£@Lb@ ιи ℓσνє.:. [♡] «·´º´·•[•".

Then came the enlightenment: maybe the ResolveUrl call fails if the URL is not perfectly url-formatted!
And it turns out it's just that way. As simple as it seems, the offending call was promptly replaced with:

Response.Redirect(ResolveUrl("~/search_users.aspx?quickValue=" + Server.UrlEncode(txtUser.Text)), true);

and suddenly exceptions stopped.
Now let's go for a check of all the Response.Redirect calls in the web site :)

venerdì 30 novembre 2007

Custom validators and Nokia Browser

On SkakkiNostri, we have a custom RequiredFieldValidator for a custom control that basically boils down to a textarea. We had a bug report stating that people using the Nokia S60 built-in browser always failed the required field validation. Well, it turns out that the standard .net ValidatorTrim function simply does not work there, probably has something to do with the order of loading of scripts, or maybe our code isn't perfect (I did not try to write a test case, and standard RequiredFieldValidators work just fine). Since I do not have much time at all, I just wrote a simple TrimString function and now we can post messages in SkakkiNostri's forum using the Nokia Browser :)

Code:

// On Nokia Browser, the .net ValidatorTrim always returns null.
function TrimString(s) { return s.replace(/^\s+/g, "").replace(/\s+$/g, ""); }

lunedì 2 luglio 2007

The downlevel W3C html validator

ASP.net is smart enough to know which html content render to which browser, which is good. However there's a small flaw in the browser detection: the W3C html validator is detected as pre-DOM (and since it's not a real browser it logically is one of those), but that defeats the purpose of validating the output of a website.
Luckily it's quite easy to fix this issue. Just create a folder called App_Browsers in your website root and place a file called w3cvalidator.browser, containing the following code:

<browsers>
<!--
Browser capability file for the W3C validator
Sample User-Agent: "W3C_Validator/1.432.2.22"
-->
<browser id="w3cValidator" parentid="Default">
<identification>
<useragent match="^W3C_Validator">
</identification>
<capture>
<useragent match="^W3C_Validator/(?'version'(?'major'\d+)(?'minor'\.\d+)\w*).*">
</capture>
<capabilities>
<capability value="w3cValidator" name="browser">
<capability value="${major}" name="majorversion">
<capability value="${minor}" name="minorversion">
<capability value="${version}" name="version">
<capability value="1.0" name="w3cdomversion">
<capability value="true" name="xml">
<capability value="System.Web.UI.HtmlTextWriter" name="tagWriter">
</capabilities>
</browser>
</browsers>

One small side note. Initially I was placing this file along with another .browser file that I use to render PNG images with transparences (will talk about this little gem in the future). That one was called All.browser and rendered the right code for all browsers, but somehow it prevented the use of the w3cvalidator.browser file. Merging those two files into one did the trick.

mercoledì 13 giugno 2007

Preventing double postback

Today I had to make sure a certain button could not be pressed twice, to avoid processing errors. Initially I just set the disabled property to true, but that would not work since postback from disabled controls is inhibited. I invoked manually the postback, and it worked, but broke when validators prevented the postback. After a little bit of wondering, I crafted this small routine, to be placed in a Page-derived class for simplicity.

/// <summary>
/// Makes a certain button one-shot only,
/// preserving validator functionality
/// </summary>
/// <param name="btn">The button that can't be clicked twice</param>
protected void RegisterSinglePostButton(Button btn)
{
System.Text.StringBuilder sb = new System.Text.StringBuilder();
sb.Append("if (typeof(Page_ClientValidate) == 'function') { ");
sb.Append("if (Page_ClientValidate() == false) { return false; }} ");
sb.Append("this.disabled = true;");
sb.Append(ClientScript.GetPostBackEventReference(btn, ""));
sb.Append(";");
btn.Attributes.Add("onclick", sb.ToString());
}

It can be easily transformed in a control if needed, for further clarity.

sabato 9 giugno 2007

A small step for a man

Just a small accomplishment, yet I'm very happy. In the last days I was having a lot of 404 reports for a no-longer existing page on SkakkiNostri. The referrer page was null, so I had to find the source myself. I grep'd the source code, queried nearly every table in the database, but there was no link to that page there. So chances were a) some search engine b) some user.
Looking at the UserAgent/IP address, I quickly found it wasn't a search engine. So probably it had a user that dumbily had bookmarked that page, and now used my 404 error page to come back to the site. I have been thinking about what I could do to avoid this error, then I had a sudden realization: I could just track down the user using the cookies collection and send him a private message. Guess what? It worked. The user wasn't understanding what a 404 error was, but could access the site, so he was happy. Nonetheless explaining the situation to him we have been to fix the wrong link in the Favorites, and I'm no longer receiving emails. Well, not for that error :)

mercoledì 30 maggio 2007

Score another one for me!

So, after a clean format of my machine, I had this weird error in Microsoft Visual Studio 2005: it wouldn't compile one of my web projects. Compilation failed with the following error:

(O): Build (web): Unable to find the required module. (Exception from HRESULT: 0x8007007E)

As you can see, it says nothing about WHICH module is missing. I tried for a few days to fiddle with dependant assemblies, web.config settings, etc. but only today I have been able to investigate and fix it. I downloaded ProcessMonitor from the Microsoft site and after defining the appropriate filters I tracked down the missing assembly: it was MSVCR71.DLL. Just found a copy on some other location on the HD, placed it into C:\Windows\System32 and it worked flawlessly.

I feel like I deserve a reward. Going to buy an icecream! :-)

domenica 13 maggio 2007

WTF?

While checking the error logs for SkakkiNostri, this morning, I noticed something strange. Yesterday night something like a spider crawled my site, querying the robots.txt as usual, but then it started messing with the file paths.

It tried to visit the pages listed in the web site root (e.g. /forum.aspx), but under the /admin/ folder (/admin/forum.aspx). These do not exist, so I received a notification of the 404 error.

The user agent for those request is Java/1.5.0_11, and the originating host is a dynamic IP of the Telecom Italia range. So maybe one of my user tried a lame scanning tool, but that IP was not in the http logs. How strange...

However I am starting to be annoyed by these notifications. Please, fix that scanning tool! :-)