Andre's Blog
Perfection is when there is nothing left to take away
Moving blogs to ASP.Net

This site was originally written in ASP JavaScript, which worked great, but lacked a couple of things, like being able to upload files without having to parse multipart HTTP requests. So, I decided to move the site to ASP.Net to take advantage of the new functionality offered by the .Net framework, while keeping the implementation written in JavaScript.

In the end, I was able to reuse most of the existing code, but ran into a few issues along the way, which are listed below in hope somebody finds this useful.

1. Page directives

I had to disable ASP.Net request validation (ValidateRequest), which is one of the configuration parameters that I find quite amusing - apparently many ASP.Net programmers are so much unaware about the inner workings of HTTP that Microsoft introduced a special directive preventing HTTP clients from being able to submit angle brackets, so incompetent developers are protected against various forms of attacks.

In addition to this, I had to add the ASPCompat directive to make sure MySQL ODBC driver could still be used, so the final page directive looked like this:

<%@ codepage="65001" aspcompat="true" validaterequest="false" %>

2. Request URL

Microsoft decided to remove HTTP_URL from the ServerVariables collection in ASP.Net and provide a special request property instead, so I had to replace all references to HTTP_URL:

Request.ServerVariables("HTTP_URL")

with the equivalent references to the new property:

Request.RawUrl

The purpose of this change escapes me - Microsoft could just add the new property without removing the original one, so existing code would not have to change.

3. Undefined Symbols

JavaScript provides a mechanism to check the type of a variable even if the symbol was not defined. This makes such tasks as generating context-sensitive menus easier because some variables could be defined only for relevant pages and then a shared menu template could be included in all pages and use code similar to this:

if(typeof(userinfo) == "undefined")
   Response.Write("<a href=\"login.asp\">Login</a>");

Microsoft eliminated this functionality, forcing developers to define variables. This practice is certainly good in languages like C++, but sometimes is too restrictive for a scripting language.

There is a compiler option (/fast-) provided in JScript.Net to disable this functionality in exchange for slower code, but it simply doesn't work in ASP.Net - when the option is active, there is no output generated and no errors are reported.

I didn't have much choice but to define all variables in a common include file.

4. Constructors

In classic JavaScript, a constructor is a function defined just as any other function, which initializes its data members this way:

function userinfo_t(userid, username)
{
   this.userid = userid;
   this.username = username;
}

var userinfo = new userinfo_t(rec.userid, rec.username);

In JavaScript.Net, all functions defined on the page are actually members of the page class and can no longer be constructors. In order to retain the functionality Microsoft introduced a new keyword, expando, which is intended to be used in front of a constructor function:

expando function userinfo_t(userid, username) {...}

5. Include Files

I always approached ASP includes in a way similar to how it's done in C++. That is, if some source file, be that an ASP file or another include, used some functionality, I would add a corresponding include file. This practice allowed me to include any file without having to worry about it dependencies.

ASP.Net, however, could no longer process multiple symbol definitions across more than one include file, so I had to move include statements from all include files into the ASP files.

6. Ending the Response

Unlike in classic ASP, ending the HTTP response ASP.Net generates an exception, which cannot be suppressed within a try/catch block and is reported by .Net in a form of an ugly message instead of just flushing existing output and quietly returning from the rendering function. Replacing Response.End() calls with return statements works around this problem.

7. Response Redirection

Another eyebrow raising feature is that Response.End() is called implicitly from Response.Redirect(), which triggers the same exception described above. It turns out that Microsoft introduced an additional parameter in Response.Redirect that indicates whether the caller wants to end the response or not. Passing false as an argument for this parameter and following Response.Redirect() with return makes the former behave as it used to in classic ASP.

8. HTML Encoding

Yet another change in the ASP.Net API I found somewhat strange - Server.HTMLEncode() was renamed to Server.HtmlEncode(). I guess Microsoft is not as big on backward compatibility as they used to be.

9. Enumerators

I was almost done when I noticed that one of the pages was still failing with security-related errors. After some investigation, I learned that this statement failed:

fsenum = new Enumerator(curfolder.SubFolders);

, because the anonymous IIS user didn't have read access to this registry key:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\SideBySide

10. .Net Hashing

Finally, I decided to get rid of my C++ code, which I was using to compute MD5/SHA1/HMAC hashes, convert UCS-2 strings to UTF-8, etc. Fortunately, the .Net provides classes like MD5 and HMACMD5, so I wanted to try them out.

Soon, however, I realized that these classes were written by people who write code for the sake of writing code and don't even provide a simple method to hash additional data and retrieve the hash as a hex- or base64-encoded string, which is how my C++ support library was implemented.

In addition to this, much to my surprise, there was no simple way in .Net to hex-encode binary data.The Convert class only handled base64 encoding and BitConverter.ToString generated hyphen-delimited hexadecimal strings.

After spending a couple of hours on these experiments, I reverted all hashing code back to use my C++/COM implementation. .Net is just a mess in this area.

Conclusion

That was it. ASP.Net compiles JavaScript instead of interpreting it every time, so page generation takes much less time. File upload works great and integrates perfectly with the FCK editor. The only downside is that ASP.Net requires more memory, so I had to reconfigure MySQL to use less RAM and set up IIS application pools to recycle when the system is low on memory.

Comments:
Name:

Comment: