Thursday, April 21, 2005

Make your own webhandler factory, why? Because you can!

In ASP.Net, the framework provide a default handler for ashx files. It is called
"System.Web.UI.SimpleHandlerFactory". You can find the mapping in machine.config.
The main job of this handler is to compile an ashx file, find the class that implements IHttpHandler, instanciate it and call its Process request so your handler can do its job.
This "System.Web.UI.SimpleHandlerFactory" does all this for you. I wanted to make my own, just for fun... Actually for my students who want to know a little more of what is going on behind the scene.

There are 3 parts to this:
- 1: A standard ashx file to make sure my new factory can create my handler and pass the request through.
- 2: A factory class that needs to be compiled as a library and placed in the bin directory. The name of the assembly needs to be webhandler.dll for this demo.
- 3: A web.config to remap the standard "System.Web.UI.SimpleHandlerFactory" to "DM.SimpleWebHandlerFactory"

Enjoy!

Part 1: Here is a standard ashx file


<%@ WebHandler Language="C#" class="SimplestHandlerEver" %>

using System;
using System.Web;

class SimplestHandlerEver : IHttpHandler
{
public SimplestHandlerEver()
{
}

public void ProcessRequest(HttpContext context)
{
context.Response.Write(this.GetType().FullName + " called");
}

public bool IsReusable
{
get
{
return false;
}
}
}
//--- End of File

Part 2: Here is the custom factory that you need to compile and place in the bin directory.

using System;
using System.Text;
using System.Web;
using Microsoft.CSharp;

namespace DM
{
///
/// Author: C. Fouquet
/// This is a very simple handler factory that can be used to replace the
/// standard System.Web.UI.SimpleHandlerFactory that is mapped to
/// the .ashx extension in the machine.config
/// Needless to say, this is a very crude implementation of an IHttpHandlerFactory.
/// This is just to illustrate the rough steps the actual System.Web.UI.SimpleHandlerFactory
/// goes through to create the handler.
/// It is very inefficient. The code is compiled every time, the generated assembly is
/// loaded every time.
/// Also, look at the web.config to see how we remap the default handler factory
///

public class SimpleWebHandlerFactory : IHttpHandlerFactory
{

public SimpleWebHandlerFactory()
{

}
#region IHttpHandlerFactory Members

public void ReleaseHandler(IHttpHandler handler)
{

}


public IHttpHandler GetHandler(HttpContext context, string requestType, string url, string pathTranslated)
{
string HandlerRequested = pathTranslated;
string Language ;
string Class;

// Open the .ashx file being hit
using(System.IO.StreamReader fs = System.IO.File.OpenText(HandlerRequested))
{

// The first line is the webhandler directive. Or so we hope!
string Directive = fs.ReadLine();

// Extract the information we are looking for from the directive
if(ProcessDirective(Directive, out Language, out Class))
{
if(Language.ToUpper() != "C#" && Language.ToUpper()!="CSHARP")
{
throw new Exception(Language + " Language Not Supported");
}
}
else
{
throw new Exception("missing or badly formatted webhandler directive");
}

string TheCode = fs.ReadToEnd(); // This is the rest of the code

string Target = System.IO.Path.GetTempFileName(); // We need an output
// file name so let the OS pick it.

// For simplicity here, we just include what we need. Obviously
// we would have to process the import directives but .. not today
// This is just a demo remember?
string[] Imports = new string[] {
"System.Web.dll"
};

System.Collections.Specialized.ListDictionary options = new System.Collections.Specialized.ListDictionary();
options.Add("target","library"); // equivalent of doing csc /t:library ...

CompilerError[] Errors = Compiler.Compile(
new string[] { TheCode },
new string[] { "TheCode" },
Target,
Imports,
options);

// Now we can load it
System.Reflection.Assembly HandlerAssembly = System.Reflection.Assembly.LoadFile(Target);

// And find the type we listed in the directive
IHttpHandler TheActualHandler = (IHttpHandler) HandlerAssembly.CreateInstance(Class);

return TheActualHandler;
}
}


// This parses the Directive. It is a little heavy on regex.. but regex are so much fun!

private bool ProcessDirective(string Directive, out string Language, out string Class)
{
Language = Class = string.Empty;

string BackSlash ="\\";
string DoubleQuote ="\"";

StringBuilder sb = new StringBuilder();
sb.Append("<%@");
sb.Append(BackSlash);sb.Append("s+");
sb.Append("WebHandler");
sb.Append(BackSlash);sb.Append("s+");


// Language="C#"
sb.Append("Language=");sb.Append(DoubleQuote);
sb.Append("(?[A-Za-z0-9]");sb.Append(BackSlash);sb.Append("#?)");
sb.Append(DoubleQuote);

// Any space
sb.Append(BackSlash);sb.Append("s+");

// class="xyx"
sb.Append("class=");sb.Append(DoubleQuote);
sb.Append("(?");sb.Append(BackSlash);sb.Append("w+)");
sb.Append(DoubleQuote);

// Any space
sb.Append(BackSlash);sb.Append("s+");

sb.Append("%<");

string regex = sb.ToString();

System.Text.RegularExpressions.RegexOptions options = ((System.Text.RegularExpressions.RegexOptions.IgnorePatternWhitespace | System.Text.RegularExpressions.RegexOptions.Singleline)
| System.Text.RegularExpressions.RegexOptions.IgnoreCase);
System.Text.RegularExpressions.Regex reg = new System.Text.RegularExpressions.Regex(regex, options);

System.Text.RegularExpressions.Match m = reg.Match(Directive);
if(m.Success)
{
Language = m.Groups["Language"].Value;
Class = m.Groups["Class"].Value;
return true;
}

return false;

}


#endregion
}
}

Part 3: The web.config

<configuration>
<system.web>
<httpHandlers>
<remove verb="*" path="*.ashx"/>
<add verb="*" path="*.ashx" type="DM.SimpleWebHandlerFactory, webhandler"/>
</httpHandlers>
</system.web>
</configuration>

I got burnt by ToString()

I have encountered a gotcha that I want to share. Strong typing is my thing. There is nothing that
bothers me more than seeing hardcoded strings in code.

In ADO.Net it is common to do something like this
Data ds = GetDataSetFromDB()
...
DataRow dr = ...

string Name = (string) dr["Name"];

If you mistype "Name" you are doomed. So I used to do this: define an enum called "Columns" that had all the
column names I am interested in.
enum Columns
{
Name,
Email,
Zip
// etc...
}

I can check the names once (visually and programmtically against the database) and in the code use this


string Name = (string) dr[Columns.Name.ToString()];

As long as you remember to use the enum, you can't mess up.

Now, before you go do this, it is very very slow. You would think that it is straightforward for the runtime
to convert an enum into its string representation. That's not the case.

if you compile this into an exe

using System;

public class HelloClient
{

public enum Columns
{
Name
}

public static void Main()
{
Console.WriteLine(Columns.Name.ToString());
}
}


and look at the ToString() with Reflector here is what you get. This is the ToString() from the
Enum type.

public override string ToString()
{
Type type1 = base.GetType();
FieldInfo info1 = Enum.GetValueField(type1);
object obj1 = ((RuntimeFieldInfo) info1).InternalGetValue(this, false);
return Enum.InternalFormat(type1, obj1);
}

and look at what GetValueField does...

private static FieldInfo GetValueField(Type type)
{
FieldInfo[] infoArray1;
if (type is RuntimeType)
{
infoArray1 = ((RuntimeType) type).InternalGetFields(BindingFlags.NonPublic | (BindingFlags.Public | BindingFlags.Instance), false);
}
else
{
infoArray1 = type.GetFields(BindingFlags.NonPublic | (BindingFlags.Public | BindingFlags.Instance));
}
if ((infoArray1 == null) || (infoArray1.Length != 1))
{
throw new ArgumentException(Environment.GetResourceString("Arg_EnumMustHaveUnderlyingValueField"));
}
return infoArray1[0];
}


Arg!!! Reflexion all over the place. No wonder it is slow....

Now, this is the generic Enum.ToString(). I would hope that it does not do that for Booleans... Let's check.

// Part of Boolean

public override string ToString()
{
if (!this.m_value)
{
return bool.FalseString;
}
return bool.TrueString;
}

public static readonly string FalseString;
public static readonly string TrueString;

// End of Boolean


Good!! Somebody is thinking.

Well, I guess we are stuck with the implementation of ToString() for our custom Enums. It would be nice though to let the
compiler know to inline the Enum's ToString() like a custom attribute. For instance:

[HeyCompilerBeSmartAboutTheToStringMethodPleaaaaseAttribute()]
enum Columns
{
Name,
Email
}

It would be nice indeed.

So I am stuck and went back to using strings like this

string Name = (string) dr["Name"];

Cool. If you use reflector again you will see that a hashtable look up is done every time
you access that column. I did some timing and it is still slow for my standards!

Let's push it further. What we want is brute speed like this.

string Name = (string) dr[3]; // 3 == "Name"

That is fast but brittle. If you move the column around in your table, you are out of synch and you will
most likelt get a beautiful exception.

This is why you need to use the "Ordinal" property on the "DataColumn".

If you want speed, you need to precompute the ordinals when the application starts and then use them.

You need to use a few tricks to do this on start up but it is worth it. Now my code is fast. I am a happy man.

Friday, April 15, 2005

Computer History is available for you to see

I found this. It is an archive of all the TV shows of the "Computer Chronicles".
You probably remember the guy always introducing himself the same way. It is fun to
see the old machines and the discussions of the time.

http://www.archive.org/details/computerchronicles